User Journey: Publish the approved set

Table of Contents

This page documents a user journey: A trader applies an approved candidate set so that the curve the system uses becomes the new one, and pricing and reporting see it from that moment.

A user journey describes what one person is trying to do, before anything is built. It is a design document that outlives any sprint, so it names the screens, the entity fields each screen shows, and the operations and messages each step needs.

1. Goal

"The decision has been made. I want the curve the desk uses to be this one now, and I want it to say who published it." The journey is done when the candidate set is the published curve, priced and reported from, and the act carries the name of the person who published it.

2. Actor and trigger

The actor is the trader who owns the curve. The trigger is a request that has reached its required number of approvals. The journey starts at the approved set and ends when the published version is visible to pricing and reporting. It follows Decide a publish; the request it applies was raised in Ask for a publish to be approved.

Publishing is a named, attributable act. The person who applies the approval is recorded, and the moment the new version becomes visible is the moment of that act. When the kind's approvals_required is zero, there is nobody to decide: the raise is the publish, and the same operation applies it at once. When the count is n, the publish applies only once n distinct approvals stand.

3. Steps

  1. Open the approved set. The trader opens Approvals or the curve and reads the set the approver said yes to. The system lists the approved requests with the curve each one is about.
  2. Read the approval. The system shows the request, who approved it, when, and the comment. The trader confirms that the required number of approvals stands before publishing.
  3. Read the points that will be published. The system lists the candidate points the approval covers: each oresmd_uri, its value and its source as the derivation wrote them. The trader reads exactly what is about to become live.
  4. Apply the approved set. The trader chooses Publish approved set, naming the approved request, the curve configuration and the as-of. The system asks the approval record whether the request permits the publish, and refuses with the request's state when it does not. It also compares the subject: the request authorises one curve configuration at one as-of for one party, and a publish of another curve, another as-of or another party is refused with a message that names both subjects. When the subject matches and the request is approved, the system writes the published set and then records the act on the request's own detail row: the request that authorised it, the account that applied it, and the time. One request publishes once, so a second attempt is refused with the publisher and the instant the first one moved the set. A refusal leaves the curve as it was, so the published set moves only once approved.
  5. Watch the moment it becomes visible. The published version becomes the one pricing and reporting read, from the published time. The read that serves a curve states whether anybody has published it, when, by whom, and under which request, so a reader can tell the live set from a candidate that nobody has approved.
  6. Record who published. The act carries the publisher's name and the time, written on the same detail row that names the subject. The approval records who decided; the row records who applied the decision. The two are different people, and both are readable afterwards.
  7. Publish immediately when no approval is needed. When the kind's approvals_required is zero, the raise is the publish and the set becomes live at once. No path applies a zero-approval request today; see What is missing.
  8. Tell the consumers. The system tells the people and services that read this curve that a new version is live. No notification kind exists for a publish; see What is missing.
  9. Leave. The trader goes back to the curve, now showing the published version.

Step 4 is the moment. Before it, the candidate set is evidence the market or the recipe produced; after it, it is what the system uses. The publish record is what tells the two apart: a set with a published instant and a publisher is the one in use, and its request says which decision it stands on.

4. Screens and wireframes

One screen. The approval sits at the top, the points it covers sit beneath it, and the publish act and its effect on consumers sit at the bottom, so the trader reads what was approved and what would go live before the publishing control.

wireframe_publish-the-approved-set.png

Figure 1: Publish the approved set: the approval, the points it covers, the publish act with its publisher, and the consumers that will see it.

The publish control is disabled while no publish operation exists, and the panel says why, so the trader is never left wondering whether the click failed.

5. Prototype

A static page at doc/prototypes/market_data/publish-the-approved-set/index.html: mock data only, no backend, no build step and no session. It argues that publishing is the moment the candidate becomes what pricing uses, and the approval count decides whether a person stands in it.

Variants
a the set summary, b a per-curve list, c the publish with its notifications
States
zero (no approval configured), one, failed
Source
doc/prototypes/market_data/publish-the-approved-set/index.html
Open
/OreStudio/doc/prototypes/market_data/publish-the-approved-set/ once the site is built, or the file directly

6. Entities composed

Entity What it contributes Model
approval_request The approval being applied: the kind, who asked, and the state that says it is approved ores.inbox.approval_request
approval_kind How many approvals publish the set, and whether zero approvals publish at once ores.inbox.approval_kind
approval_decision Who approved, when and with what comment ores.inbox.approval_decision
market_series The curve that becomes the published one, and how it was derived ores.marketdata.market_series
market_observation The points the approval covers, and the rows the published version is read from ores.marketdata.market_observation
observation_lineage The recipe and source as-of the published points were built from ores.marketdata.observation_lineage
curve_publish The subject the request authorises, and the publication record: the request, the publisher and the instant ores.marketdata.curve_publish
notification_kind What kind of notice a publish sends, so consumers are told ores.inbox.notification_kind
notification The notice itself: who it is for and where it points ores.inbox.notification

A published curve has one entity: the curve_publish detail row of the request that authorised it. The row names the subject from the raise, and the apply stamps the publisher and the instant on that same row, so the published set and the decision behind it are one record.

7. Operations and messages

Step Operation Subject Status
Open the approved set List the approved requests of a kind inbox.v1.approval_requests.list_by_kind_code exists
Read the approval Read the request and its decisions inbox.v1.approval_requests.get, inbox.v1.approval_decisions.list_by_request_id exists
Read the points Read the candidates and the latest snapshot marketdata.v1.market_observations.list_by_series_id, marketdata.v1.curve_snapshot.get exists
Apply the approved set Publish the approved set as the curve the system uses marketdata.v1.ops.publish_curve exists
Apply the approved set Write the derived observations unconditionally marketdata.v1.ops.republish_curve partial
Watch the moment Read the published version a consumer sees, with its publisher and as-of marketdata.v1.curve_snapshot.get exists
Record who published Name the publisher and the time on the publication record marketdata.v1.ops.publish_curve exists
Record who published Read the publication record of a request marketdata.v1.curve_publishes.list_by_request_id exists
Publish with zero approvals Raise a request that is approved at once, then apply it inbox.v1.ops.raise_approval with approvals_required 0 missing
Tell the consumers Raise a publish notice to the consumers inbox.v1.ops.raise_notification partial

marketdata.v1.ops.publish_curve exists and carries the decision: a call that names no approved marketdata.curve_publish request raises one and publishes nothing, and a call that names an approved one writes the output. The call also carries the subject. It reads the curve configuration and the as-of out of the call, and the party out of the configuration, and refuses a publish that names another curve, another as-of or another party than the request authorised. The answer states the published instant and the publisher when it published, so the caller reads what the record holds rather than its own clock. marketdata.v1.ops.republish_curve still writes the derived observations with no gate at all, and its own contract says so. It stays as the internal write the gated operation calls, and is partial because a caller can still bypass the decision by sending it. inbox.v1.ops.raise_notification exists and is generic, but no market-data notification kind tells it what a publish notice is.

8. What is missing

  1. There is no read of every published curve. A reader finds the published set of one series, and no read lists the tenant's published curves with their publishers. The candidate is a list over the publication records. Until then the screen reads one curve at a time through the snapshot read.
  2. There is no notification kind for a publish. Consumers are not told a new version is live. The candidate is an ores.inbox.notification_kind such as marketdata.curve_published, with message_key and mail_optional, seeded beside the kind that raises it. Until then the consumers panel states that nobody is told. The recipients, the trigger and what the notice carries are the decision The publish notice below.
  3. Zero approvals have no path. approvals_required is a count the kind carries, including zero, but nothing moves a zero-approval request to approved without a person. The candidate is the rule in the inbox service that a raise with approvals_required 0 closes the request approved at once, which then lets the owning publish apply it. Until then a kind that publishes immediately cannot be expressed. The rule, the actor and the record it leaves are the decision The zero-approval path below.
  4. There is no candidate set to publish. The thing published would be a set of points with one as-of, and no entity holds it. The candidate is the candidate set of the first journey. Until then the publish names the curve configuration and the as-of, takes whatever the derivation wrote under them, and the record names that pair rather than a set identifier.

9. The decisions

9.1. The zero-approval path

9.1.1. The rule

approval_kind.approvals_required is a count on the kind, and zero is a count like any other. When it is zero, nobody decides, and the raise is the publish.

One operation performs the whole act: marketdata.v1.ops.publish_curve, called with the configuration and the as-of and no approved request. It raises the request, writes its subject, and, because the kind needs no approval, the inbox closes the request approved in the same act. The owning operation applies the subject at once, and the answer carries the published instant and the publisher, which the publish record holds.

The gate still states what happened. The request exists after the act, in the state approved, with its reason, its subject and its actor, so the audit reads one request and one publish and not a silent write. The publish record names the asker as the publisher, because the asker is the person who applied it.

The zero-approval close is not a decision by a person. The rule that a decider is not the asker refuses a decision by the asker, so the inbox writes the close as a state transition whose decider is the system account, and whose comment names the kind and its zero count. A person's decision and the system's close therefore never read the same way.

9.1.2. Who may take it

An account that holds the kind's raise permission and the write the act needs: the market data maker's right to publish a curve. The decide permission is not needed, because there is no decision. The account is the maker and the publisher at once, and the record says so.

9.1.3. Why this answer

A tenant may run a curve family that needs no second pair of eyes: a synthetic curve, or a reference curve that no trade prices from. The count already exists on the kind, so the model should not carry a count it cannot reach. The gate stays in force either way: the publish is one operation with one record, and a tenant can raise the count to one without changing a screen.

The alternative is that the raise writes no request and publishes straight away. That is rejected, because the gate would then have two shapes and the audit would have to tell a request-shaped publish from a shapeless one.

9.1.4. Open questions

  1. May a tenant set the count to zero? The recommendation is yes, for a named list of curve families, and the setting is audited like any other kind change; the seeded value stays one for a curve publish. The alternative is that zero is refused for market data and only other kinds may use it.
  2. Does the system close name a decider? The recommendation is one system account, so every decision row names somebody and no row carries an empty decider. The alternative is a null decider and no decision row, which reads as a request that was never decided.
  3. What does the maker's screen say? The recommendation is that the act is named Publish when the kind's count is zero, and the ask is named Raise publish request when it is one or more, with the panel stating that no second person stands in the act. The alternative is one word for both acts and a note under it.
  4. Is the kind's expiry used? The recommendation is no: a zero-approval request closes in the raise and never waits.

9.2. The publish notice

9.2.1. The rule

The trigger is the apply, once, at the instant the published set moves. The notice is not sent at the raise and not at the approval: until somebody applies an approval, the curve the system uses has not changed, and a notice that says it has is untrue.

The recipients are the people and the services that read the curve:

  • the accounts subscribed to the curve through their party's market data subscriptions, which is how the desk reads it;
  • the roles that price from the curve, where a party holds the subscription by a role rather than by an account;
  • the services that consume the curve: pricing and reporting, and the market data service itself.

The notice is one notification of the kind marketdata.curve_published, seeded beside the kind that raises it, with a message key, its arguments and an optional mail. It carries the subject and the act, and no values:

Field What it holds
Curve configuration The code the reader knows
Party The party whose curve changed
Published as-of The instant the set was built at
Published at The instant the set moved
Publisher The account that applied it
Authorising request The request the act stands on
Previous as-of The set it replaced, or empty for the first

The link on the notice opens the published curve's record page, and the record page is where the values are read. A notice names the change; it does not carry the curve.

A replacement sends the same notice, because a replacement is a publish. A withdrawal sends marketdata.curve_withdrawn, with the same subject and the withdrawal reason in words, because a withdrawn curve is a change a reader must act on.

9.2.2. Why this answer

The consumers of a published curve are people at a desk and services in the platform, and the model already holds both: the subscriptions name the party, and a notification names the account and the link. A notice that carried the values would duplicate the curve and drift from it; a notice that names the subject and links to it cannot drift.

9.2.3. The alternative

A change event alone, marketdata.v1.events.market_series.updated, and no notification. It is rejected because an event says a row changed, and a person cannot read it; and because a consumer that misses the event has no place to look.

9.2.4. Open questions

  1. Is the notice per party or per person? The recommendation is per account subscribed, because the party subscription names a party and the bell hangs on an account. The alternative is one notice per party, which needs a party bell the platform does not have.
  2. Does a consumer outside the tenant get a notice? The recommendation is not yet: a published curve is tenant-scoped, and a cross-tenant feed is its own design.
  3. Is mail sent? The recommendation is that mail is off for a publish and on for a withdrawal, because taking a curve out of use is the one a person must not miss. The alternative is mail on every publish.
  4. Does the notice carry the previous set's values? The recommendation is no: the previous as-of is enough to find them, and the delta shows the difference.
  5. Who is told when nobody is subscribed? The recommendation is the queue and nobody else: an unsubscribed curve changes without a notice, and the read states the new instant.

10. Related journeys

11. Related knowledge

12. See also

Emacs 29.3 (Org mode 9.6.15)