Enumerate the scenario cost models a set of URPX documents expresses.
A SCENARIO COST MODEL is one urpx:RatePlanVersion, plus every urpx:RatePlanModifierVersion compatible with it, plus one urpx:ProfileAlternative for each dimension any of them leaves open. Fully determined: given an instant inside its window it resolves to prices with no further input. If a choice is still outstanding it is not one model but several, and each of those is a model in its own right.
Each model is the composition a urpx:ScenarioCostModel prices.
WHAT THIS CAN AND CANNOT ENUMERATE. Which compatible modifiers a given CUSTOMER has is a fact about the customer, and URPX places customer data outside its scope: urpx:AccountServiceAgreement carries the skos:note "Service account and agreement data lives in customer data, not URPX." So this enumerates the models the DOCUMENTS EXPRESS, every combination the filings say is permitted. That set is larger than any one customer's and is what a price server can publish.
OPTIONAL BY CONSTRUCTION. This namespace requires urpx.price; urpx.price does not require this. A consumer that wants prices for a composition it already knows how to assemble uses urpx.price directly and never loads this file. Nothing here changes an existing arity or return shape.
Enumerate the scenario cost models a set of URPX documents expresses. A SCENARIO COST MODEL is one urpx:RatePlanVersion, plus every urpx:RatePlanModifierVersion compatible with it, plus one urpx:ProfileAlternative for each dimension any of them leaves open. Fully determined: given an instant inside its window it resolves to prices with no further input. If a choice is still outstanding it is not one model but several, and each of those is a model in its own right. Each model is the composition a urpx:ScenarioCostModel prices. WHAT THIS CAN AND CANNOT ENUMERATE. Which compatible modifiers a given CUSTOMER has is a fact about the customer, and URPX places customer data outside its scope: urpx:AccountServiceAgreement carries the skos:note "Service account and agreement data lives in customer data, not URPX." So this enumerates the models the DOCUMENTS EXPRESS, every combination the filings say is permitted. That set is larger than any one customer's and is what a price server can publish. OPTIONAL BY CONSTRUCTION. This namespace requires urpx.price; urpx.price does not require this. A consumer that wants prices for a composition it already knows how to assemble uses urpx.price directly and never loads this file. Nothing here changes an existing arity or return shape.
(applicable-modifiers documents base-version)(applicable-modifiers documents base-version opts)The urpx:RatePlanModifierVersions in documents that MAY apply to
base-version.
This is the query a consumer actually wants, and it is the half URPX can answer. urpx:applicableToRatePlan states compatibility with a plan identity; urpx:applicableToRatePlanVersion states it against a specific version. Where a modifier names any versions, those are taken to be exhaustive, because the version-level statement is the more specific.
WHICH READING applies is a caller policy, :compatibility, defaulting to
named-versions-narrow. URPX does not settle whether naming a version
narrows the plan-level statement or adds to it, so this library does not
settle it either; see the policies for the evidence on each side.
WHAT THIS DOES NOT ANSWER, deliberately. Which of these a given customer HAS
is a fact about the customer, and URPX places customer data outside its
scope: urpx:AccountServiceAgreement carries the skos:note "Service account
and agreement data lives in customer data, not URPX." Nor does URPX say
which modifiers may be held TOGETHER: there is no property anywhere in the
ontology expressing exclusivity or combinability between modifiers, and
urpx:modifierCategory and urpx:modifierType, which might have served as a
signal, are optional. So CARE and FERA are both returned for SCE
Schedule D and nothing in the documents says a customer has at most one.
Choosing among them is the caller's, which is why enumerate takes a
combining policy rather than inventing one.
Options:
:at a ZonedDateTime. Restricts to modifier versions current then.
:repeated-ids fn from {kind -> [[identity-id version document] ...]} to the
same, deciding what one @id naming several distinct snapshots
means. Defaults to repeated-ids-refuse; repeated-ids-union
merges them, which is the RDF reading. A THIRD POLICY for the
same reason as the other two: URPX does not say, and a client
reading one filing and a client merging a corpus want different
answers.
:compatibility fn [modifier-version base-version plan-id] -> boolean.
Defaults to named-versions-narrow; named-versions-add
is the monotone alternative.
:package-zones as enumerate takes it.
The urpx:RatePlanModifierVersions in `documents` that MAY apply to
`base-version`.
This is the query a consumer actually wants, and it is the half URPX can
answer. urpx:applicableToRatePlan states compatibility with a plan identity;
urpx:applicableToRatePlanVersion states it against a specific version. Where
a modifier names any versions, those are taken to be exhaustive, because the
version-level statement is the more specific.
WHICH READING applies is a caller policy, `:compatibility`, defaulting to
`named-versions-narrow`. URPX does not settle whether naming a version
narrows the plan-level statement or adds to it, so this library does not
settle it either; see the policies for the evidence on each side.
WHAT THIS DOES NOT ANSWER, deliberately. Which of these a given customer HAS
is a fact about the customer, and URPX places customer data outside its
scope: urpx:AccountServiceAgreement carries the skos:note "Service account
and agreement data lives in customer data, not URPX." Nor does URPX say
which modifiers may be held TOGETHER: there is no property anywhere in the
ontology expressing exclusivity or combinability between modifiers, and
urpx:modifierCategory and urpx:modifierType, which might have served as a
signal, are optional. So CARE and FERA are both returned for SCE
Schedule D and nothing in the documents says a customer has at most one.
Choosing among them is the caller's, which is why `enumerate` takes a
combining policy rather than inventing one.
Options:
:at a ZonedDateTime. Restricts to modifier versions current then.
:repeated-ids fn from {kind -> [[identity-id version document] ...]} to the
same, deciding what one @id naming several distinct snapshots
means. Defaults to `repeated-ids-refuse`; `repeated-ids-union`
merges them, which is the RDF reading. A THIRD POLICY for the
same reason as the other two: URPX does not say, and a client
reading one filing and a client merging a corpus want different
answers.
:compatibility fn `[modifier-version base-version plan-id] -> boolean`.
Defaults to `named-versions-narrow`; `named-versions-add`
is the monotone alternative.
:package-zones as `enumerate` takes it.(enumerate documents)(enumerate documents opts)Every scenario cost model documents expresses, as a vector.
documents is a seq of coerced urpx:RatePlan and urpx:RatePlanModifier
documents, the same values urpx.price takes.
Options:
:at a ZonedDateTime. Restricts to models whose every component
is CURRENT at that instant: the latest version of each identity
to have taken effect and not expired. Omit to enumerate the whole
expressed space across every version, a different and larger
question.
:combine fn from the compatible modifier versions of one base version to a
seq of the modifier SETS a customer might hold. Defaults to
one-modifier-at-most.
:compatibility fn [modifier-version base-version plan-id] -> boolean
deciding which modifiers MAY apply. Defaults to
named-versions-narrow; named-versions-add is the monotone
alternative. TWO POLICIES, not one, because URPX does not say
whether naming a urpx:applicableToRatePlanVersion narrows
urpx:applicableToRatePlan or adds to it. They differ only when
a modifier names some version, about a base version it does not
name whose plan it names; see the policies.
:package-zones what a urpx:timezoneIdentifier on a package counts for
when zoning a version. A package counts when it
names the version, its identity or its source document by
urpx:packages, urpx:hasRatePlan or urpx:hasRatePlanModifier.
:agree (default) one more declaration, which must agree
with the version, its identity and its source
document, or the call refuses
:urpx.scenario-cost-model/conflicting-timezone.
:fallback read only when none of those declares a zone.
:ignore packages contribute no zone.
Under every mode, two packages declaring different zones for one
version refuse, as do a version and its identity. Any other
value refuses :urpx.scenario-cost-model/unknown-package-zones.
THE COMBINING POLICY IS THE CALLER'S BECAUSE URPX CANNOT STATE IT. Nothing
in the ontology expresses exclusivity or combinability between modifiers,
and urpx:modifierCategory and urpx:modifierType, the only properties that
might have served, are optional. So CARE and FERA are both compatible with
SCE Schedule D and no document says a customer has at most one. The default
is conservative and knowingly incomplete; every-subset is complete and
knowingly wrong; a caller holding its own program rules should pass those
instead. Use applicable-modifiers to see what it is choosing among.
Each model is a map with these keys, all in :urpx.scenario-cost-model: rate-plan the coerced base document, declaring the zone found for its version version the base version snapshot version-id its @id plan-id the plan identity @id modifiers coerced modifier documents, in order, zoned the same way modifier-versions their snapshots modifier-version-ids their @ids selections {container-@id alternative-@id}
A urpx:ProfileAlternative listed by two containers across one
composition's versions refuses :urpx.scenario-cost-model/shared-alternative.
Deterministic: sorted by identity-tuple, so regenerating the same
documents gives the same order. Nothing here consults wall-clock time.
Every scenario cost model `documents` expresses, as a vector.
`documents` is a seq of coerced urpx:RatePlan and urpx:RatePlanModifier
documents, the same values urpx.price takes.
Options:
:at a ZonedDateTime. Restricts to models whose every component
is CURRENT at that instant: the latest version of each identity
to have taken effect and not expired. Omit to enumerate the whole
expressed space across every version, a different and larger
question.
:combine fn from the compatible modifier versions of one base version to a
seq of the modifier SETS a customer might hold. Defaults to
`one-modifier-at-most`.
:compatibility fn `[modifier-version base-version plan-id] -> boolean`
deciding which modifiers MAY apply. Defaults to
`named-versions-narrow`; `named-versions-add` is the monotone
alternative. TWO POLICIES, not one, because URPX does not say
whether naming a urpx:applicableToRatePlanVersion narrows
urpx:applicableToRatePlan or adds to it. They differ only when
a modifier names some version, about a base version it does not
name whose plan it names; see the policies.
:package-zones what a urpx:timezoneIdentifier on a package counts for
when zoning a version. A package counts when it
names the version, its identity or its source document by
urpx:packages, urpx:hasRatePlan or urpx:hasRatePlanModifier.
:agree (default) one more declaration, which must agree
with the version, its identity and its source
document, or the call refuses
`:urpx.scenario-cost-model/conflicting-timezone`.
:fallback read only when none of those declares a zone.
:ignore packages contribute no zone.
Under every mode, two packages declaring different zones for one
version refuse, as do a version and its identity. Any other
value refuses `:urpx.scenario-cost-model/unknown-package-zones`.
THE COMBINING POLICY IS THE CALLER'S BECAUSE URPX CANNOT STATE IT. Nothing
in the ontology expresses exclusivity or combinability between modifiers,
and urpx:modifierCategory and urpx:modifierType, the only properties that
might have served, are optional. So CARE and FERA are both compatible with
SCE Schedule D and no document says a customer has at most one. The default
is conservative and knowingly incomplete; `every-subset` is complete and
knowingly wrong; a caller holding its own program rules should pass those
instead. Use `applicable-modifiers` to see what it is choosing among.
Each model is a map with these keys, all in :urpx.scenario-cost-model:
rate-plan the coerced base document, declaring the zone found
for its version
version the base version snapshot
version-id its @id
plan-id the plan identity @id
modifiers coerced modifier documents, in order, zoned the
same way
modifier-versions their snapshots
modifier-version-ids their @ids
selections {container-@id alternative-@id}
A urpx:ProfileAlternative listed by two containers across one
composition's versions refuses `:urpx.scenario-cost-model/shared-alternative`.
Deterministic: sorted by `identity-tuple`, so regenerating the same
documents gives the same order. Nothing here consults wall-clock time.(enumerate-pairs documents)(enumerate-pairs documents opts)Every (base version, modifier set) pair documents expresses, as a set:
#{[base-version-iri #{modifier-version-iri ...}] ...}
The enumeration collapsed to one row per composition, with any
ProfileAlternative choices NOT expanded. That is a coarser question than
enumerate answers and a deliberately different one: a model with
an open dimension is several models and one pair.
FOR COMPARING TWO IMPLEMENTATIONS. A consumer cross-checking an independent enumerator against this one should compare pair SETS rather than model counts, because the two sides can legitimately disagree about whether a pending choice is one row or several while agreeing completely about what composes with what.
opts is what enumerate takes. PIN EVERY POLICY EXPLICITLY when the
result is an expected value in a gate: :at, :combine, :compatibility,
:repeated-ids and :package-zones each change the answer, and matching
defaults across two implementations is agreement by coincidence rather than
by construction.
Every (base version, modifier set) pair `documents` expresses, as a set:
#{[base-version-iri #{modifier-version-iri ...}] ...}
The enumeration collapsed to one row per composition, with any
ProfileAlternative choices NOT expanded. That is a coarser question than
`enumerate` answers and a deliberately different one: a model with
an open dimension is several models and one pair.
FOR COMPARING TWO IMPLEMENTATIONS. A consumer cross-checking an independent
enumerator against this one should compare pair SETS rather than model
counts, because the two sides can legitimately disagree about whether a
pending choice is one row or several while agreeing completely about what
composes with what.
`opts` is what `enumerate` takes. PIN EVERY POLICY EXPLICITLY when the
result is an expected value in a gate: `:at`, `:combine`, `:compatibility`,
`:repeated-ids` and `:package-zones` each change the answer, and matching
defaults across two implementations is agreement by coincidence rather than
by construction.(every-subset modifier-versions)A combining policy yielding every subset, including the empty one.
Complete and unfiltered: it will pair mutually exclusive programs, since nothing in the documents marks them exclusive. 2^n per base version, so use it on a narrowed modifier list rather than a whole corpus.
A combining policy yielding every subset, including the empty one. Complete and unfiltered: it will pair mutually exclusive programs, since nothing in the documents marks them exclusive. 2^n per base version, so use it on a narrowed modifier list rather than a whole corpus.
(from-node documents node)(from-node documents node opts)The model the urpx:ScenarioCostModel node names in documents, as the map
enumerate yields for it, so resolve-at, segments-for, schedule-for
and node take it as they take an enumerated one.
node is keyword-keyed, as urpx.core/parse-graph yields it, either raw or
coerced through urpx.schema/ScenarioCostModel: each property is read bare
or as a list. Its urpx:consumesVersion, urpx:consumesModifierVersion and
urpx:selectsProfileAlternative are read by @id. documents is what
enumerate takes.
An @id matches a document's @id when the two are equal, or with :context
when they expand to one IRI, so a node node wrote reads back against
documents that write compact IRIs. The model carries the documents' @ids.
Options:
:context as node takes it
:compatibility as enumerate takes it
:repeated-ids as enumerate takes it
:package-zones as enumerate takes it
Refusals, each under :urpx.scenario-cost-model and carrying :node-id:
not-a-reference a property value is not a node with an @id
no-version urpx:consumesVersion is absent
unknown-version a version or modifier version @id names no
version snapshot of its kind in documents
inapplicable-modifier :compatibility rejects a modifier version for
the base version
shared-alternative as enumerate refuses it
unknown-alternative an alternative is in no container of the
consumed versions
dimension-selected-twice two alternatives are in one container
dimension-unselected a container has no alternative selected
The model the urpx:ScenarioCostModel `node` names in `documents`, as the map
`enumerate` yields for it, so `resolve-at`, `segments-for`, `schedule-for`
and `node` take it as they take an enumerated one.
`node` is keyword-keyed, as `urpx.core/parse-graph` yields it, either raw or
coerced through `urpx.schema/ScenarioCostModel`: each property is read bare
or as a list. Its urpx:consumesVersion, urpx:consumesModifierVersion and
urpx:selectsProfileAlternative are read by @id. `documents` is what
`enumerate` takes.
An @id matches a document's @id when the two are equal, or with `:context`
when they expand to one IRI, so a node `node` wrote reads back against
documents that write compact IRIs. The model carries the documents' @ids.
Options:
:context as `node` takes it
:compatibility as `enumerate` takes it
:repeated-ids as `enumerate` takes it
:package-zones as `enumerate` takes it
Refusals, each under :urpx.scenario-cost-model and carrying :node-id:
not-a-reference a property value is not a node with an @id
no-version urpx:consumesVersion is absent
unknown-version a version or modifier version @id names no
version snapshot of its kind in `documents`
inapplicable-modifier `:compatibility` rejects a modifier version for
the base version
shared-alternative as `enumerate` refuses it
unknown-alternative an alternative is in no container of the
consumed versions
dimension-selected-twice two alternatives are in one container
dimension-unselected a container has no alternative selected(identity-tuple model)The intrinsic identity of model:
[base-version-iri [modifier-version-iris sorted] [alternative-iris sorted]]
The values of urpx:consumesVersion, urpx:consumesModifierVersion and urpx:selectsProfileAlternative on the urpx:ScenarioCostModel it describes. Each alternative's container is in the model's selections.
Computable from the documents alone, stable across regeneration, external nothing. Two models are the same when this matches and different otherwise, INCLUDING when they resolve to the same price: a bundled customer and one buying generation elsewhere may pay the same delivery rate and are on different models.
The intrinsic identity of `model`: [base-version-iri [modifier-version-iris sorted] [alternative-iris sorted]] The values of urpx:consumesVersion, urpx:consumesModifierVersion and urpx:selectsProfileAlternative on the urpx:ScenarioCostModel it describes. Each alternative's container is in the model's selections. Computable from the documents alone, stable across regeneration, external nothing. Two models are the same when this matches and different otherwise, INCLUDING when they resolve to the same price: a bundled customer and one buying generation elsewhere may pay the same delivery rate and are on different models.
(named-versions-add mv bv plan-id)The monotone policy: a version statement ADDS to urpx:applicableToRatePlan and never removes from it.
Sound under RDF, which is what URPX documents denote: merging graphs adds triples and never retracts, so a larger corpus can only ever yield more compatibility. It also stops the plan-level statement being cancelled by triples that never mention the plan it names.
KNOWN COST. It leaves urpx:applicableToRatePlanVersion with almost nothing to do: it can only widen, and only to a version whose plan is not already named. A publisher wanting to say "this modifier applies only to version X of plan P" has no way to say it under this reading.
The monotone policy: a version statement ADDS to urpx:applicableToRatePlan and never removes from it. Sound under RDF, which is what URPX documents denote: merging graphs adds triples and never retracts, so a larger corpus can only ever yield more compatibility. It also stops the plan-level statement being cancelled by triples that never mention the plan it names. KNOWN COST. It leaves urpx:applicableToRatePlanVersion with almost nothing to do: it can only widen, and only to a version whose plan is not already named. A publisher wanting to say "this modifier applies only to version X of plan P" has no way to say it under this reading.
(named-versions-narrow mv bv plan-id)The default policy: naming any urpx:applicableToRatePlanVersion means those versions and no others, overriding urpx:applicableToRatePlan.
Reads with the ontology's own wording, "Defines which SPECIFIC rate plan
versions are compatible with this modifier version", and it is the only
reading under which the property can express a restriction at all: under
named-versions-add a version statement can only widen, and then only to a
version whose plan is not already named.
KNOWN COST, stated because it is not small. The rule is NON-MONOTONIC. Merging a document that adds a version statement REMOVES compatibility with a plan named only by urpx:applicableToRatePlan, and RDF merge never retracts. A partial view of a corpus can therefore yield MORE models than the whole of it. It is the default because changing it would change behavior, not because it is known right; the evidence on each side is recorded above.
The default policy: naming any urpx:applicableToRatePlanVersion means those versions and no others, overriding urpx:applicableToRatePlan. Reads with the ontology's own wording, "Defines which SPECIFIC rate plan versions are compatible with this modifier version", and it is the only reading under which the property can express a restriction at all: under `named-versions-add` a version statement can only widen, and then only to a version whose plan is not already named. KNOWN COST, stated because it is not small. The rule is NON-MONOTONIC. Merging a document that adds a version statement REMOVES compatibility with a plan named only by urpx:applicableToRatePlan, and RDF merge never retracts. A partial view of a corpus can therefore yield MORE models than the whole of it. It is the default because changing it would change behavior, not because it is known right; the evidence on each side is recorded above.
(node model iri-fn)(node model iri-fn opts)model as one urpx:ScenarioCostModel node, in the coerced shape
urpx.schema/ScenarioCostModel describes, for urpx.emit to write.
Every @id on the node is absolute. Compact @ids are expanded through
:context, so a model read from documents that write compact IRIs needs
the @context of the files they came from.
iri-fn mints the node's @id from the absolute identity tuple
[base-version-iri modifier-version-iris alternative-iris], both lists
sorted. The IRI scheme is the caller's; rate-plans-iri is urpx-rate-plans'.
urpx:consumesVersion is one reference. urpx:consumesModifierVersion and urpx:selectsProfileAlternative are vectors of references, absent when the model has none.
Options:
:context the JSON-LD @context to expand compact IRIs through, a map
or a vector, keyed as parsed or as written. A prefix bound
two ways refuses :urpx.scenario-cost-model/conflicting-prefix;
an @id it cannot expand refuses
:urpx.scenario-cost-model/unexpandable-iri.
:name the node's urpx:name
:description the node's urpx:description
`model` as one urpx:ScenarioCostModel node, in the coerced shape
`urpx.schema/ScenarioCostModel` describes, for `urpx.emit` to write.
Every @id on the node is absolute. Compact @ids are expanded through
`:context`, so a model read from documents that write compact IRIs needs
the @context of the files they came from.
`iri-fn` mints the node's @id from the absolute identity tuple
`[base-version-iri modifier-version-iris alternative-iris]`, both lists
sorted. The IRI scheme is the caller's; `rate-plans-iri` is urpx-rate-plans'.
urpx:consumesVersion is one reference. urpx:consumesModifierVersion and
urpx:selectsProfileAlternative are vectors of references, absent when the
model has none.
Options:
:context the JSON-LD @context to expand compact IRIs through, a map
or a vector, keyed as parsed or as written. A prefix bound
two ways refuses `:urpx.scenario-cost-model/conflicting-prefix`;
an @id it cannot expand refuses
`:urpx.scenario-cost-model/unexpandable-iri`.
:name the node's urpx:name
:description the node's urpx:description(offered-by versions)Group version snapshots by the urpx:Organization @id that offers them, for a broader search than one plan at a time.
urpx:applicableToRateGroup and urpx:hasServiceClass might look like alternatives, but both appear ZERO times in RatePlanModifierVersionShape, so they cannot be set on a modifier version at all.
Group version snapshots by the urpx:Organization @id that offers them, for a broader search than one plan at a time. urpx:applicableToRateGroup and urpx:hasServiceClass might look like alternatives, but both appear ZERO times in RatePlanModifierVersionShape, so they cannot be set on a modifier version at all.
(one-modifier-at-most modifier-versions)The default combining policy: the empty set, and each modifier on its own.
Conservative because URPX cannot state which modifiers combine. Every model it yields is one the documents support, and it is knowingly INCOMPLETE: real multi-overlay models exist, and California publishes identifiers for some of them, so a caller that knows its own program rules should pass its own policy rather than accept this one.
The default combining policy: the empty set, and each modifier on its own. Conservative because URPX cannot state which modifiers combine. Every model it yields is one the documents support, and it is knowingly INCOMPLETE: real multi-overlay models exist, and California publishes identifiers for some of them, so a caller that knows its own program rules should pass its own policy rather than accept this one.
(plan-versions documents)(plan-versions documents opts)Every urpx:RatePlanVersion in documents, as a vector of snapshots.
:at restricts to the version of each plan identity in force at that
instant. Omit it for every version the documents carry, which reads no zone.
:package-zones is as enumerate takes it.
Every urpx:RatePlanVersion in `documents`, as a vector of snapshots. `:at` restricts to the version of each plan identity in force at that instant. Omit it for every version the documents carry, which reads no zone. `:package-zones` is as `enumerate` takes it.
(rate-plans-iri [base mods alts])The IRI urpx-rate-plans mints for the scenario cost model whose identity
tuple is [base-version-iri modifier-version-iris alternative-iris], every
IRI absolute. A function to pass node as its iri-fn.
The rule is the IRIs section of urpx-rate-plans doc/scenario-cost-models.md:
N https://rate-plans.grid-coordination.energy/<utility>/, the
utility being the base version IRI's first path segment there
slug scm-<base>, then --<modifier> per modifier in code-point order,
then --<hash> when there is any alternative, each <name> being
the local name after N
hash the first 12 lower-case hex characters of SHA-256 over the UTF-8
lines base <iri>, modifier <iri> sorted and alternative <iri>
sorted, joined by LF with no trailing LF
IRI N followed by the slug
A base outside the root, a modifier or alternative outside N, or a local
name other than lower-case ASCII words joined by single hyphens refuses
:urpx.scenario-cost-model/iri-outside-namespace or
:urpx.scenario-cost-model/iri-local-name.
The IRI urpx-rate-plans mints for the scenario cost model whose identity
tuple is `[base-version-iri modifier-version-iris alternative-iris]`, every
IRI absolute. A function to pass `node` as its `iri-fn`.
The rule is the IRIs section of urpx-rate-plans doc/scenario-cost-models.md:
N https://rate-plans.grid-coordination.energy/<utility>/, the
utility being the base version IRI's first path segment there
slug scm-<base>, then --<modifier> per modifier in code-point order,
then --<hash> when there is any alternative, each <name> being
the local name after N
hash the first 12 lower-case hex characters of SHA-256 over the UTF-8
lines `base <iri>`, `modifier <iri>` sorted and `alternative <iri>`
sorted, joined by LF with no trailing LF
IRI N followed by the slug
A base outside the root, a modifier or alternative outside N, or a local
name other than lower-case ASCII words joined by single hyphens refuses
`:urpx.scenario-cost-model/iri-outside-namespace` or
`:urpx.scenario-cost-model/iri-local-name`.(repeated-ids-refuse by-kind)The default policy for one @id naming more than one distinct snapshot: refuse, naming every offending @id at once.
An @id identifies a thing, so two different things under one is a contradiction rather than a choice. Where urpx.price refuses two DIFFERENT snapshots tied on an effective instant it can say "pass :version to choose", because the caller has two distinguishable things to choose between; here both carry the same @id and there is nothing to name.
Every conflicting @id is named in one refusal, across every kind. Called once per kind this threw on the base versions before the modifier versions were ever examined, so a corpus with three conflicting @ids reported one.
Byte-identical repeats are NOT a conflict. One version published in two filings is one version, and it is deduplicated.
The default policy for one @id naming more than one distinct snapshot: refuse, naming every offending @id at once. An @id identifies a thing, so two different things under one is a contradiction rather than a choice. Where urpx.price refuses two DIFFERENT snapshots tied on an effective instant it can say "pass :version to choose", because the caller has two distinguishable things to choose between; here both carry the same @id and there is nothing to name. Every conflicting @id is named in one refusal, across every kind. Called once per kind this threw on the base versions before the modifier versions were ever examined, so a corpus with three conflicting @ids reported one. Byte-identical repeats are NOT a conflict. One version published in two filings is one version, and it is deduplicated.
(repeated-ids-union by-kind)A policy that MERGES snapshots sharing one @id rather than refusing them.
The RDF reading: several documents describing one IRI contribute the union of their statements, and absence of a property is not a negative assertion.
KNOWN COST, and it is not small. RDF MERGES TRIPLES, NOT MEANINGS. Merging a
copy that states urpx:applicableToRatePlanVersion with one that omits it
yields a node that HAS the property, which under named-versions-narrow
restricts the modifier to exactly those versions. The omitting copy meant the
opposite: no version restriction at all. So the union of the triples narrows
where the union of the meanings would widen. Pair this with
named-versions-add if the widening reading is what you want.
It also SILENTLY RECONCILES a case that is a defect on any reading: a version @id whose option list differs between filings because the list is time-varying and the @id is not. A July filing offers one option; a September filing republishes the same version @id with two more, which are September versions that did not exist in July. The union asserts that a version effective in July offered them. Merging makes that enumerable; it does not make it true.
Refuses :urpx.scenario-cost-model/unmergeable-property when occurrences
disagree about a non-collection property, which cannot be combined.
A policy that MERGES snapshots sharing one @id rather than refusing them. The RDF reading: several documents describing one IRI contribute the union of their statements, and absence of a property is not a negative assertion. KNOWN COST, and it is not small. RDF MERGES TRIPLES, NOT MEANINGS. Merging a copy that states urpx:applicableToRatePlanVersion with one that omits it yields a node that HAS the property, which under `named-versions-narrow` restricts the modifier to exactly those versions. The omitting copy meant the opposite: no version restriction at all. So the union of the triples narrows where the union of the meanings would widen. Pair this with `named-versions-add` if the widening reading is what you want. It also SILENTLY RECONCILES a case that is a defect on any reading: a version @id whose option list differs between filings because the list is time-varying and the @id is not. A July filing offers one option; a September filing republishes the same version @id with two more, which are September versions that did not exist in July. The union asserts that a version effective in July offered them. Merging makes that enumerable; it does not make it true. Refuses `:urpx.scenario-cost-model/unmergeable-property` when occurrences disagree about a non-collection property, which cannot be combined.
(resolve-at model zdt)(resolve-at model zdt opts)Resolve model at zdt, returning what
urpx.price/resolve-prices-with-modifiers returns.
A convenience over urpx.price, not a replacement: it binds each document to
its own version and hands the model's selections through as
:profile-alternatives, so the opts cannot reach a document they do not
belong to. Both :version defects fixed in 0.28.0 were an opt and a document
failing to line up: one applied the base plan's snapshot to every modifier,
the other re-derived the snapshot on the holiday path and ignored the opt
entirely. A model makes both unrepresentable rather than repeatedly
fixable.
The binding does more than choose. Handed a document carrying several version snapshots, urpx.price refuses outright rather than picking one, so this is what makes such a document resolvable at all.
Extra opts merge over the model's own, except :version and
:profile-alternatives, which are refused. See bound-opts.
Resolve `model` at `zdt`, returning what `urpx.price/resolve-prices-with-modifiers` returns. A convenience over urpx.price, not a replacement: it binds each document to its own version and hands the model's selections through as `:profile-alternatives`, so the opts cannot reach a document they do not belong to. Both `:version` defects fixed in 0.28.0 were an opt and a document failing to line up: one applied the base plan's snapshot to every modifier, the other re-derived the snapshot on the holiday path and ignored the opt entirely. A model makes both unrepresentable rather than repeatedly fixable. The binding does more than choose. Handed a document carrying several version snapshots, urpx.price refuses outright rather than picking one, so this is what makes such a document resolvable at all. Extra `opts` merge over the model's own, except `:version` and `:profile-alternatives`, which are refused. See `bound-opts`.
(schedule-for model start end)(schedule-for model start end opts)A stepped price schedule for model across [start, end), as
urpx.schedule/price-schedule-with-modifiers returns them.
Walks a grid, default hourly, merging adjacent steps whose prices are
equal. Use it when a caller genuinely wants a fixed cadence; use
segments-for when they want the truth about where prices change, which for
a price server is almost always the question.
Same bounds, opts and refusal handling as segments-for: a step whose
resolution throws becomes an interval carrying :urpx.interval/refused,
and equal refusals merge.
A stepped price schedule for `model` across `[start, end)`, as `urpx.schedule/price-schedule-with-modifiers` returns them. Walks a grid, default hourly, merging adjacent steps whose prices are equal. Use it when a caller genuinely wants a fixed cadence; use `segments-for` when they want the truth about where prices change, which for a price server is almost always the question. Same bounds, `opts` and refusal handling as `segments-for`: a step whose resolution throws becomes an interval carrying `:urpx.interval/refused`, and equal refusals merge.
(segments-for model start end)(segments-for model start end opts)Exact price segments for model across [start, end), as
urpx.schedule/price-segments returns them.
PREFER THIS over schedule-for for publishing. Boundaries are derived from
the documents rather than discovered by sampling, so a segment ends where
the tariff actually changes and not where a step grid happened to land. For
a consumer handing intervals to an optimizer that is the difference between
a schedule that is right and one that is right only because every bracket in
that plan sits on an hour.
A resolution that throws inside the window becomes a segment carrying
:urpx.interval/refused rather than aborting the horizon, and equal
refusals merge, so a stretch the model does not cover is one segment
and not one per candidate instant. That is what lets a publisher emit the
part of a window it can price and say plainly what it cannot.
start and end may be in any zone; segments are in the plan's. Extra
opts are as resolve-at: merged, except the two the model
determines, which are refused.
Exact price segments for `model` across `[start, end)`, as `urpx.schedule/price-segments` returns them. PREFER THIS over `schedule-for` for publishing. Boundaries are derived from the documents rather than discovered by sampling, so a segment ends where the tariff actually changes and not where a step grid happened to land. For a consumer handing intervals to an optimizer that is the difference between a schedule that is right and one that is right only because every bracket in that plan sits on an hour. A resolution that throws inside the window becomes a segment carrying `:urpx.interval/refused` rather than aborting the horizon, and equal refusals merge, so a stretch the model does not cover is one segment and not one per candidate instant. That is what lets a publisher emit the part of a window it can price and say plainly what it cannot. `start` and `end` may be in any zone; segments are in the plan's. Extra `opts` are as `resolve-at`: merged, except the two the model determines, which are refused.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |