Task: Expose the configuration document operations from each owning service

Table of Contents

This page documents a task in the Model the ORE report configuration as entities story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

A service saves, reads and deletes another component's configuration documents only through that component's operations.

2. Status

Field Value
State DONE
Parent story Model the ORE report configuration as entities
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-04

3. Acceptance

  • Each owner has an operation model and a handler for save, get and delete of its documents, under the caller's session and with seeded permissions.
  • Each handler is tested over NATS against a running service.
  • Every owner tests save, find by configuration and get of its own documents through its operations, so analytics and refdata no longer rely on the ORE corpus round trips for their coverage (raised in the review of PR #2624).

4. Plan

(Implementation strategy. Written when work starts; key decisions are distilled into the parent story's * Decisions at close, but the plan itself stays — it is the historical record of what we did.)

5. Measurements

Every number this task claims about a tree, with the command that produced it and the commit it was measured at. A number without both is not a measurement, because a clean-up record describes a tree and trunk moves under a branch: a consumer count, a gate's component count and a suite's size all change with no code changing, and the reader of a bare number cannot tell which tree it came from. Where the raw output matters, put it in an evidence/ file beside the task and name that file in the Command column.

What Value Command Commit
       

6. Notes

Part of the redesign the operator asked for on 2026-10-04, after ruling that a service reading or writing another component's tables is an architectural error (No service reads or writes another component's tables). Order: this store move, the owners' operations, the import saga, then the package step.

7. Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario) that verify this task. Link new ones here as they're created; the scenario doc itself links back via its "Verifies task" field.

Scenario State Notes
     

8. PRs

PR Title
#2639 [refdata,analytics,reporting] Serve configuration documents over NATS

9. Review

# Comment summary File Decision Notes
1 Reporting writes as the owner for a party-less session, which a user token without a party could reach run_document_handler.cpp Accept Every write requires a session that acts for a party (require_party); a party-less session may only read, as the owner. A test proves a party-less delete is refused and a party-less get succeeds.
2 Refdata and analytics save and delete have no party guard configuration_document_handler.cpp Accept The same rule on every write; a test proves a party-less save is refused.
3 remove is not atomic; deleting a missing document succeeds document services Accept, in part Each remove and the protocol say so; the delete is idempotent for compensation, with a test. Atomicity stays with Import a run's configuration in one transaction.
4 Save returns the id the client sent configuration_document_handler.cpp Decline The store writes the given id; only the party is stamped.
5 for_requested_party reads every party on a bad id handler_helpers.hpp Accept A non-empty id that does not parse is refused, with a test.
6 authorise is copied into three handlers handlers Accept One authorise in ores.service/messaging/authorise.hpp.
7 A dangling configuration_id is no longer caught models Decline The saga creates the configuration through reporting before it saves the document, so the id is real by construction.
8 Missing tests tests Accept, in part Added party-less writes refused, a missing delete and a bad party id; the cross-party refusal already exists; a partial-failure remove is not tested, since remove is not atomic by design.

10. Result

Refdata, analytics and reporting now serve their configuration documents over NATS, so the ORE service can import and export a run without touching their tables.

  • Operation models, with the TypeScript facet off since no UI reads them: ores.refdata.configuration_document_messages (curve configuration save, get and delete; conventions save and get), ores.analytics.configuration_document_messages (pricing engines and today's market save, get and delete) and ores.reporting.run_document_messages (run document save, bind, get and delete).
  • Handlers and registrars in each owner's core, under the caller's session. A get may name a party when the session acts for none, as a workflow step's does (for_requested_party in ores.service). Reporting acts only on a definition the session's party owns, or as the owner for a session with no party.
  • Delete on every document service, for the saga's compensation.
  • refdata::conventions:read and :write are seeded; the other operations use their header table's existing codes.
  • Five headers (curve configuration, pricing model config, today's market config, stress test library, credit simulation config) checked configuration_id against reporting's table in their insert trigger, which runs with the inserting service's grants and so would have failed under the owners' own grants, and broke the rule besides. Their foreign keys now carry :skip_check:, which drops the trigger check and keeps the generated list by configuration operations; reporting's binding holds the reference.
  • Tests drive each handler over real NATS with a minted token (ores.testing/handler_test_support.hpp): save, get by configuration and delete per owner, the permission refusal, and reporting's cross-party refusal. ctest 90/90 after a database recreate.

Emacs 29.3 (Org mode 9.6.15)