Product backlog — inbox
Table of Contents
This is the inbox bucket of the product backlog. Every capture created
via compass capture --note "..." lands here. Inbox captures have not yet
been triaged — they are ideas or observations waiting to be assessed.
At triage, move each capture to one of:
next/— ready to pull into an upcoming sprint.deferred/— real but not soon; long-term horizon.discarded/— explicitly decided against.
Or promote directly to a story via compass capture promote <slug>.
The table below is regenerated by
projects/ores.codegen/scripts/regenerate_backlog_indexes.py — do not
edit the rows by hand. To add a capture, run
compass capture --note "..." and re-run the script.
1. Inbox captures
| Capture | Tags | Description | ||||
|---|---|---|---|---|---|---|
| –reset-goldens deletes the golden dataset and nothing recreates it | ore testing codegen |
Twelve golden round-trip suites under projects/ores.ore/core/tests/ print "Golden file missing (run with –reset-goldens to bootstrap)" when a golden is absent. The flag is real, but it lives on projects/ores.codegen/scripts/xsdcpp_generate_ore.sh, not on the test binary, and all it does is delete assets/test_data/golden_dataset/Products. No suite writes a golden back: each one calls REQUIRE(std::filesystem::exists(gpath)) and fails. So following the message destroys the dataset it points at, and the message never names the command it means. Only xml_example_coverage_tests.cpp writes missing goldens, and only when ORES_BOOTSTRAP_GOLDENS is set. Pick one: give the flag a bootstrap mode the twelve suites honour, or change the message to name the command that recreates the dataset. | ||||
| 87 non-nullable columns still generate an indeterminate member | codegen valgrind models tech_debt |
Only :default_value: reaches a generated struct's member initializer, and codegen synthesises one for bool and int alone. 87 non-nullable columns across the catalogue declare neither, so a default-constructed object of the type they belong to holds indeterminate members that are only found when a write path reads them – which is how the 2026-09-29 nightly found 214 reads in ores.analytics.core.tests and 99 in ores.ore.core.tests. The valgrind hotfix closed the instances it reported and gated the nullable shape; the class remains. | ||||
| A bulk import sends one notification and one NATS event per row | The 298 generated notify triggers fire for each row, so importing 100,000 market observations sends 100,000 PostgreSQL notifications and 100,000 NATS events. | |||||
| A bump of one web package.json leaves the lock file stale until main builds | A dependency bump that edits one package.json under projects/ores.web and not the root package-lock.json passes review, merges, and fails npm ci in every full build. Fastify 5.12.6 did it on 23 October and zod 4.6.6 would do it next. The TypeScript gate that runs npm ci runs only after a merge. | |||||
| A calendar rebuild never rewrites a day it already built | refdata calendars data_quality |
calendar_dates.regenerate only adds days past the watermark, so a rule or exception change never reaches a year that is already built; the business days stay wrong until someone deletes them by hand. | ||||
| A codegen test fails only in the full suite | codegen tests flaky |
test_a_routed_table_checks_exactly_the_codes_routed_to_it passes alone and fails when the whole codegen suite runs, on a clean main, so an earlier test leaks state into the model index it reads. | ||||
| A composite's part models are outside every drift gate | codegen drift component |
A catalogue component's modeling_dir is its own modeling/, so the <part>/modeling/component_overview.org models of a composite are discovered by no entry: check_component_drift.py never renders them and their generated CMakeLists.txt and component_files.cmake have no gate. regenerate_cmake_component_files.py covers the file lists only, and the workspace clean-up had to render the three parts by hand. | ||||
| A composite's parts were never enumerated by codegen discove… | A composite's parts were never enumerated by codegen discovery. manifest.discover_models globs the composite's modeling_dir one level deep, so ores.<comp>/{api,core,service,client,adapter}/modeling/component_overview.org was never rendered. Their export.hpp, tests/main.cpp and umbrella headers therefore carry every template change since the part was last generated: at ores.iam/api those files were last written 2026-06-05, while the templates changed 2026-08-02. A full regeneration flushes about 250 files – the generated-file banner (114), licence rewrapping, the OpenSSL test-main cleanup (22), the database lifecycle listener (20), and test_timeout_listener removal (14). Discovery now reaches the parts; the flush, and each component's reconciliation, are the separate work. | |||||
| A current-state remove reports removed for a delete that matched nothing | codegen database |
execute_delete_query discards the affected-row count, so a generated current-state repository returns remove_status::removed although the tenant-scoped DELETE matched no rows; the audit-column path reads the row back and does not have this hole. | ||||
| A curve feed that serves an adapter publishes no display tick | marketdata synthetic |
The market regime raster draws a row for every running feed and reads each feed's ticks from its display subject. An IR curve feed whose pillars are all served by an adapter publishes nothing there: its tick loop publishes the adapter's tick and continues before the display publish, so the feed's row is empty on the raster and its Ticks tab shows nothing, while the ticks are stored. | ||||
| A curve segment part's insert trigger checks that the segmen… | A curve segment part's insert trigger checks that the segment's element has that part (ores_refdata_validate_curve_segment_part_fn), but writing a new version of the segment with a segment_type of another kind does not re-check the parts it already has. The ORE export refuses the mismatch, so a document never leaves the store wrong, but the store can hold it. A trigger validation sees one column, so the check needs the segment's id and type together: a check on the segment's insert that reads its live parts, or a statement the projection generator writes beside the part validators. Raised in the review of PR #4385. | |||||
| A database recreate fails while the fleet's pools are still closing | tooling compass database reliability |
compass db recreate refuses to drop a database that has connections to it. Stopping the fleet does not close its pooled connections at once, so a recreate started soon after a stop aborts with a few active connections even though –kill was passed. Waiting until the database has no other connections makes it succeed; on this machine that took between ten and forty seconds after the stop. | ||||
| A duplicate tenant code shows the raw SQL error | web iam provisioning errors |
Provisioning a tenant whose code already exists fails with the PostgreSQL text: duplicate key value violates unique constraint tenants_code_uniq_idx, plus the PL/pgSQL context of ores_iam_provision_tenant_fn. The person reads the database's words instead of a sentence such as 'A tenant with the code acme_corporation already exists'. ores.iam should check the code before the insert, or map the unique violation to a named refusal, and the journey should show that refusal on the form. | ||||
| A failing test reached main because no PR workflow runs ctest | ci testing |
The range bound repository test failed on main. The workflows that build and run ctest run on a schedule, not on a PR, so nothing ran the test before the merge. Find out why, and decide whether a PR needs a test gate. | ||||
| A forced password change is advisory | iam security login session |
An account the provisioner marks as owing a password change can still call everything it is authorised for: the flag travels with the login answer and the forced change is enforced by the screen, not by the service that answers a request. | ||||
| A fresh database gives every service account no roles | compass db recreate populates as postgres, so ores_iam_account_role_assign_fn refuses the seed with 'Invalid modified_by: postgres' and every service account holds no role; the run-token exchange then refuses with no_service_identity and every report run fails at the market data export step. | |||||
| A freshly recreated database has no materialised calendar da… | A freshly recreated database has no materialised calendar dates, so every tenor resolution refuses with calendar_not_materialised until somebody rebuilds a calendar. Verified 2026-10-18: after compass db recreate and the ACME provisioning script, ores_refdata_calendar_dates_tbl was empty across all 122 calendars, and every preview and resolve call against any calendar refused. One rebuild fixed it: POST /api/refdata/calendars/Argentina/rebuild with endYear 2027 wrote 1461 dates spanning 2024 to 2027 and the same call then resolved. The journey's test step and the new resolve screen both therefore refuse on a brand new environment, and the refusal is correct but reads as a broken screen. Provisioning should materialise at least the calendars the seed conventions roll on, or the rebuild should run as a provisioning step, or the screens should offer the rebuild where they report the refusal. | |||||
| A generated eventing integration test leaves the parent row it seeds active | codegen tests |
The codegen template that writes the eventing integration tests seeds a soft-FK parent row and closes only the row under test. Because a generated entity's code restarts its sequence every run, the parent left active makes a second run against the same database fail on the duplicate code. Fixing it regenerates 53 files across five components. | ||||
| A generated eventing test's re-drive cannot succeed | codegen eventing tests |
When a notification is late, the generated eventing test re-drives its write with the row it already wrote at version zero, which the store refuses as an existing row, so the retry meant to absorb a lost notification fails the test instead. | ||||
| A generated FX variance swap breaks its own check constraint | code trading seeder |
generate_trades fails at step 8 of 8 on acme_demo: the booked FX variance swap violates CHECK (end_date > start_date), which the product's own constructor refuses to build, so the row reaching the database did not pass through it. | ||||
| A generated recipe sends none for a required enum, so the command aborts | The shell sentinel table knows the C++ primitives but not a component's own enum types, so trade_types add, set and put-many abort at the client. | |||||
| A generated shell command with no arguments wraps an empty try block | codegen shell |
The shell operation command generator emits a try/catch around the block that populates a request from the parsed arguments. A request model with no fields produces no statements in that block, so the generated command contains 'try { } catch (const std::exception& e) { … }' with nothing between the braces. It is harmless but it is noise in every no-argument command, and the first one is authorization_operations_commands::process_get_my_roles, generated from iam.v1.roles.mine. The candidate is for the command template to skip the block when the request declares no fields. The generator lives in projects/ores.codegen/library/templates/, so the fix is a template change plus a regeneration, not a hand edit of the generated file. | ||||
| A junction's timestamp column is not mapped to sqlgen::Timestamp | codegen generator-defect junction tech_debt |
The junction C++ entity template emits a raw std::chrono::time_point for a junction's own timestamp column, which sqlgen cannot serialise, so ores.assets.image_tag fails to compile in image_tag_repository.cpp. The same column type on a domain entity is correctly emitted as std::optional<sqlgen::Timestamp<…>> (compare ores.compute host last_rpc_time with ores.assets image_tag assigned_at). The entity path sets is_optional_timestamp and is_required_timestamp in core.py around line 2418; the junction column-decoration block near line 4595 sets is_int, is_uuid, is_optional_uuid and is_date but never the timestamp flags. Adding them there did NOT change the generated output, so the C++ context for a junction is built on another path that still needs finding. Per G05 the fix belongs in the codegen source with a regression test in the codegen suite. | ||||
| A leverage loses its digits at the ORE binding | A range bound's levels keep the document's text except the leverage, which is a plain float leaf: a document stating 1.05 exports as 1.04999995 while its sibling levels keep their digits. Fixing it needs a lexical double leaf in the ORE binding, which is work on the reapply script and the binding's double writer, not an entity unit. | |||||
| A lookup's display order is not unique | refdata iam sql |
display_order is a free integer, so two rows may share it and the list order is undefined. | ||||
| A lower-case org id passes lint and stops the site build | docs site lint |
compass lint reports every org id link as resolving, and org export refuses the same link. An id spelled in lower case is accepted by the lint and unresolvable by the exporter, which aborts the whole site build on the page that carries it. | ||||
| A market-wide arrival regime, so the desk can panic together | synthetic arrival hawkes regime scenario risk |
The arrival processes built so far model one stream, so each config row clusters on its own events and nothing makes FX, IR and credit burst at the same time. A fast market or a panic is exactly that: every series' intensity rises together for a while. The approach note already lists Regime-switching as a tick mode (two-state active/quiet with a state-transition matrix, lambda_active, lambda_quiet) but no code implements it. Options, cheapest first: (1) one shared market-state machine per run, calm/active, scaling every feed's baseline by a per-asset sensitivity; (2) a common-factor intensity added to every baseline, a shared shock stream that decays; (3) full multivariate Hawkes with a kernel matrix, faithful but O(N^2) and needing multivariate thinning. Option 1 matches the note's vocabulary and gives observable panic windows for scenario and QA runs; option 3 is the only one where one series' events excite another's. All three need the per-row arrival parameters first, so they sit on top of the current task rather than inside it. | ||||
| A merge took an old tree over two merged increments | incident = = merge = = process |
Commit 1398383538 was meant to bring back three planner files. Its tree also reverted 174 files of main and 37k lines, because it was built from copies taken before those merges. The build still passed, so nothing announced it. | ||||
| A message may name a type declared later in its model | codegen modeling lint |
The generators emit a model's structs in the order the file states them, so a response declared above the type it carries produces a header that does not compile. Every documentation gate passes; only the compiler catches it. | ||||
| A narrow vitest run leaves the build defines unsubstituted, so the version-footer tests fail | web testing vitest defect |
Running one test file or one directory fails with ReferenceError: BUILD_RELEASE is not defined, while the same file passes inside the full package run. The globals come from the define block of vite.config.ts and nothing assigns them at runtime. | ||||
| A NATS subscription does not drain on destruction | nats lifetime concurrency tests |
Destroying a subscription while the dispatch thread is inside its callback is a use-after-free of the subscription's own storage, so keeping a callback's captures alive is not enough. | ||||
| A notify trigger collides when a natural key is called key | codegen generator-defect notify-trigger tech_debt |
The notify-trigger template declares changed_key jsonb and derives a changed_<natural key column> variable for the entity's key. An entity whose natural key column is called key therefore declares changed_key twice, once text and once jsonb, and create function fails with duplicate declaration. Found on ores.assets.image. Fix belongs in the template by namespacing the payload variable, but that rewrites the 210 generated notify triggers tree-wide plus iam, so the assets story renamed its column to code and filed this instead. | ||||
| A primary-key column never takes its default | The domain template emits a primary-key column as 'type name;' with no initialiser, while every other column carries the ':default_value:' guard. So the one column where an unset value is most likely, and most damaging, is the one that cannot default: a missed assignment reads an indeterminate int instead of failing a constraint. Found while giving a new key column a default of zero. | |||||
| A profile image over the payload cap cannot reach the validator | The deployment's NATS takes the default 1 MB max_payload, and the upload body carries the image base64 so it grows by a third: an image over roughly three quarters of a megabyte fails in the transport with MAX_PAYLOAD_EXCEEDED and the caller gets a 503, so the validator's own image_too_large answer is unreachable while the picker and the validator both state 2 MB. Direction (product owner, 2026-10-05): an upload larger than 1 MB travels over HTTP storage, not the message fabric. | |||||
| A provisioning run should end with one line that says whethe… | shell |
A provisioning run should end with one line that says whether it succeeded, and if not, which step failed and why. Today it ends with 'Script complete: 5 commands executed', which says the script ran and nothing about what the tenant got. | ||||
| A provisioning run that dies cannot be resumed | code ops provisioning |
When a tenant provisioning run fails or stalls, provision tenant refuses because the code exists and db reset-tenant only re-arms the GUI wizard, so the only headless way forward is recreating the whole database. | ||||
| A QuantLib calendar builds its business days without its holidays | refdata calendars quantlib data_quality |
The rebuild reads only stored calendar rules, and QuantLib calendars have none, so their days and the days of any calendar derived from them mark weekends only, labelled quantlib_computed. | ||||
| A raw ../../ path in the web service answers 500 | A request to ores.web with raw ../../ segments in the path answers 500 from @fastify/static, not 400 or 404. It was so before the QA runner work. Find where the error comes from and map it to a 4xx in the BFF error handler. Also: the French and Portuguese text of the Development module is a machine-style translation and needs a speaker to read it. | |||||
| A record's measured numbers go stale when trunk moves under the branch | agile process verification |
Two independent verification rounds failed the ores.service record for the same reason: counts measured on a tree that trunk then moved out from under. The branch was rebased four times while it waited, and each advance changed a consumer count, a gate's component count or a suite's size. Nothing in the record said which tree a number was measured on, so the drift was silent until a verifier re-ran the commands. | ||||
| A reference table of job titles | Make the job title an entity that a person selects from a list, not a free-text column. | |||||
| A regeneration of the reporting component left projects/ores… | A regeneration of the reporting component left projects/ores.reporting/core/src/repository/parameter_definition_entity.cpp at zero bytes and churned include order and comment wrapping across 21 other generated reporting files. Found in the working tree during the atomic step claim work; reverted rather than committed. Either the entity no longer asks for the ostream operator and the template emits nothing, or the run was partial. Worth checking whether the committed tree and the generator disagree for this entity, and whether any other entity is emptied the same way. | |||||
| A report is owned by a team, not by a person | reporting ownership iam decision |
ores_reporting_report_definitions_tbl records no owner: party_id names a legal entity and modified_by and performed_by are audit, not accountability. Decided, not implemented: ownership belongs to a team, because a team answers for a report, absorbs people leaving and is empty only by omission. What a team is in this system stays an open question. | ||||
| A required decimal always samples 1, and no test checks it parses | codegen shell |
The shell sentinel table gives every required decimal the token 1, and nothing fails when a model's own constraint rejects it. | ||||
| A restored environment arrives in bootstrap mode with no human admin | provisioning db snag |
After a database recreate the database came back in bootstrap mode with no human administrator, so a soak run could not log in until the documented bootstrap create-initial-admin step was performed mid-run. A freshly restored environment that nobody can authenticate against is a provisioning gap, and the step is discoverable only if you already know it exists. Seed the initial admin as part of the restore, or have the restore report that it is in bootstrap mode. | ||||
| A role-grant test depends on which role comes back first | iam test flake |
an_approved_role_request_is_granted_once asserts that a fresh account does not hold the first role that roles.read_latest returns. Whether that holds depends on which role is first, so the test fails or passes with the order the suite happens to run in. | ||||
| A route calls a subject nothing serves | web bff refdata counterparties bug |
/api/counterparties/children reads counterparty_business_centres.list, and the refdata service subscribes to no such subject, so the route answers 503 and the counterparty screen cannot show its business centres. | ||||
| A route that reads an id as an RFC uuid refuses rows the ORE import writes | The curve page returned 400 on a real configuration: the ORE bundle import mints ids whose RFC 4122 version and variant bits are not the ones z.uuid() accepts (90e6d408-aa8e-3e14-206b-d510eefb7c29 has variant 2), while every id the application mints is a v7 and passes. Any other route that parses an address with z.uuid() has the same hole, and only an end-to-end read of imported data finds it. | |||||
| A run whose dependency is dead reports a timeout, not the cause | The party stage waits on the bundle run it published for 1500s and then fails with 'timed out after 1500s; 1/3 steps completed; last step: marketdata.fx_driver_rates (in_progress)', while the real reason sits in another process's log: the marketdata service had exited on a schema error before the run started. Nothing ties a workflow step to the liveness of the service that owns its command subject. | |||||
| A running fleet reports as missing and start times out | In a sandboxed session compass services status and compass bearings classify every unit as missing even while the whole fleet is up: systemctl –user cannot reach the user manager and _unit_active_state returns missing rather than reporting the query failure. That reads as 'nothing is running' when the opposite is true. A follow-up compass services start –use-busctl then waits the full 301s and reports '23/23 still not ready', because _wait_for_logs looks for a Service ready. line appended after start_pos and the already-running processes never log another one; the logs still hold only the previous run's readiness line. The timeout also suggests compass services stop, inviting the operator to kill a healthy fleet. Confirmed on this worktree: status said missing=24 while ports 20205 and 20202 were listening and the services were logging normally. Fix is to distinguish 'query failed' from 'unit missing', and to treat an already-active unit as ready instead of waiting for a fresh log line. | |||||
| A seed profile's generate_trades config names a book by name… | A seed profile's generate_trades config names a book by name, and nothing checks that name against the tree the same dataset seeds. The ACME tree review removed the equity and commodity desks while the acme_demo profile still named 'GBP Equity Derivatives' and 'USD Commodity Derivatives', so every provisioning run stopped at the first config whose book no entity held — and it stopped after the data was published, which makes the failure look like the population's fault. The northwind profile names two books of its own, 'GBP Bonds Book' and 'USD Bonds Book', and the same absence would stop it silently. Check the profile's book names against the dataset's books before the step runs, and refuse with the config's name rather than the book's. | |||||
| A service binary older than its libraries crashes with a lie | code ops services |
compass services start does not rebuild, so a binary built before a library it loads starts and segfaults inside that library; the stack names innocent code and the failure reads as a source defect. | ||||
| A service crashes on exit in faker's locale table | Every service that links faker-cxx segfaults while shutting down, inside the static destructor of faker's locale map, so every stop reports the unit as failed and writes a core dump. | |||||
| A service dies on one failed query, and nothing says so | A repository error escapes the handler and the service runner to main(), so ores.marketdata.service exited EXIT_FAILURE on the first select naming a column its stale schema lacked. The fleet keeps reading as healthy: telemetry records heartbeats but no check flags a service that stopped sending them, and compass services status is the only place the failure appears. | |||||
| A stale publish tree runs code the source no longer has | compass build services http defect |
ores.http.server failed to start asking for a JWT secret. The source stopped asking for one a day earlier and .env correctly has none. The published library predated the change, so the service ran an option the tree had deleted. | ||||
| A step command published while its service is stopped is lost | workflow engine correctness bug reliability |
The engine publishes a step command fire-and-forget to the subject its definition names. If the service that serves that subject is not subscribed at that instant, the command is gone: nothing retries it, nothing reports it, and the run waits for ever on a step that will never answer. Recovery re-dispatches an in-progress step, but only when the workflow service restarts, so the run needs an operator to notice and restart the engine. A step's command must be held until the far end acknowledges it, or a step whose handler has not answered within its budget must be re-dispatched. | ||||
| A step that waited in a queue is called silent | The engine's step deadline counts from dispatch, so a step queued behind a slow one is failed as silent; a real failure then leaves a tenant half-built, because a run's provisioning cannot be resumed. | |||||
| A step's wait outlives the engine's deadline | workflow iam provisioning defect observability |
A provisioning step waits 7200 seconds for a command it publishes, while the workflow engine expires a step at 1200. A command that is never received is therefore reported as twenty minutes of silence rather than a named failure, which is how a subject mismatch between a stale service and the engine stayed invisible. | ||||
| A subject rename leaves durable JetStream consumers unable to attach | Six of the twenty-five services in an environment that has been running across the subject rename do not start, and every one of them dies at the same call: the workflow service and all five compute wrappers fail with js_QueueSubscribe failed: Error. The cause is not the stream. The durable consumers that live in the JetStream file store were created before the rename and still carry the old filter subjects, and JetStream refuses to attach a durable whose filter differs from the one the code now asks for. Measured on eager_maxwell: the workflow-engine-step-completed consumer had Filter Subject workflow.v1.events.step-completed while the service subscribes to workflow.v1.ops.step_completed, and compute_wrapper_shared_x64-linux had compute.v1.work.assignments.*.x64-linux against compute.v1.ops.work_assignment.*.x64-linux. Commit 964d526a39 reconciles a stream's subject filter, and it worked – the streams carry the new subjects – but nothing reconciles a consumer's, so the store keeps a filter the code can no longer match. Deleting the four stale consumers and restarting brings the services up, which is a hand fix every environment must repeat. The stream reconcile is the shape the fix should take: on attach, compare the stored filter with the one being asked for and delete and recreate the consumer when they differ, since a consumer carries no state worth keeping across a rename (all four had zero ack-pending and zero unprocessed). | |||||
| A swap leg's index is checked against no table | trading swap-leg refdata sql |
The swap leg's floating_index_code holds whatever index its leg type names: a floating index, a CMS swap index, an inflation index, a commodity or a formula. The trigger checked it against the floating index table alone and refused the others, so the check was dropped. A floating leg's index is now checked by nothing; the check should come back keyed by the leg type. | ||||
| A system clock drives the date the feeds read | One system clock gives the date the feeds read, and a table of daily rates means a public source is asked for each day only once. | |||||
| A tenant can write a system catalogue | security tenancy codegen synthetic |
A handler generated with system_tenant_validation runs every write in the system tenant and checks only the permission, so a tenant administrator who holds * changes the catalogue every tenant shares. | ||||
| A tenant downloads a compute node and registers it against the platform | compute multi_tenancy distributed security |
A tenant's user downloads a compute node binary, runs it on their own PC, and registers it against an ORE Studio deployment so the tenant's runs execute on their machine. The use case, the journey it needs, and the issues it raises: identity and enrolment, distribution, reaching the platform from outside, trust, and scheduling. | ||||
| A tenant is offered edits to system feeds it cannot make | marketdata synthetic permissions web |
A tenant administrator sees Edit, Start, Stop and Delete on a system feed's page, and an editable Arrivals tab, but a save fails with a database error: the feed and its collection belong to the system tenant. The screens should offer a tenant what it may do on a system feed, which is to read it. | ||||
| A trade generation config overflows an int | synthetic trading seeding provisioning bug |
Provisioning ACME with the acme_demo profile fails at generate_trades: recording the trade generation config 'ACME ACMCOR bond population' fails with 'value 2167221318 is out of range for type integer'. A 32-bit integer column holds a value that needs bigint. The tenant, party, LEI hierarchy, staff, passwords and market data subscriptions all provision, so only the trade population is blocked. Find the column, decide whether it should be bigint or numeric, and fix the model so the seed can record the config. | ||||
| A trade shows a version for every write to its parts | The trade anchor is immutable but its versions carry the economic digest, so every write to a part adds an entry the timeline cannot hide. | |||||
| A username is unique within a tenant only, so a tenant perso… | A username is unique within a tenant only, so a tenant person can share a username with a shared service account of the system tenant. The service actor rule is fixed for that case. Three paths still resolve a username across the tenant and the system tenant: read_any_by_username (history lookup by username picks the newest of the two rows), the account list and the People page. Decide that a tenant refuses a username that names a shared account, and add the check to account creation. | |||||
| A version conflict carries no message | The store answers a stale claim with outcome conflict and code version_conflict, and with an empty message. The profile panel composes the record-changed sentence itself, and the self contact write carries no version claim, so no member path reaches the empty message. The profile journeys checker asserts that the conflict answer carries a message, and fails on the empty one. Decide whether the wire answer carries words of its own, or the checker asserts the code alone. Found by the profile journeys run on the rebuilt database, 2026-10-05. | |||||
| A versioned seed that says it is idempotent fails on a second run | sql seed |
A populate script that inserts version 0 with on conflict do update fails with already_exists when its row exists, because the insert trigger refuses a create that collides with a current row. | ||||
| A web journey test expects text no source writes | testing web main |
On origin/main 36a94808aa, ores.web.tests fails the tenant form case 'opens as a summary, and asks for no settings, when the profile states its own' (parts.test.tsx:338). It expects 'Empty operational uses its standard settings.' and no web source contains that text. The revert-and-restore incident (#4312) probably brought back the test without its source. | ||||
| A workflow compensation that cannot decode its step's comman… | A workflow compensation that cannot decode its step's command or result rolls back nothing and reports no error. In ores.ore.api's ore_import_workflow.hpp and run_configuration_import_workflow.hpp, build_compensation reads cmd_json and result_json with json::try_read and, when either read fails, still returns a rollback request with empty saved-id lists, so the rollback step deletes nothing and succeeds. The saved currencies, portfolios, books, trades or documents stay behind with no trace of why. The behaviour predates the codec move (reflect-cpp's failed reads did the same). Make a failed read fail the compensation, or at least log it, and check the other workflows' compensations for the same pattern. Raised by the review of PR #4360. | |||||
| Add a batch-scoped input key helper to compute_storage | compute shell |
Add an input_key helper for the batch-scoped shared input bundle so dispatch and download do not hand-build the key. | ||||
| Add a language control to the site | The site holds English, French and Portuguese catalogues and a language provider with a setter, but no screen calls the setter, so nobody can change the language. Add a control to the site shell that lists the languages and changes the active one, and keep the choice between visits. Moved here from the retired bindings screen story, whose French and Portuguese words first raised it. | |||||
| Add a panic state to the regime | marketdata synthetic arrival regime |
A third state above active: rare, short and much faster, entered only from active and left back to active, so the chain can show a market that is not just busy but disorderly. The chain becomes a three-state Markov chain, the calm multiplier is derived so the mean pace stays one, and a person can pin panic as they pin active. | ||||
| Add an ACD arrival law | marketdata synthetic arrival quant |
An autoregressive conditional duration law, Engle and Russell's ACD(1,1), beside periodic, Poisson and Hawkes: the expected gap depends on the last gap and the last expectation, so long and short gaps cluster the way trade durations do. | ||||
| Add the curve publication record and the approval chain. The… | Add the curve publication record and the approval chain. The ask, decide, publish and withdraw journeys need a publication record, a market data approval kind and a publish operation. The decision on the record is in the story Add proper curve support to ores.marketdata. | |||||
| An account can hold a TOTP secret and nothing can enrol, prove or revoke it | iam security totp credentials login |
iam.account_credential carries totp_secret, nullable and :no_wire:, and no code path in the tree reads or writes it: there is no enrolment, no code verification and no way to turn a second factor off. The column is a placeholder. The credentials split has just put the secret on the entity that owns it and given it a version stream of its own, so the seam is in the right place; what is missing is the operations, the login contract change, and a decision about how a secret that cannot be hashed is held at rest. | ||||
| An archetype placed in a facet that every component renders … | An archetype placed in a facet that every component renders makes the local check gate verify every component at every address, because check_component_drift.py –changed selects the components the branch touched. Adding the umbrella header to ores.cpp.component therefore drags 94 components into the gate at once, and any component whose generated files main hand-edited then fails it – geo, ores.history/api and ores.storage/service all do. A change of this shape should land as the mechanism alone: the discovery fix, the guards and the template, touching no component file, so the changed set stays empty and the gate passes. Each component then regenerates, and reconciles its hand-edited files, inside its own clean-up task. The bulk flush of about 250 presence files is real work, but it belongs to those tasks, not to the enabling change. | |||||
| An asset class is not a data-quality severity | The badge catalogue paints asset classes but files them under a severity_code, which is a data-quality judgement. Nothing chooses that severity for a class, and no reader can act on it. Decide what severity means for a badge that is not a finding, and let a class carry a colour without one. | |||||
| An asset class is two lists, not one | asset-class taxonomy refdata marketdata |
The product asset class taxonomy is authoritative, runtime-managed and FK-validated, and it is the list a market series takes its class from. The market data namespace is a different and much looser axis: the key grammar an oresmd_uri authority names, accreted from ORE's own key-prefix conventions rather than from any product taxonomy. The two share five spellings and diverge on the rest, and nothing in the repository declares the mapping between them. | ||||
| An embedded trade outlives a parent that failed to import | ore import trading structure |
The ORE import books a total return swap's, a composite's or a contract for difference's embedded trades before the parent and skips the parent when one of them fails, but the embedded trades that did save stay in the book with no parent. The parent and its embedded trades should be written as one unit. | ||||
| An entity's key on the wire cannot be composite | codegen protocol keys |
declared_key_field returns one field, so an entity whose identity is a pair cannot address a row and its by-key reads ignore half the key. | ||||
| An events collection cannot be wildcarded | nats = = eventing = = http |
A NATS wildcard is a whole token, so a subscription to *.v1.*_events.> is a literal that matches nothing and the server accepts it and delivers nothing. The events namespace should be its own token, <component>.v1.events.<collection>.<action>, so one subscription can hear every event without also hearing every request. | ||||
| An inflation swap on a YY leg cannot be stored | The rates review's finding 2 was fixed for a CPI leg: the import reads the index, base level and lag from the CPI leg's payload and the export writes them back. A year-on-year inflation swap states the same three on a YY leg, and neither direction has a YY branch, so the fact row's inflation_index_code stays empty and the table's non-empty check refuses the insert, exactly as before the fix. | |||||
| An instrument cannot be saved through the trading service | trading storage audit defect |
Every put_*_instrument_request write struct carries the business fields and no audit, and no trading handler stamps one, so the store's modified_by validation refuses every instrument the service writes. The ORE import is the first caller to find it. | ||||
| An operation named get_<entity> silently shadows the entity verb's type | codegen protocol nats |
A domain operation whose name is get_ plus an entity's own name generates the same C++ and TypeScript type as that entity's generated get verb, in the same namespace. Nothing rejects it and no gate catches it: the build picks one, the service subscribes to the wrong subject, and the failure surfaces as no responders, which reads as an unreachable bus. | ||||
| An optional scalar in a message has no shell token form | codegen shell modeling |
A message field declared std::optional<int> is refused by the shell facet: the generator has no token form for an optional scalar, so the whole component regeneration stops. The model author then has to express the value another way. | ||||
| ASCII case conversion is written out in eighteen files | utility cleanup |
Eighteen non-test source files convert ASCII case with their own loop or with std::toupper and std::tolower; one helper in ores.utility would replace them. | ||||
| Assert the history field projection covers every member | codegen history diff tests |
The generated render_<entity>_fields projection has no coverage check at all, so a field the projection template does not handle is silently absent from every diff; the one hand-written test that guarded this was deleted as a spot test. | ||||
| Audit every field that holds an oresmd URI | One validator was written for one column. The same URI vocabulary appears in other fields that nothing validates, so the same defect can exist unnoticed elsewhere. Find every column that holds an oresmd URI, give each the validation or a reason it does not have one, and pin what each field is allowed to name rather than only that the URI parses. | |||||
| Authentication is optional at runtime on both transports | security auth http nats defect |
The HTTP server skips its whole auth middleware block when no authenticator is configured, and warns rather than refusing; the NATS request context comes back unauthenticated when no verifier is configured; and has_permission returns true for an empty permission list to keep pre-RBAC tokens working. A deployment that forgets to configure either transport therefore accepts everything, and nothing reports it. | ||||
| Batch 3 of the badge/image/plain-text rendering rollout (tas… | Batch 3 of the badge/image/plain-text rendering rollout (task 08547F5A, closing): the audit/classification story is closed and batches 1-2 (badge_key wiring + regenerated entities) shipped. What remains from the implementation task's acceptance is the plain-text documentation leg: for each entity the audit classified as plain-text (no badge/image wiring), record a one-line documented reason per entity, and publish the plain-text-vs-badge-vs-image policy note. Small, documentation-only, no codegen changes expected. | |||||
| Batch the ticks of one instant into a single transaction | marketdata ingest performance batching database |
The ingest stores one observation per tick, each in its own transaction and round trip, so a burst from every feed at the same instant costs one acquisition each. Buffer the ticks of a timepoint and commit them together, without breaking the rule that a republished tick is already stored. | ||||
| Blotter subjects break the closed verb set (resolved) | trading nats codegen |
Resolved: the subjects moved to the ops namespace. The blotter subjects trading.v1.blotter.rail and trading.v1.blotter.page use verbs outside the closed set of eight, so the subject conformance tests fail on main since PR #4403. | ||||
| BondFutureOption is a bond product with no routed table. The… | BondFutureOption is a bond product with no routed table. The trade type catalogue lists it with product_type bond, has_options true and an empty instrument column, so its row cannot be booked anywhere and the planner cannot draw it: a tenant holds no option on a bond future, and the constructor written for it is never reached. Either the catalogue routes it to bond_instrument, which needs its own fact shape because it states a contract and an option at once, or it is declared an unbookable product with the reason recorded. | |||||
| book_trade cannot validate a trade's origin. The trading ser… | trading |
book_trade cannot validate a trade's origin. The trading service does no in-service authorisation: only ores.iam.core run_grant_operations_service reads ctx.roles(), and trading has no permission vocabulary, so the boundary is the NATS subject ACL, which decides who may call book_trade and not what they may claim inside it. ctx.service_account() is the trading service's own database user, so a check on it judges the host rather than the caller and refuses the population writer and ORE import, which both arrive through that service. ctx.actor() comes from the verified JWT, but the synthetic service forwards the party's end-user token, so actor is the user and not the generator. A real check needs either a permission model for trading operations or an origin the server derives instead of a client field. | ||||
| Bootstrap the NOK and BRL overnight curves | ir curves bootstrap marketdata |
The curve bootstrap does not implement ACT/ACT.ISMA (NOK-NOWA) or BUS/252 (BRL-CDI), so neither currency has an overnight curve config, and the stored NOWA fixings are read by no curve. | ||||
| Bring the no-audit-columns entities over with the domain member gone | codegen marketdata |
:no_audit_columns: now drops the recorded_at domain member as well as the audit tail, so the marketdata entities that state it and the two hand-written tests that populate it need regenerating together when that component is brought over. Resolved: PR 3 did exactly that. | ||||
| Bring the official catalogue generator up to its output | sql codegen marketdata |
generate_official_catalogue.py was last changed on 10-28; five commits on 10-30 edited the SQL it writes by hand, so running it would undo the feeds, scopes and routes. | ||||
| Build a rate blending service. Several simulated providers (… | Build a rate blending service. Several simulated providers (Bloomberg, Refinitiv, ICE, the exchanges) publish their own spot for a pair such as EUR/USD. A desk prices off one rate, so a rate blending service should read the providers' spots, blend them by a configured rule (a weighted mid, the best bid and offer, a median of the fresh quotes, with staleness and outlier rejection), and publish the blended EUR/USD as its owner. Until it exists, the conflict guard on synthetic collections lets one bound system collection run, so one provider is bound, chosen arbitrarily, as the authoritative source and the others run sandboxed. Follows the story Organise feeds by provider and scope (0A32284A-5F8C-4A99-9539-34923631DED3). | |||||
| Build ores.web only when its sources change | build cmake web |
The ores_web custom target has no output, so every build runs npm run build for about 20 seconds, even when nothing in ores.web changed. | ||||
| Build the compute catalogue screen: what the grid runs | web compute operations |
The Keep what the grid runs journey has read and write subjects for apps, versions, platforms and packages, and no BFF route serves a compute screen. The system home lists it as upcoming. | ||||
| Build the market data feeds screen for the system administrator | web operations marketdata |
The Keep the market data feeds running journey has a design and most of its subjects, and the web client has no screen or BFF route for it. The system home lists it as upcoming. | ||||
| Build the trade digest tests again | trading tests cmake correctness |
A CMake regeneration dropped add_subdirectory(digest_tests) from ores.trading.core, so the trade economic digest tests have not been built or run since 2026-10-16. | ||||
| Build the yield curve process types screen for the system administrator | web marketdata synthetic |
The Manage the yield curve process types journey has a design and generated subjects, and no web page, BFF route or shell verb reaches the catalogues. The system home lists it as upcoming. | ||||
| Calibrate a feed's arrival law from its ticks | marketdata synthetic arrival hawkes calibration |
Fit a feed's arrival law to observed tick times: the Poisson rate by its mean, a Hawkes baseline, branching ratio and decay by maximum likelihood, so a synthetic feed can be set to look like a live one rather than by hand. | ||||
| Cap the rows a generated list may return | reporting codegen review |
The generated list applies the caller's limit and no ceiling of its own, so a client that states none, or a large one, pulls every row the filter matches. The result rows are one such list: the BFF asks for 20,000 rows of one run, and any other client with the read permission could ask for every row of the tenant. A page cap in codegen, or a required filter for a table whose key is a run rather than a row, is the decision this captures. | ||||
| Carry a document's families as a bundle, not as one struct of typed arrays | The curve configuration document is one struct of 34 typed vectors of full domain types, which the data classifications forbid as a second type system. It is the same anti-pattern the conventions carried before they were split. File the redesign as its own story. | |||||
| Carry the ORE import choices as a typed member, not a JSON s… | Carry the ORE import choices as a typed member, not a JSON string. ore_import_request and ore_import_execute_request carry import_choices_json, a string the shell fills with rfl::json::write(choices) (projects/ores.shell/application/src/app/commands/trading/ore_commands.cpp:637) and the execute handler parses back (ore_import_execute_handler.cpp, step 3). The web protocol twin declares it as a string too. That is untyped data on the wire: nothing checks the choices' shape until the handler runs. Model the choices in ores.ore.api (planner::import_choices lives in ores.ore.core, which the api cannot name), make the member typed in both requests, and move the shell and web callers. The ore codec task gave import_choices wire_fields and enum text forms, so the typed member needs no new codec. | |||||
| Carry the volatility parts through the DQ publish | refdata dq curveconfig bug |
fx_volatility_smile, cap_floor_proxy_config and swaption_proxy_config have no DQ artefact table and are not in the curve configuration publish list, while their entries are. A staged curve configuration that states an FX smile or a proxy publishes the entry without it, and nothing refuses. The swaption smile and the inflation seasonality got artefacts when they were split; these three did not. | ||||
| Check every create script reaches its manifest | sql codegen checks |
A generated create script that no component manifest includes passes sql-hygiene and model-drift, and fails only at a database recreate; the earlier model commit reported its targeted checks green with the scripts unwired. | ||||
| Check every web request against the server's decoder | web protocol testing |
The web server tests stub the server, so a request the C++ decoder refuses passes them. PR 2588 broke seven routes that way. A contract test should run every request the web client sends through the generated decoder. | ||||
| Check that every generated registrar is wired into its service | codegen refdata messaging |
The refdata service had calendar name and day counter registrars that nothing called, so their subjects had no responder. | ||||
| Check the generated CMake file lists in CI | build ci cmake codegen |
regenerate_cmake_component_files.py –all –check is red on main: 31 component_files.cmake files across 16 components are stale. No workflow and no compass command runs the script, so nothing reports it. Wire it into the codegen drift job so a stale file list fails a pull request. | ||||
| check_component_drift.py corrupts a branch that is behind main | Running projects/ores.codegen/scripts/check_component_drift.py with the component flag on a branch whose codegen templates are older than main's regenerates the whole component in place from the stale templates. It rewrote 67 tracked files and materialized 44 untracked ones under ores.trading, reverting newer generated shapes (the trade sub-struct split) and dropping hand-written protocol types (export_portfolio_request). A build running concurrently then failed on the clobbered headers. The script is only safe for components in its KNOWN_DRIFT_FREE registry, which requires zero drift; any other component needs the single-entity compass codegen entity generate command instead. Recovered by stashing the fallout; a matching stash entry dated 2026-09-11 shows this has bitten before. | |||||
| Classify a product type as flow or non-flow | trading refdata product classification junction authorisation |
The authorisation queue divides deals into flow and non-flow, and the division is a hand-written set of trade type codes in the BFF. It is a property of the product type, and desks disagree about where the line falls, so the store should carry it: on the trade type row for a tenant, with a party-level override where a party draws the line elsewhere. | ||||
| Codegen a bucketed range read for a hypertable | codegen telemetry compute timeseries |
The entity codegen generates paged and newest reads and cannot express a read that groups a hypertable into time buckets. The grid and node series reads are hand-written, and every sample table will need the same read. Let an entity model declare it, and generate the repository read, the columnar protocol and the TypeScript schema. | ||||
| Codegen an installation-owned current-state table | The work ledger is a mutable table that only a session of the system tenant reads or writes, with atomic claim statements. The entity templates offer a current-state shape and a shared-reference policy, and no policy that admits the system tenant alone, so the ledger is hand-written. Let a model state the installation-only policy and generate the table, the domain and the repository base. | |||||
| Codegen can own a junction's service, so the hand-written junction registrars are duplicates | codegen junction tech_debt |
A junction model whose nats-handler, nats-sub-registrar and service flags are nil generates no handler, yet its shell-command flag generates commands that publish to per-operation subjects. Nothing serves them. Setting the three flags to true makes codegen emit the handler, the registrar and the service, as ores.assets.image_tag now proves. ores.iam.account_party carries the same nil flags and is served by a hand-written registrar in ores.iam/core/src/messaging/registrar.cpp, so that registrar is a hand-written duplicate of a generatable artefact. | ||||
| Codegen template cpp_domain_type_table.cpp.mustache streams … | Codegen template cpp_domain_type_table.cpp.mustache streams enum columns raw (table << iter_var.column), which cannot compile: generated enum classes have no operator<<, only to_string(). trade_type_table.cpp is the first entity table with an enum column (product_type, added in the badge batch-2 trading rollout); it was hand-rendered via to_string(). The template needs an is_enum branch like the existing is_bool/is_optional/is_uuid branches. | |||||
| Codegen: auto-derive most Qt drawer fields instead of requir… | Codegen: auto-derive most Qt drawer fields instead of requiring them spelled out per entity. domain_include/domain_class/protocol_include are pure functions of component and entity_singular. get/save/delete/history request/response/message_type class names are pure functions of entity_plural/entity_singular plus the standard dq::messaging naming convention already used identically by every entity's generated protocol header. collection_name/item_var are typically just entity_plural/entity_singular themselves. Only key_field, has_uuid_primary_key, settings_group, window_title, icon, and the has_ Qt knobs are genuinely entity-specific and need spelling out. Discovered while manually authoring near-identical Qt drawers for catalog, change_reason, change_reason_category, data_domain, and dataset_bundle – the boilerplate was copy-pasted with only entity-name substitutions each time, exactly the drift-prone pattern profiles exist to eliminate. | |||||
| Codegen: has_parent_id without its two column properties fails silently | codegen variability guard |
Turning has_parent_id on emits a recursive-CTE hierarchy function that names the entity's parent_id_column and hierarchy_name_field. If the model sets the feature without those two properties, the function is generated with empty column names and nothing fails. Eleven entities sat in exactly that state, hidden only by a separate namespace defect. A loader check that rejects the combination would turn the silence into a hard error at regeneration time. | ||||
| Collapse the ORE import rollback's saved-entity lists into one ordered collection | trading ore protocol codegen rollback |
The rollback request carries one string list per entity kind, which a generic ordered list of kind-and-key entries would replace; adding a kind would then change one field instead of four lists, two handlers and a wire name. | ||||
| compass build fails when only busctl reaches the user manager | compass build sandbox systemd tech_debt |
The build wraps cmake –build in systemd-run –user –scope, but systemd-run uses the plain transport, so a sandbox where only busctl reaches the user manager fails the build outright. | ||||
| compass build scopes itself with systemd-run, which the sandbox cannot reach | Inside the DSH sandbox, compass build fails before it compiles anything: 'Failed to connect to user scope bus via local transport: No data available'. The memory-cap scope is added with a raw systemd-run –user –scope, which needs the private user-manager socket at $XDG_RUNTIME_DIR/systemd/private. That socket is unreachable here, which is exactly why systemctl_bus.py exists: it drives the same user manager over busctl on the D-Bus session bus, and that path works. So the detection and the action disagree – _has_user_systemd() probes through the shim and answers yes, and the scope creation then fails through the raw call. Measured: 'busctl –user list' succeeds unprivileged, 'systemctl –user show-environment' fails, 'systemd-run –user –scope' fails. Two candidate fixes: route the scope through the shim, or make the check probe what it is about to do and run unscoped when it cannot. Workaround in use is an escalated shell, which is a policy ask every build should not need. | |||||
| compass check –only still runs the heavy phase's other members | compass checks snag |
compass check –only step-consumers –include-heavy was expected to run one check, but it started the build, db and ctest closure as well and began a build while the fleet was running. –include-heavy admits the phase's own members even when –only names a single check, so –only is not literally only. Either make –only authoritative, or document that it selects within the phase rather than narrowing the phase. | ||||
| compass check leaves the service fleet running, so the next check cannot rebuild the database | compass testing |
ticks-smoke starts the environment's services and does not stop them. The next compass check then fails its db step with 'there are 2 active connection(s)', and ctest runs on a stale database. | ||||
| compass db recreate -D drops the environment's shared roles | compass database defect |
Recreating a database under another name with -D still runs drop_roles.sql for the whole environment, so a scratch test database cannot be built beside a deployment that holds data; it failed safely only because the roles own objects in the deployment database. | ||||
| Compass has no way to create a story or task without creatin… | compass agile tech-debt paperwork |
Compass has no way to create a story or task without creating a branch. 'compass story new' unconditionally runs 'git switch -c branch base' (see _scaffold_and_branch in compass.py) with no opt-out flag; 'compass task new' creates the branch object without switching (worktree stays put – the start vs add distinction), but still creates a branch; only 'compass task start' switches. There is no branch-free scaffold path at all. Triggered while doing pure paperwork: creating an umbrella story under sprint 25 to group all trading-instrument-to-codegen port tasks, and re-parenting the existing port tasks (pilot equity_position_instrument, task 91ED2388 via PR 1857; the 5-entity batch plus remaining conversions, task F560ADDF via PR 1874; eventing facet work) into it – 'compass task move' already supports relocating tasks between stories UUID-intact, but creating the target story forces a branch switch, which is hazardous on shared mid-flight feature branches with unmerged commits (here: feature/codegen-nats-eventing-and-integration-tests). The manual workaround is to hand-author story.org plus sprint-table row plus task orgs plus regenerate indexes, all of which the scaffold does by itself. Desired: a –no-branch flag (or a story add / task add subcommand) that scaffolds the org files and sprint row without touching git, mirroring how 'task new' already avoids the switch. | ||||
| compass lint runs one of the six checks in the doc-lint job | ci documentation tooling tech_debt |
The doc-lint job runs six checks and only the first is compass lint; the other five are committed build scripts the workflow invokes by path. A contributor who runs the verb named after the job gets a green result while CI can still fail, and the trigger filter names only the generate_skill scripts. | ||||
| compass site page publishes paths the full build excludes | compass site build |
compass site page hands the changed files to ores-build-page.el by name, and that path calls org-publish-file directly, so it never consults the site:pages project's :exclude regex. A page under an excluded path is therefore published by compass site page while a full build skips it. Observed: with projects/ores.dsh_kanban/test/fixtures added to the exclude regex, the page builder still published 65 fixture pages, and only stopped once the named-file loop was given its own exclusion test. The fix is to apply the project exclusion in that loop, or to route named files through the project machinery. | ||||
| compass story new –kind hotfix flips the story to STARTED b… | compass story new –kind hotfix flips the story to STARTED but leaves its row in the sprint's Hotfixes table at BACKLOG, so the sprint table disagrees with story.org until the row is edited by hand. Observed on the main_ci_red hotfix: the scaffold output printed 'state: BACKLOG -> STARTED' and 'story state -> STARTED', yet the sprint row stayed BACKLOG. Either update the sprint row when the story state flips, or leave the story at BACKLOG until task start so the row is written once. | |||||
| compass task done does not flip the task's row in the story'… | compass agile |
compass task done does not flip the task's row in the story's * Tasks table whenever the story's * Status block names that task as Next. The row updater _update_task_row_in_story (projects/ores.compass/src/compass.py:4002) walks the story line by line and acts on the FIRST line that links to the task, which is the Status table's Next row. That row splits into four cells, fewer than the six a task row has, so the function returns False and the real row, further down and correctly shaped, is never reached. The command prints no error: it simply omits its 'story * Tasks row -> DONE' line. Closing a task is exactly when the Status block tends to name it, so the failure is the common case, and the drift it leaves (task DONE, story row BACKLOG) is the silent inconsistency the runbook warns about. The candidate fix is for the loop to skip a match whose cell count is not the task table's and continue to the next match, rather than returning False on the first one, plus a unit test over a story text whose Status block names the task. Found while closing the bundle write, where the row was corrected by hand. | ||||
| compass task done misses the story Tasks row. _update_task_r… | compass task done misses the story Tasks row. _update_task_row_in_story (projects/ores.compass/src/compass.py:4002) scans for the first line that holds the task id link and returns False when that line has fewer than six cells, so it never reaches the real Tasks row. Seen when BAE5860D closed on 2026-10-04: the story Status Next row links the task, is matched first, and the Tasks row stayed STARTED; the row was set by hand. The scan should skip lines that are not rows of the Tasks table. | |||||
| compass task done silently skips the story row when a Decisions bullet names the task first | Closing a task can leave its row in the story * Tasks table still open, and the command reports no error. The task flips to DONE, the journal is stamped, and the story row keeps its old state. | |||||
| compass test run crashes on test output that is not UTF-8 | compass testing bug |
compass test run reads the test process's output as UTF-8 in _run_logged and stops with UnicodeDecodeError ('utf-8' codec can't decode byte 0xa1) when a Catch2 failure expands a uuid as raw bytes. The run's results XML is written, but the summary and the failure detail are lost. Seen on 2026-11-03 with a failing uuid comparison in ores.ore.core.tests. Decoding with errors='replace' would keep the run readable. | ||||
| compass test run crashes when a suite prints bytes that are not UTF-8 | compass testing |
_run_logged decodes a child's stdout as strict UTF-8, so a Catch2 failure that prints MessagePack bytes stops the run with UnicodeDecodeError, and every later suite goes unreported. | ||||
| Compute the SHA-256 of a run's archives and the files in them | reporting compute storage ore |
The files of a run show no digest for the input package, the output archive or the files inside them. Compute the SHA-256 of each archive when it is stored and of each file when it is listed, so a person can check a download against the run. | ||||
| Consolidate the duplicated tarball archivers into one shared utility | Move the libarchive pack/unpack archiver to a shared home (ores.utility) and consolidate the two duplicate implementations | |||||
| Conventions spell calendars in a vocabulary ORE refuses | refdata ore conventions calendar |
The convention seed holds refdata.calendars codes such as UnitedStates.Settlement, which ORE's parseCalendar refuses; ORE reads its own calendar names, such as US or US-SOFR, and the tree has no translation between the two vocabularies. | ||||
| Cover the 43 ORE trade types that no example exercises | ore trading testing coverage |
43 of the 122 oreTradeType values in the regenerated domain.hpp appear in no XML under external/ore/examples/, so no example-derived test can ever reach them. The example-walking golden test added with the v17 sync cannot cover them: it derives its cases from the examples tree. Split by what is missing. Four types already have hand-written ores.ore code and need a fixture only: BondFuture and BondPosition have a mapper, BondPosition and EquityOptionPosition have a test reference, and Failed is the enum sentinel handled in exporter.cpp and importer.cpp. The other 39 have no example, no mapper, and no test, so each needs both. The seven v17 types are a subset of that 39 and are tracked separately at task 64CB13D8. | ||||
| ctest can report green when a Catch2 binary fails to register its cases | ORES_CATCH2_ARGS in projects/CMakeLists.txt passes –filenames-as-tags, and that flag takes a Catch2 code path which skips duplicate-test-case detection. A component suite with duplicated case names ran 16 cases and exited 0 under ctest, while the same binary refused to run under –list-tests and under a bare run. The estate has one test binary per component, so any registration fault can hide behind a green ctest. | |||||
| curve_configuration_document_service saves and reads no comm… | curve_configuration_document_service saves and reads no commodity curve rows: commodity_curve_configs, commodity_price_segments, and the commodity curve parts (interpolation, direct, cross currency, basis) are absent from its write, read and remove paths, and from the dq publisher's table list. A saved curve configuration keeps its CommodityCurves definitions but drops their settings, so the export fails with 'curve NaturalGas in section CommodityCurves has no settings row'. Main has the same gap. Observed live on 2026-11-02 with 'ore import-run' then 'ore export-run' of external/ore/examples/MarketRisk/Input/Curvealgebra/curveconfig.xml. | |||||
| Declare a shape when a synthetic feed starts. Feed ticks nev… | Declare a shape when a synthetic feed starts. Feed ticks never declare axes, so a synthetic IR curve has points and no grid, and the curve evolution screen cannot show it. Make the feed declare its tenor ladder with the same shape writer the import uses. It touches marketdata and synthetic and crosses into the synthetic implementation story, owned by another environment. | |||||
| Decode or refuse a storage put's content encoding | storage correctness |
The storage put handler stores the content as sent and ignores content_encoding, so a base64 put stores the base64 text and reports its length. | ||||
| Defects in the generated C++ templates | Five defects in the shared C++ templates found by the G04 review of ores.marketdata's generated code: lost claims report as internal errors, put_many reads back row by row, three archetypes have no generated test, generators fill foreign keys with random UUIDs, and the eventing test assumes audit columns. | |||||
| Delete the per-feed clock now that one scheduler drives a run | synthetic arrival scheduler tests |
Both feeds still carry a tick_clock and a clock_.run branch for the case where no scheduler was given. It is unreachable in production, since every feed_build_context sets a scheduler, and no test exercises it — so it is dead code that exists only because the feed tests and the adapter runner construct feeds without a scheduler and expect the feed to tick itself. Removing it means making the scheduler a required feed dependency and migrating those callers: the five service-test fixtures (folder cascade, config handler, selection, registry stub) and the adapter test each need their own scheduler and a thread running it, generator_runner needs the run's scheduler in the test, and the remaining tick_clock cases move to the scheduler before the clock is deleted. Attempted on 2026-10-25: everything compiled and the quant and API suites passed, but the service suite hung under ctest, so the attempt was reverted rather than shipped. | ||||
| Derive the compute node's HTTP base URL instead of copying a stale host profile | compute deploy snag |
The .env.<host> profiles are gitignored hand-maintained copies with no regeneration path. goedel, newton and simba carried ORES_COMPUTE_HTTP_BASE_URL=http://192.168.1.172:20400 while the environment's HTTP server moved to 20401, so every remote job failed with 'connect: Connection refused' and the grid ran on local wrappers only for about fourteen hours before anyone noticed. The profiles are stale in other ways too: service DB ports at 5433 against 5432 in .env, and variables this environment no longer has. env deploy copies the profile faithfully, so the defect stays invisible until work is dispatched. Derive the URL from .env at deploy time, or give the profiles a generator. | ||||
| Desk-facing product type | domain trading modelling product |
ORE Studio models products at ORE's trade-type granularity, which is a pricing-level abstraction; a desk treats several configurations of one trade type as distinct products. | ||||
| Document the mechanisms that only exist in the code | documentation codegen testing |
Two generated and testing mechanisms work but appear nowhere in the knowledge base — the per-entity JSON stream operator, and the test logging switches. Both were only discoverable by reading source. | ||||
| drift-sweep was red on 32 refdata generated files, and regenerating fixed it | compass check –only drift-sweep failed with 32 files that a render would change, all in ores.refdata generated output. Every diff was clang-format wrapping and include ordering, with no semantic difference, so the gate was reporting formatting drift and not a model disagreement. Regenerating the component with compass codegen regenerate –component refdata –address ores restored all 32 to the content HEAD carries: the working tree had them reformatted away from what the generator produces. The sweep is green afterwards and a second regeneration leaves the 32 clean, so the fix is stable rather than incidental. git status went from 232 to 200 modified paths. Worth knowing because the failure looks like a code change and is only a formatting one, and because the same shape could hide a real drift behind 31 cosmetic ones. | |||||
| Drive the step-consumers config assertions wrong once, with the fleet down | nats checks follow-up |
The step-consumers gate asserts ack explicit, ack_wait 30s, max_deliver 10 and retention interest, which is what the step_claim_lease invariant is written against. Only the count-and-name assertion has been driven wrong: a stray consumer made it exit 1, and removing the stray returned it to 0. The four config fields have only ever been observed holding their correct values. Change each in turn on a legitimate consumer with the fleet down, record the verbatim failure for each, and restore. A stray consumer is the wrong instrument because it fails on count before the config is examined. | ||||
| Drop rfl::Skip from the credential once nothing writes it wi… | Drop rfl::Skip from the credential once nothing writes it with reflect-cpp. account_credential wraps password_hash, service_password_hash and totp_secret in rfl::Skip because the generated http route (account_credential_routes.cpp) and shell commands (account_credential_commands.cpp) still write the credential responses with rfl::json::write; the generated codec already leaves the no_wire columns out. Once the http and shell codec tasks move those templates to the codec, derive the wrapper from the codec opt-in (wrap a no_wire column only for a model still on the reflector), regenerate, remove the .get() and .value() reads in account_operations_service.cpp and the domain test, and keep the codec test that checks no secret reaches any encoding. A first attempt in PR #4368 was reverted for this reason. | |||||
| Durable documents link into agile content | documentation zettelkasten graph hygiene |
Knowledge, meta and recipe documents hold org-roam links into stories, tasks, sprints and captures, which the one-way rule forbids. Around 140 links across some 70 files; compass lint reports the live count. Sweep them, absorbing provenance into the durable page where the link carries information rather than deleting it. | ||||
| Durable documents still link back into agile content | documentation lint workflow |
About 180 id links run the wrong way, from doc/knowledge, doc/recipes, doc/meta and doc/llm into stories, tasks, captures and plans, which the lint reports as an advisory rather than a failure. | ||||
| Editing a run re-parents it to the editor's tenant | tenant_id is server-owned and stamped from the session, so a system-tenant caller editing another tenant's run moves the row to its own tenant, leaving two open rows for one id. Met while fixing the timestamps; pre-existing and unrelated to them. | |||||
| Ensure all entities follow the entity naming convention | naming entities codegen |
The entity naming page now states the patterns the code follows. Review every entity against it and bring the ones that disagree into line, or record why they are exceptions. | ||||
| Evaluate C++ NATS client libraries | nats dependencies research |
Assess antlad/nats_asio, dancasimiro/nats.cpp and ishbir/cppnats as a replacement for, or reference for, the ores.nats wrapper over cnats. | ||||
| Evaluate migrating codegen mustache templates to Handlebars | codegen templates tooling tech-debt |
Assess whether ores.codegen's pystache-based templates should move to Handlebars for real boolean-logic helpers, reducing hand-computed OR-flags in core.py. | ||||
| Every catalogue in the platform is seeded with the same boil… | dq |
Every catalogue in the platform is seeded with the same boilerplate data quality metadata, so none of it says where the data came from or what it is worth. | ||||
| Every generated NATS handler says its reads check the permission a write needs | cpp_nats_handler.hpp.mustache carries one comment above every handler it emits: 'The adapter decides nothing: it proves the request, checks the permission a write needs, decodes the canonical request, calls the service and replies with the response the service filled.' The sentence is written once and emitted for every verb, so a read verb's comment claims a write permission and a delete verb's claims a write too. The generated handlers for ores.iam.sessions are the concrete example: list, get and get_many are now guarded with iam::sessions:read, and all seven verbs carry the same comment. The fix belongs in the template, not in one generated file, and the template is itself tangled from its org source, so the change has to be made there. Raised during the review of PR #2465, where the same rewording had been applied by hand to one generated file and was reverted by regeneration. | |||||
| Every scaffold writes an empty Result heading that a second append duplicates | 49 task documents across the agile tree carry two '* Result' headings, because compass scaffolds one and a later append writes another. compass pr merge warns on it but nothing fails. Collapse the duplicate headings in one sweep and add a check that a task document has exactly one Result heading, so the warning is not the only guard. | |||||
| Explore model validation support using ORE output reports | model_validation pricing ore ore_studio sprint_25 v0 |
ORE exports structured pricing reports (flows.csv, additional_results.csv, curves.csv) that allow independent NPV reconstruction without source-code access — cashflow-level discount factors, forward rates, and model parameters are all exposed. Investigate how ORE Studio can consume these outputs to build model validation workflows: benchmarking, vendor comparison, discrepancy drill-down. | ||||
| Export currencies and calendar adjustments as ORE documents on the server | refdata ore export |
There is no server operation that writes currencyconfig.xml, and the calendar adjustments export returns data rather than the document. | ||||
| Export the BMA basis swap lockout under the name ORE reads | ore conventions import_export |
ORE's BMABasisSwapConvention::fromXML reads OvernightLockouDays and its toXML writes OvernightLockoutDays. The ores.ore mapper reads and writes OvernightLockoutDays, so a conventions document ORE Studio exports carries a lockout ORE never reads, and a document written with the parser's spelling imports without it. Write the spelling ORE reads, read both, or report it upstream. | ||||
| Expose the telemetry stats surface | telemetry protocol codegen |
Four telemetry_repository reads and their SQL functions have no caller: the stats surface is implemented and tested but has no subject, so nothing can ask for it. | ||||
| Extend the greek ladders to every risk class | reporting sensitivity greeks risk-class |
Swaption, cap and floor, credit, equity, inflation, commodity, correlation and bond future ladders: the same report over a different sensitivity block, gated on market data the store does not hold. | ||||
| Extend the handler permissions gate to IAM | check_handler_permissions.py's registry omits iam, so the new IAM read codes are ungated and pre-existing IAM write and delete codes are unseeded (iam::account_statuses write/delete, account_types write/delete, sessions delete, tenant_types write/delete, tenant_statuses write/delete, tenants write). Add iam to the registry and seed what it reports. | |||||
| Externally sourced holidays are not gated by authorisation | refdata calendars governance |
The administration model expects a holiday from an untrusted source to wait for authorisation; nothing models a pending holiday or a trusted source. | ||||
| Fail the CMake file-list check when a component has no unit to check | codegen cmake testing tech_debt |
regenerate_cmake_component_files.py –component ores.analytics –check exits 0 having inspected no file: ores.analytics is a modeled component with a component_overview.org but no src/ or tests/, so regenerate_one skips both units and the run prints 'All component_files.cmake up to date.' The guard that rejects an unknown slug does not cover a known component with zero CMake units, so a group name reads as evidence when it is a false green. | ||||
| Filter a convention list by its terms | conventions search refdata |
The generated list filter of every convention kind takes id_one_of and nothing else, so finding the document that states a set of terms means reading every page. A kind such as swap holds 320 documents that state 201 term sets. Decide whether each kind gets a generated filter on its term columns, and how the list reports the count of distinct term sets. Found while writing the journey Find a convention by its terms. | ||||
| Find every type that still crosses NATS through the reflect-… | Find every type that still crosses NATS through the reflect-cpp primary template of wire_traits, and give each a generated codec or wire fields before Remove reflect-cpp deletes the fallback. The component codec moves checked their sources for reflect-cpp includes and calls, but a hand-written protocol header with no wire_fields still travels through default_wire_codec on the fallback without naming reflect-cpp anywhere. Known so far: ores.synthetic.api/messaging/market_regime_protocol.hpp (get_market_regime_request and response, market trace, market history, pin_market_regime, configure_market), which the shell's synthetic commands call. A quick way to list them all: temporarily make the primary template static_assert, build, and read the failures; each is a type to give wire_fields and shaped_wire_traits, or to move into a model. | |||||
| Find why the CSA and conventions publishes failed now and then | sql refdata dq test flaky |
The CSA publish and the conventions publish failed now and then in a full SQL run. Splitting the CSA publish into two statements and letting the conventions parts skip a row that exists stopped the failures, but nobody proved the cause. | ||||
| Finish the authorisation queue's specification | web operations queue trading specification |
The queue screen states the deal, its book, its counterparty and the version it is at, and it decides a request. The rest of the signed-off prototype needs data the read does not carry: the expiry a deal is pinned by, the operational error flag that separates a wrongly booked deal from one that moved, the fields an amendment changed and their previous values, the legs of a package, and the person and time the row last moved. | ||||
| Finish the eventing payload migration, or read the legacy shape | eventing codegen sql tech_debt |
postgres_event_source parses every database notification with rfl::json::read<entity_event_notification>, whose struct requires event_id, entity, key, action, version, occurred_at and tenant_id, and returns on a parse failure. 86 of the 209 *_notify_trigger_create.sql files emit that canonical shape and 123 still emit the older {entity, timestamp, entity_ids, tenant_id}. Every notification from the 123 fails to parse, so those entities publish no entity_change_event at all. Observed as 322 parse failures in the trading service log and as twenty-one failed eventing assertions in ores.trading.core.tests. | ||||
| Finish wiring draft_reason on main | trading codegen |
Main carries draft_reason with its permissions unseeded, two drop scripts no aggregator includes, its shell scripts and recipe inventory untangled, and a shell unit the aggregator test does not expect; six local checks fail on it. | ||||
| Five test binaries fail on main, and four of them share one … | Five test binaries fail on main, and four of them share one cause: a generated insert function now raises 'Row already exists: a create cannot replace it' where the test expects a plain insert to succeed. Seen in ores.refdata.core.tests (ores_refdata_books_insert_fn line 91, ores_refdata_party_identifiers_insert_fn line 80, ores_refdata_portfolios_insert_fn line 111) and ores.marketdata.core.tests (ores_marketdata_market_series_insert_fn line 32, ores_marketdata_series_classification_rules_insert_fn line 34). Two eventing tests fail in the same suites because no event is published when the insert raises (counterparty_contact_information_eventing_integration_tests.cpp:178, counterparty_eventing_integration_tests.cpp:164). The fifth, ores.dq.core.tests, fails for separate reasons: ores_dq_lei_entities_tbl and ores_dq_lei_relationships_tbl are named by the code and created by no script, the change_reason_category validator rejects the code data_correction, and six generator tests assert version == 1 and get 0. Also failing: ores.dq.api.tests, on two table-rendering assertions in domain_coding_scheme_tests.cpp, and ores.shell.api.tests, on to_iso8601_utc emitting a space instead of T, which is already captured separately. Observed on 2026-09-27 with ctest –preset linux-clang-debug-make: 81 of 86 pass. None of the failing binaries belongs to a component the reporting branch touches. | |||||
| Fix compass pr create/merge task misattribution on shared branches | compass tooling bug agile |
compass pr create/pr merge pick the wrong task doc when multiple tasks share the same #+branch value, silently editing an unrelated task or blocking merge on its state. | ||||
| Fix the flaky conventions publish pgTAP test | sql pgtap flaky |
refdata_conventions_publish_test.sql fails in about 1 run of 8 on main: the repeat publish inserts a convention row at version 1 that already exists, so a live row was closed or not seen between the two publishes. | ||||
| Fix the shell recipe sentinel for optional columns | codegen shell recipe tech_debt |
sentinel_value in org_loader.py falls back to _none for a cpp_type it does not know, and std::optional<…> has no entry. The shell's absent-value token is '-' (ores.shell.api command_token.hpp absent_token), so a generated recipe script for an optional uuid aborts with 'Invalid value for <field>: none' before it reaches the service. Observed on three of the 40 generated analytics scripts during the ores.analytics clean pass: pricing_model_product_parameters add, set and put-many. iam carries seven optional uuid columns, so the fix changes iam's committed recipes and script library too and belongs on a codegen story, with a regression test. | ||||
| Four iam shell commands have no recipe after the stale documents were deleted | iam shell docs recipe |
Deleting seventeen stale hand-written recipe documents left accounts info, accounts history, accounts logout and tenants history with no recipe at all, because each was documented only by one of the deleted pages. Their commands work; what is missing is a recipe written against current fixtures. | ||||
| Four marketdata core tests fail on main against a fresh database | testing marketdata main |
On origin/main 36a94808aa, with a fresh database and the services up, ores.marketdata.core.tests fails four cases: export_with_a_date_keeps_the_history_and_writes_the_value_at_the_close_of_that_day (3 series where 1 is expected), the_reads_for_every_series_give_what_the_reads_for_each_series_give (5 where 3), and the two provider terms acceptance cases (the accept reply is not success). A second run on the same database adds five projection and backfill failures on an RLS refusal for market_series_identity, so the suite leaves rows behind that its next run reads. | ||||
| Four pgTAP files fail before their first test | Under the test DDL role, refdata_counterparty_test, refdata_currencies_test and refdata_party_test die on fixtures the schema no longer accepts (a missing business_centre, a dropped asset_class column, a missing party_category), and synthetic_market_data_generation_config_scope_test hard-codes another worktree's DDL user as modified_by. The other 16 files pass. | |||||
| FX forwards for cross pairs | The FX forward read answers USD pairs only, so a cross such as EUR/GBP is refused until spot is triangulated. | |||||
| FX forwards have no end-of-day record | A forward computed on read has no end-of-day record of its own, so a verified set of forwards would need storing. | |||||
| Generate a repository test for every entity, and retire the hand-written ones | codegen tests |
Codegen has no repository-test archetype, so 90 hand-written CRUD test files cover some entities across 12 components and most entities have none. | ||||
| Generate equality that ignores the columns the store stamps | codegen domain equality tests |
The generated operator== is defaulted over every member, so a record read back from the store never equals the one that was written; the audit columns, the version, and for system-owned rows the tenant id are all rewritten on write. Capture the decision and the C++ options. | ||||
| Generate the empty instrument batch from the protocol | A booking failed for everyone on main because the BFF's empty instrument batch is hand-written and main added two families to the batch. The wire refuses a request that omits a declared member, so every family must be named twice: once where it is declared and once in a list nobody regenerates. | |||||
| Generate the HTTP and CLI layers of the ORE file entities | codegen reporting gap |
ore_file, ore_file_category and ore_file_version were generated through every layer the codegen has a profile for; the HTTP endpoints and the CLI commands have none, so the entities have no HTTP or CLI surface. The entity skill marks both as codegen gaps to close with a profile, not by hand. | ||||
| Generated eventing tests leave their seeded parents behind | iam tests hygiene isolation |
Forty-eight generated *_eventing_integration_tests.cpp seed a parent row to satisfy the child's soft FK and never remove it. The row is system-tenant reference data, so the helper's per-tenant isolation does not reach it and it stays active forever. It no longer breaks the suite now that a seed profile's code is unique per deployment, but the tests still grow a global catalogue row per run. | ||||
| Generated HTTP recipes send no request body | http codegen recipe defect testing |
Every write endpoint answers 400 where its recipe asserts 200: the ores.doc.http-recipe template emits no body, so 57 of the 82 generated recipes never reach the handler they exist to check. | ||||
| Generated list-by commands carry two template nits | Every generated entity's repository and service .cpp has two consecutive blank lines after the list-by methods, and every generated by-column shell command's usage text omits –scope, which its parser accepts and its service then rejects for subtree. Both come from the codegen templates and appear identically in every entity with a list-by foreign key. | |||||
| Generated recipes are stale, and nothing watched them | codegen drift recipe |
Sixty generated recipes disagree with the models that produce them, in two different ways, and no gate could see either because the drift check rendered per technical space and never produced a recipe at all. A further 76 files sit at the generated recipe path shape with no model behind them. | ||||
| Give a table-less record a way to suppress the audit envelope | codegen variability profile |
The table-less-record profile cannot reach :no_audit_columns:, and no flag suppresses the audit recorded_at member, so a generated table-less record still carries a timestamp it has no use for. Partly resolved: no_audit_columns is now a sql-namespace feature the profile states, which closed the blocker; the second half of the proposal was rejected. | ||||
| Give csa_eligible_currencies a party policy | ores_refdata_csa_eligible_currencies_tbl has no party_id and no party policy, so a direct listing is not filtered by party even though its CSAs are. Derive the party from the CSA or add a policy by join to the CSA. | |||||
| Give each person a history tab, with revert | web iam people history |
The person page has no history. Add a History tab with one section per record, as the currency pair page does: identity (account) and contact history with the GitHub-style diff and revert through the iam saves, and an Audit section of role grants and removals once the server keeps grant history, which it does not today. | ||||
| Give every generated handler registrar a responder | codegen messaging tooling |
54 generated handler registrars in seven components have subjects no service answers; decide for each whether to call it or retire it, then add the component to the handler-registrars gate. | ||||
| Give members self reads for their sessions and picture | security iam web shell |
A member's own sessions and picture are read through privileged reads, iam.v1.sessions.active and iam.v1.accounts.get, so both answer 403 to a member; each needs a self read on the allow-list, and the shell should report a refusal rather than a decode failure. | ||||
| Give report_trigger_event the audit stamps its sibling generators set | reporting codegen snag |
report_trigger_event_generator.cpp sets only tenant_id, id, report_definition_id, trigger_type, triggered_by and party_id. Each of the other twenty reporting generators sets change_reason_code = system.test, and most also set modified_by, performed_by and recorded_at. Its table has no audit columns at all, so the asymmetry is either deliberate and undocumented or an omission. It invited a wrong fix: an uncommitted edit added report_trigger_event_parent.change_reason_code to report_error_eventing_integration_tests.cpp, which cannot compile because the domain struct has no such member. Decide whether the entity carries audit stamps, then fix the generator or record why it does not. | ||||
| Give service accounts a name and an icon | iam services ux icons |
Each service account carries a human readable name, such as Analytics Service, and a service-specific icon from the project's icon sets, for the service status screens; the super administrator and tenant administrator icons are revisited to match. | ||||
| Give tenant administration its own landing | web ux journeys shell |
A tenant administrator lands on the generic Signed in card, because the shell declares areas only for system administration. Give tenant administration its own areas and journeys, starting with Parties and New party, so the person lands on cards the way the system administrator does. | ||||
| Grant the trade summary read to a seeded role | iam trading trade_summaries seeding web |
The Trades area is offered to a person who holds a trade summary read, and no seeded role holds one: ReportRun holds trading::trades:read, refdata::books:read and refdata::counterparties:read but not trading::trade_summaries:read, so the only role offered the area is refused by /api/trades. Grant it to the role that already reads trades, or decide which role a blotter belongs to. | ||||
| Have a French and Portuguese speaker read the text that the … | Have a French and Portuguese speaker read the text that the oresmd link story added to ores.web: the Evolution page notices, the series page, the Inspect dialog, the Series label, and the tooltip on the feed's oresmd URI. A model wrote it and no speaker has read it. | |||||
| Holiday rules and business days carry no holiday name | refdata calendars modeling |
A calendar rule has no name column and a materialised date carries none, so no screen can say Good Friday. | ||||
| House-wide error handling convention: std::expected vs exceptions | codegen modernisation cpp error-handling |
Decide and document one error-signalling convention across components; synthetic's audit flagged ~60 throw sites with no house standard. | ||||
| iam.v1.accounts.list rejects a well-formed request from a valid session | A logged-in session with a party cannot list accounts. The server answers iam.v1.accounts.list with bad_request, which aborts verify-login.ts before its last three checks run. | |||||
| Implement the processes that act on sets of trades | trading process trade_set trade_activity |
Seed the process enumeration the reference table is waiting for, then implement the processes one at a time, piloting a single one and adding the rest only once its shape is settled. | ||||
| Inject an exogenous tick burst | marketdata synthetic arrival regime |
A system verb that makes the market receive a burst of ticks from outside at once: either real ticks the feeds publish, which raise the heat and excite every Hawkes feed, or the heat alone, as a shock. Recorded in the trace, so a tester can watch a panic spread and fade without waiting for the chain or pinning the state. | ||||
| Inventory system-scoped entities and rationalise tenant scoping strategy | Currently system-scoped reference data is handled inconsistently: some entities copy data per tenant during provisioning, others rely on a system-tenant context switch. We need an architectural audit. | |||||
| Investigate backdated market data for specific use cases | With vintage removed from the generators, find which use cases need market data as of a past date, and how to serve them. | |||||
| Is a steady_timer spawned from on_started the right design for periodic work? | architecture scheduler variability |
Compute keeps two recurring behaviours and both hardcode their timing, one as a boost::asio steady_timer loop spawned from the runner's on_started callback and one as a seeded scheduler job. Neither can be tuned for a given system, and the timer's fate is tied to a lifecycle hook. | ||||
| job_instance_summary.job_name carries the definition id when the definition is gone | scheduler operations shell bug |
The scheduler's instance-list operation joins each execution to its job definition to fold in the job's name and action type. When the definition row has been deleted the join finds nothing, and the summary's job_name carries the definition's identifier instead, so a field documented as a name is sometimes a key. Seen from the shell: after scheduler remove, scheduler instances prints the identifier for every execution of the removed job. | ||||
| Junction staging keyed by name for report configurations | The junction artefact template stages a code for the right side; report_configurations binds by name and was staged by hand. | |||||
| Legacy template docs sit outside the ores.* physical-space graph | Eleven archetype-named template-library pages (doc_facet_org, doc_facet_group_org, doc_technical_space_org, doc_archetype_org, doc_profile_org, doc_feature_org, and five sql_* files) are typed knowledge, carry no facet keyword, and are named for the template they hold rather than by MASD address. The inventory generator globs ores-star-dot-org only, so it cannot see them, and their facets (ores.doc.template and the ores.sql facets) report zero archetypes. Migrate each to the ores DOT facet DOT archetype filename shape with the archetype type and the facet keyword, preserving its ID and its tangle block, so the catalogue lists them. | |||||
| Let one builder per request carry every field | The ORE import handler builds 26 put_*_request messages and several copy fewer fields than their write struct declares. The strike one cost a PR: a CapFloor and an index option strike went out with an empty role and an indeterminate ordinal, so neither product could be imported, and every test passed because none of them crosses the handler. A census over the handler and the generated *_write structs names the rest. | |||||
| Let one feed's ticks excite another's | marketdata synthetic arrival hawkes |
A multivariate Hawkes over the feeds, with a kernel matrix that says how much a tick in one feed raises another's intensity, so a burst in EUR/USD lifts GBP/USD more than it lifts SOFR. Today every feed shares one heat, a rank-one kernel. | ||||
| Let ores::utility::codec::json::write, read and try_read (an… | Let ores::utility::codec::json::write, read and try_read (and the msgpack pair) call a type's generated wire_traits when it has one. Today they instantiate the struct encoder in the caller's unit, which needs the wire_fields of every nested type, so a handler that writes a message holding another component's types fails to compile unless it includes their codec headers. It has happened twice in the reflect-cpp move: ore's package handler reading trading's export_portfolio_response, and iam's account party and account handlers writing their responses. Each was worked around by calling wire_traits of T::write_json directly. The fix must split the codec into a direct core and a dispatching front, because the generated definitions call object::read_json, which calls json::read, so a dispatch in json::read alone would recurse. Detect a generated codec through the forward declaration (a requires on wire_traits of T::is_generated) so json_codec.hpp does not pull in reflect-cpp, and add a test that a message with nested generated types writes through json::write in a unit that includes only its protocol header. | |||||
| Let the generators state both directions | The synthetic generators write one value for a closed either-or: the forward rate agreement generator always writes Long, so no fixture or dataset ever holds a Short FRA. That is how a mapper that ignored the direction survived review: every witness in the tree agreed with the constant. | |||||
| Let the heat turn the regime | marketdata synthetic arrival regime |
Make the chain's transition rates depend on the heat, so a market that runs hot is likelier to turn active and stay there. Today the chain is exogenous: it turns on its own, and the heat only adds to the pace. | ||||
| Let the oresmd URI name quotes that ORE cannot name | marketdata oresmd codec |
oresmd_uri_codec refuses a quote no ORE key can name, such as a hazard rate, so the ingest loop drops its tick; decide which quote types the URI may name beyond ORE and relax the codec and its callers. | ||||
| Limit concurrent running fleets via fleet slots | compass memory host |
Bound concurrent fleets to a fixed slot count so service fleets cannot exhaust host memory. | ||||
| Link each day counter spelling to its day count fraction | refdata conventions ore |
A day counter row is one of about seventy spellings ORE accepts and carries no description, because which canonical day count fraction it means is not recorded. | ||||
| Locking an account reports success when it changed nothing | iam security |
As SuperAdmin, POST api/accounts:id/lock on an Acme account answers success true, but row-level security keeps the system session out of Acme's rows, so the account stays unlocked. The iam lock and unlock report success without checking that a row changed. Found by the role walk in Give a person's token the permissions they hold. | ||||
| Main lost the batch members a consumer uses | b3a78b33ba regenerated instrument_batch.hpp and removed the bond_issue members 637f5527e2 had hand-added to it. ores.synthetic reads slot.instruments.bond_issues, and no model declares it, so main no longer compiles. The drift gate saw the hand edit and rewrote files in place; the break is in the committed tree. | |||||
| Make activity and volatility excite each other | marketdata synthetic volatility hawkes |
A bivariate Hawkes: activity excites volatility and volatility excites activity, with today's shared heat as one coordinate. The rank-one kernel becomes a 2x2 block and stability stops being max n + sum m < 1 and becomes a spectral radius. It depends on the volatility channel landing first. | ||||
| Make compass shell report a script abort in its exit status | shell compass testing tech_debt |
compass shell -l exits 0 even when the loaded script aborts at its first bad command, because run_host_sync returns EXIT_SUCCESS and the shell's own failure flag never reaches it. Observed during the ores.analytics clean pass: pricing_model_product_parameters put-many aborts with 'Invalid value for pricing_model_product_id: none' and the process still exits 0, so the 40-script V04 sweep had to be read by eye and no CI job can gate on the library. | ||||
| Make compass site page recover from a truncated publish cache | compass site tooling dx |
Make compass site page recover from a truncated publish cache. A 0-byte build/output/org-timestamps/site:pages.cache plus a stale Emacs lock (.#site:pages.cache) left by a dead PID makes every site page run fail with 'org-publish-cache-get called, but no cache present'. The cache is derived data and rebuilds in one run, but nothing says so: the command reports a cryptic org-internals error and no recovery. Delete the stale lock and the truncated cache before publishing, or make the command detect the state and say what to do. The how_do_i_deploy_the_site recipe documents neither the failure nor the recovery. | ||||
| Make ISO 8601 timestamp conversion fast | datetime::to_iso8601_utc and from_iso8601_utc take 760-960 ns a call and are 80-90 percent of the cost of encoding or decoding a message with timestamps; a fixed-format writer and reader would take tens of nanoseconds. | |||||
| Make sunday_to_monday survive regeneration of the refdata calendar rule | refdata codegen snag |
Commit a1d358e5da added sunday_to_monday to projects/ores.refdata/api/include/ores.refdata.api/domain/calendar_rule.hpp, which is marked AUTO-GENERATED, and never updated the model it comes from: projects/ores.refdata/modeling/ores.refdata.calendar_rule.org line 189 still lists only none, nearest_weekday and roll_forward_to_monday, and the valid-values column at line 316 agrees with three. Any codegen run drops the fourth value from the generated header; this happened and had to be reverted by hand. The functional fix in the materialiser and its test is hand-written and survives. Fix the model, not the generated file. | ||||
| Make the build's systemd probe test what the build actually runs | compass build sandbox tech_debt |
compass build wraps cmake in 'systemd-run –user –scope' whenever compass_claude._has_user_systemd() passes, but the probe only runs 'systemctl –user show-environment'. In a sandbox where systemctl reaches the manager and systemd-run cannot open the scope bus, the probe passes and the build dies with 'Failed to connect to user scope bus via local transport'. The probe should exercise the thing the build depends on, or the scope wrap should honour the ORES_USE_BUSCTL transport that the rest of compass adopted. | ||||
| marketdata persistence intermittently failed 2026-08-12 03:0… | marketdata persistence intermittently failed 2026-08-12 03:05:30-08:35:48 with 'Failed to persist observation' after 'No available connections in the pool': with the default pool size of 2 (database_options.hpp), one connection stuck in COMMIT (wait_event IO) from service boot at 03:01:50 for ~5.7h left one effective connection, and concurrent ingest handlers (5 ticks/s) drained it between acquires. Persistence recovered once the stuck connection resolved (~08:54); ~10,500 observations/party persisted afterward. Environmental/pre-existing fragility, not an F15 defect; consider surfacing the acquire timeout and/or raising pool size. ~479 idle Postgres connections also accumulated over 5 days (pre-existing leak, out of scope). | |||||
| Materialise the trade summary row for very large lists | trade-blotter |
The trade summary view builds every row for every page, about 37 microseconds a trade. Store the row when a tenant outgrows the view. | ||||
| Model cash flows, and decide what represents an amount of cash | trading cash cash_flow modeling |
Four knowledge pages describe cash and none of it is modelled: cash, cash_flow, cashposition and linked_cash. Decide whether a cash flow is an entity of its own, whether cash is represented by a trade (ORE prices a CashPosition), or both, and how summary cash and orphan cash are held. Needs analysis before anything is built. | ||||
| Model the two trading export verbs as operation models | codegen trading |
trading.v1.trades.portfolio.export and export-to-storage are declared in a pasted cpp block in the trade model with hand-written handlers; P04 and M06 want operation models. | ||||
| Model the workflow payloads instead of storing them as documents | workflow architecture data-modelling |
The workflow schema holds six jsonb columns that carry serialised messages: request_json and result_json on the instance, and request_json, response_json, command_json, compensation_json and step_log_json on the step. Some of them are already typed on the wire and flattened into a document only for storage: step_log_json is a std::vector<step_log_entry>, whose shape the model already declares. Others are genuinely opaque to the engine and are relayed into the next step's builder, which parses them. Work out which of the six are models that were flattened and should be relations, which are payloads the engine must not interpret and should stay opaque, and what the engine actually needs to be able to name. The end state is that nothing in the schema holds a relation disguised as a document. | ||||
| MSVC fails C1202 on the bond export carrier | ci windows msvc trading |
The Windows MSVC build stops with C1202 in instrument_payload.cpp, because reflect-cpp tags the trade_instrument variant over every field name reachable from bond_instrument_data; no sprint-26 story owns it. | ||||
| N-way domain groups have no model left | The wide trade was the only entity that composed its struct from N field groups (identity, parties, classification, lifecycle, audit). With it deleted, the codegen's N-way domain group path, the group member prefixes it feeds the eventing seed plan and the grouped audit stamping run for no model; only probe refusal tests remain. Instruments use the separate identity and audit group slots. Decide whether to remove the N-way path or keep it with probe tests that load a complete grouped entity. | |||||
| Name a set of unrelated refdata kinds that a screen or export groups | architecture data_classification conventions bff |
The data classification page has no name for a set of kinds that a screen, an export or a boundary lists together with no invariant between them. The BFF convention screen is one case: it shows the document families, a composite family and two kinds the conventions document does not carry (tenor and currency pair). The page says a set that needs a screen to be true is not a bundle, and it says a list of several kinds is not a list. It also closes the set of classifications. Decide whether the page needs a new classification for such a set, or whether each case stays several lists with a small hand-written catalogue that the code states as a presentation choice. Then record the decision on the classification page. Found while the BFF family list task moved to the generated registry. | ||||
| Name GBP LIBOR 3M in one swap convention | trading refdata provisioning |
Acme provisioning fails at generate_trades: the Swap builder refuses GBP LIBOR 3M because both GBP-3M-SWAP and GBP-3M-SWAP-CONVENTIONS name it. | ||||
| Name the event-filled cache in the pattern language | patterns data caching |
Entity-mirror caches are filled by reading the owner back on its change events, which the Cache-Aside page calls a different technique. The pattern language names no pattern for it. Find the established name, such as Event Notification with a read back, or Event-Carried State Transfer if events come to carry the rows, and write its page in the data or communication group, linking the entity-mirror cache page as its use. | ||||
| Narrow the inbox raise to one security-definer function | refdata trading sprint_28 |
Gated services write five inbox tables to raise a request. Give them EXECUTE on one inbox function instead, so the inbox owns the write rules and the grant surface shrinks. The call still runs in the caller's transaction, so the request and the held change still commit together. Refdata and trading both use the wide grants today (service_registry.org). Found while checking whether the trading raise crosses an owner. | ||||
| NATS tests share the running services' subject prefix | testing nats tech-debt |
ores.testing's make_nats_options gives every test the environment's ORES_NATS_SUBJECT_PREFIX, so a running service takes or answers a test's messages; three market data and synthetic tests fail whenever the services run. | ||||
| No CI job runs the physical-space inventory check | codegen drift inventory |
regenerate_physical_space_inventories.py –check reports a stale facet inventory on main, and nothing on the pull-request path runs it. | ||||
| No CI job runs validate_docs.sh, and main is red | codegen docs drift |
validate_docs.sh fails on main with two violations for ores.shell.workflow, and nothing on the pull-request path runs it. | ||||
| No role below the tenant administrator can maintain reference data | iam refdata permissions |
Only TenantAdmin can run the reference data journeys end to end; Operations writes currency records but cannot read the lists its pickers need. | ||||
| No service subscribes to refdata.v1.ops.begin_bundle_import,… | No service subscribes to refdata.v1.ops.begin_bundle_import, stage_bundle_family or commit_bundle_import. bundle_import_operations_service exists in ores.refdata.core, but no messaging handler registers it, and git history shows it was never wired, as conventions_import_operations_service either. The ore service's run configuration import calls these subjects for the run's conventions file, so 'ore import-run' on any directory with a conventions file fails with 'conventions.xml: Exception calling refdata.v1.ops.begin_bundle_import: NATS request timed out'. Observed live on 2026-11-02 against a recreated database with Acme provisioned. The import-run recipe was last tested on 2026-10-05, before the bundle import existed. | |||||
| No test shows that a tenant creates a service account only w… | No test shows that a tenant creates a service account only with rights it already holds, though a service account of a tenant reads every person of that tenant through the party rule. Write the C++ test for the account save and the role grant paths, and fix a gap if one shows. | |||||
| Nobody can list the batches, workunits and results | compute web ux journeys |
The grid screen shows counts of batches, workunits and results and no row of any of them. The journeys Browse the grid's jobs and Follow a job are written and prototyped. No BFF route and no web screen serves them, so neither a tenant administrator nor the operator can list or open a job. | ||||
| Nothing ends a session, so every session is an open one | ores_iam_sessions_tbl carries end_time text not null default '', and an empty end_time is what makes a session active. Nothing ever writes it: after signing out through POST /api/session and DELETE /api/session the row still has an empty end time, and a live read of the fleet's sessions found 17 rows and not one with an end time. The consequences for the credentials work are that iam.v1.sessions.active answers every session the deployment has ever created rather than the open ones, the audit screen cannot show a session that has ended or a sign-out at all, and iam.v1.sessions.end - the operation the audit and rescue screens both want, to end another account's session - has no counterpart writer behind it either. Found while implementing the active sessions read (PR #2468). | |||||
| Nothing enforces that a QuantLib calendar is read only | refdata calendars sql |
The calendar model says the insert trigger pairs source and is_editable, but no trigger checks it, and rules and exceptions can be written to a calendar that is not editable. | ||||
| Nothing gates a hand-written operation handler | security auth codegen permissions defect |
check_handler_permissions.py compares only the four components in its registry, and only their generated messaging handlers. An operation model generates no handler, so its handler is hand-written and can ship with no permission check at all: ores.scheduler's operation handlers call has_permission zero times. The HTTP server has no route-level permission hook either, and only iam_routes checks codes. | ||||
| On login geolocation the country lookup fails with a genuine… | On login geolocation the country lookup fails with a genuine grant or row-level-security defect, and the failure is logged and then discarded. Observed 2026-10-14 10:59:12 in the iam service journal under component ores.geo.service.geolocation_service: ERROR: permission denied for table ores_geo_ip2country_tbl. The error is raised inside PL/pgSQL function ores_geo_ip2country_lookup_fn(uuid,inet) at line 15 of its RETURN QUERY, which selects c.country_code from ores_geo_ip2country_tbl c where c.tenant_id = p_tenant_id and c.ip_range @> ip_as_bigint limit 1. The login succeeds and continues, so the caller silently loses the country; the surrounding workflow never learns that anything failed, and the workflow step that was running at the time did not use the geolocation at all, so this is an independent defect rather than the cause of that step's silence. It is either a missing grant on the table or a policy that was never applied to this database. | |||||
| One source for reference data that the system and each tenant read | dq reference_data tenancy |
Reference data such as the ore parameters and currencies sits in both system_core and base because some readers check the system tenant and others check the tenant. Choose one source and make every reader use it. | ||||
| One spelling for an asset class code | The conventions screen groups by interest-rates; both the refdata and the badge catalogues store interest_rates. A hyphen and an underscore are two codes where there should be one. Find every place that derives a class code from a display name or a slug and make it read the catalogue. | |||||
| open-as refuses to open when SingletonLock names a pid from a dead namespace | compass tooling defect |
profile_in_use() treats any live process with the pid Chrome recorded in SingletonLock as a live holder. A Chrome launched inside a PID namespace records a namespace-local pid, so once that namespace is gone the lock can name an unrelated host process and open-as reports 'already open' forever, with –fresh silently not applied. | ||||
| ores.ore reads reporting's tables, which inverts the layering | ores.ore.core links ores.reporting.core and includes ores.reporting.api headers: run_store.cpp opens report_definition_repository, file_type_repository and run_document_service, and run_document_projection.hpp includes risk_report_config and configuration_market_binding. The pure ORE library therefore depends on the reporting component, so reporting cannot use ore's types without a cycle, and the engine's own document is built from another component's entities. | |||||
| ores.refdata has three hand-written source files with no test | refdata testing coverage tech-debt |
V08 of the refdata clean-standard pass surveyed the 17 hand-written files under src/. Ten are named by no test; seven are wiring or thin adapters whose behaviour is the service they drive or the live subscriptions the fleet runs. Three carry logic and have nothing: core/src/repository/asset_class_repository.cpp (the joined asset-class read), core/src/service/asset_class_service.cpp, and core/src/service/calendar_adjustment_export_service.cpp. Each needs a test that asserts a literal expected value, in the shape the generated repository and service tests already use against the live database. | ||||
| ores.scheduler.api.tests fails on main since the vcpkg updat… | ores.scheduler.api.tests fails on main since the vcpkg update of 2026-10-05 (978e1e098d): cron_expression::from_string accepts the six-field '* * * * * *', which the test expects it to refuse. from_string prepends a seconds field before calling croncpp, so a six-field input reaches croncpp as seven fields, and the newer croncpp evidently accepts seven. The fix is to require exactly five fields before the prepend. | |||||
| ores.shell folder feeds: start/stop folder must cover IR cur… | ores.shell folder feeds: start/stop folder must cover IR curve configs too. synthetic start folder <token> only starts fx_spot_generation_config rows (marketdata.v1.market_feed_configs.start_folder, per market_feed_config_protocol.hpp); ir_curve_generation_configs under the same folder are ignored, and ores.shell has no IR curve feed commands at all (the synthetic.service ir_curve_feed_configs.start/stop/list handlers are only reachable via raw NATS, config_id-keyed). Design intent: the top-level folder contains both FX and IR; folder-scoped start/stop should enumerate both config kinds. Extend the folder protocol (or add a synthetic.v1 ir_curve folder variant) and add shell verbs mirroring the FX ones. | |||||
| ores.trading.core.digest.tests fails: 4 of its 5 test cases,… | ores.trading.core.digest.tests fails: 4 of its 5 test cases, 48 of 177 assertions, in projects/ores.trading/core/digest_tests/trade_economic_digest_write_tests.cpp. The assertions read '!(after.front().economic_digest.empty())' and 'after.front().economic_digest != before.front().economic_digest', so the digest comes back empty for most families – FxOption, FxVarianceSwap, Swap, ScriptedTrade among them. It is the only suite of 93 that fails: 99% tests passed. The branch that found it changes no digest file and no SQL: its only trading changes are the presence files and a component brief, and the test file was last changed on main on 2026-10-11 by 7998cd1956 [trading] Observe the rate header and test the digest for every family. | |||||
| ores.web pages hard-code English instead of using translations | web i18n |
No page under projects/ores.web/packages/web/src/pages calls useTranslation. SignInPage hard-codes Username, Password, Sign in and Choose a party, although en, fr and pt already define a full signIn catalogue that nothing uses. Wire every page to its existing keys and add the missing ones. | ||||
| ores.web test files escape the typecheck | web typescript gates testing |
projects/ores.web/packages/web/tsconfig.json excludes src/**/*.test.ts, so no test file in the package is typechecked. A blatant type error in a test passes npm run typecheck, and vitest transpiles without checking. | ||||
| ores_workflow_workflow_steps_tbl.idempotency_key is not null… | ores_workflow_workflow_steps_tbl.idempotency_key is not null default empty, has no unique index, and nothing reads it for a decision; the engine sets it to the step's own UUID and only display code and the shell read it. The name promises the guarantee the claim change is adding, so either give it one or rename it. Found while grounding the atomic step claim. | |||||
| Page the authorisation queue and count it on the server | web operations queue paging |
The queue screen reads a window of 250 requests because it filters and counts the rows it holds, and the inbox has no read that pages the queue while stating how many rows each state and class holds. Paging it needs those counts from the server; until then the screen says when its window is shorter than the queue. | ||||
| Paginate the compute list requests | compute shell |
Compute list requests cap at 1000 rows and never check total_available_count; paginate so a large grid does not silently drop rows. | ||||
| Parallelise bundle publishing | A bundle's datasets are published one after another, and that is most of a bootstrap's wall clock. The chain can now say which datasets are independent. | |||||
| Party events did not reload IAM's party cache during provisioning | iam refdata caching eventing bug |
While ACME was provisioned, refdata created its parties, but IAM's party cache issued no token for ACME, so no created-party event reached the cache's subscription and nothing reloaded the partition. Sign-in still works because it loads a missing partition on demand. Check whether refdata publishes party events to the subjects the generated registrar subscribes to, and whether the start-up warm-up should retry until the producer answers instead of trying once. | ||||
| Party GUCs leak across pooled database connections in the service layer | ores_service ores_database rls party_isolation pool |
The service sets app.visible_party_ids/app.current_party_id/app.current_tenant_id per request on pooled connections; a request whose context carries no party does not clear the GUCs an earlier party-context request left, so read visibility under the party-isolation RLS policies depends on which pooled connection serves the request (same session saw 26 party-scoped rows, then 0, with identical credentials). | ||||
| Party provisioning returns no workflow instance ids | workflow provisioning defect |
workflow.v1.parties.provision declares workflow_instance_ids in its response and the handler never fills the vector, so a caller cannot follow the workflow it just started. | ||||
| Password recovery by emailed link does not exist end to end | Nobody can recover a forgotten password. There is no request subject and no completion subject (the candidates are iam.v1.accounts.request-password-reset and iam.v1.accounts.complete-password-reset), no table stores a recovery token or its expiry, no screen in ores.web asks for a reset, and no client has a screen that completes one. The product owner set this as the design for Rescue access while accepting its prototype: a tenant administrator sends the link, and the colleague sets a password only they know, so an administrator-typed reset becomes a collapsed fallback rather than the principal action. The journey document journey_rescue_access.org carries the corrected steps, operations table and gaps. The delivery and token machinery this needs is captured separately as the tree cannot send an email; this capture is the flow itself: who may request a reset, what the token guarantees (single use, expiry, invalidation on password change), how a completed reset interacts with the lock state and open sessions, and the two screens (member-requested and administrator-sent) that were left undrawn. | |||||
| Pause and resume the market | marketdata synthetic arrival regime |
Freeze the market's clock so every feed stops at once and resumes where it was, with tau, the heat and the chain's dwell held, so a person can stop a demonstration or inspect a moment without stopping and restarting feeds one by one. | ||||
| PlantUML conventions doc contradicts the diagram corpus | plantuml diagrams conventions |
The class diagram conventions document prescribes notes, legends, {field} prefixes, a struct keyword and test-suite namespaces that almost no diagram in the repository uses, so following it produces a diagram unlike every other one. | ||||
| PriorStates HFT trading system demo | reference trading research ui |
A public demo of a C++ low-latency trading system covering CME, BrokerTec and Tradeweb, with reference data and linear and ML model research; a reference point for ORE Studio's trading and research screens. | ||||
| Privileged access needs a recorded break-glass process | security iam ux modes approval |
The mode a session runs in is a property of the account it signed in with, so a super administrator and a tenant administrator are distinguishable only if the account is. Getting there needs roles that request elevation, an approval, and a time-boxed recorded grant with no overlapping windows. The reporting-line proposal needs the same approval primitive, so it should be built once. | ||||
| Process Joey O'Brien's ORE sensitivity analysis post | ore sensitivity research |
Joey O'Brien's worked example of ORE sensitivity analysis — zero-rate deltas converted to par-rate deltas via a Jacobian change of basis, verified by a manual market-quote bump — to be processed into the knowledge base. | ||||
| projects/ores.sql/test/trading_trade_envelope_names_test.sql… | projects/ores.sql/test/trading_trade_envelope_names_test.sql fails 5 of its 10 subtests, and it fails on main. Failures 1 to 4 and 7, all about a recorded identifier naming the counterparty and netting set: the results are (CP,NS), (CP), (CPTY_7,CPTY_B), (CPTY_A,) and (CPTY) where the test expects NULL or (CPTY). The pgtap gate check is the only local check that fails for this reason. The branch that found it changes no SQL file and does not touch the test, so the failure predates it: projects/ores.sql/create/trading/ last changed 2026-10-15 15:42, the test last changed 2026-10-11. | |||||
| Provisioning produces duplicate temporal account rows: the s… | Provisioning produces duplicate temporal account rows: the same id and version twice, observed after a full ACME tenant provisioning run. Login still resolves the active row, so it is invisible today, but a duplicated bitemporal row is the class of defect the versioning work exists to prevent, and it stays invisible until it is not. The suspicion is a publish and version race: the DQ publish and the account write path both stating a version for the same row. Reproduce it on a recreated database by provisioning a tenant, then inspect the account tables for rows sharing id and version. Found while atomising the tenor basis swap convention, in the same run that proved stream provisioning already worked. Needs its own story: it is a correctness defect in the publish and version path, not part of any current workstream. | |||||
| Purge the streams a test run creates | compute nats testing test_isolation |
The test environment now appends .tests to ORES_NATS_SUBJECT_PREFIX so suites cannot collide with a running fleet. nats purge reads the .env prefix, so the streams the suites create under the .tests namespace are never removed and accumulate on the developer machine. | ||||
| Put the test timeout listener in the test-main template | codegen tests hotfix |
The test timeout listener is registered in projects/ores.http/client/tests/main.cpp by hand; the test-main template states only the logging and database lifecycle listeners, so the drift check flags the file. A listener that kills a test after 60 seconds is a whole-suite policy, so it belongs in the template behind a per-component opt-in (a property such as :test_timeout_listener: true on the component model) rather than in one generated file. The hotfix that cleared main dropped the hand edit, so the http client suite has no per-test timeout today. | ||||
| Qt codegen: no way to show a friendly name instead of a raw UUID in list columns | codegen qt ux marketdata |
ores.cpp.qt's Columns (Qt model) codegen only supports plain UUID stringification for a uuid-typed column; there is no lookup/display-name mechanism analogous to combo_display_field on detail-dialog combos, so every UUID FK-ish column in a generated list window shows a raw truncated UUID. | ||||
| Quant's process factory takes a string process type | analytics architecture tech-debt |
process_factory::make_process takes process_type as a string and falls back to geometric for an unknown value; quant should take its own enum, with the mapping in the calling component. | ||||
| QuantLib's lunar holiday lists stop, so later years miss holidays | The holidays are generated from QuantLib, whose hard-coded lunar lists end, so China, Taiwan, Singapore and Turkey lose holidays in later years. | |||||
| Read a page of accounts with the roles each holds | iam web people |
The people list reads each person roles one account at a time, because the server has no read that joins accounts and their roles; a joined page read would draw the role column in one call. | ||||
| Read desk group members by group, and close them with their group | refdata currencies |
Memberships can be read by currency only, and closing a desk group leaves its membership rows open. | ||||
| Read the covering series once per start batch | synthetic calibration performance |
A feed with no fixing items reads every series on each start to derive its candidates; a demand start of many feeds repeats the full read once per feed. | ||||
| Read the cut's approval columns and the report instance's copy of the cut | reporting data-oriented-design modeling |
The re-inventory found two reporting types over twenty members. cut (26) carries requires_authorisation with approval_request_id, approved_by, approved_at, refused_at and refusal_comment beside it, a flag followed by its block, while cut_approval_detail is already a part. report_instance (21) carries cut_label, cut_kind_code and cut_timepoint beside cut_id, a copy of the cut it names. Readings from outside the component for the reporting owner to confirm or argue down. | ||||
| Read the portfolio tree's junctions from the server | trading portfolio books tree api web |
The trade list's portfolio tree draws portfolios, the books under them and the trades in each book. The UI must learn two junctions from the server: which books hang from which portfolios, and which trades are filed in which book. Investigate the read API for both once the prototype is signed off. | ||||
| Read the public government bond curves | marketdata ir curves |
The US Treasury par curve, the H.15 curve, the gilt curve and the ECB's EUR AAA spot curve could be read as pillared items, moved here from Read the public interest rate sources, which now reads overnight rates only. | ||||
| Reading a session that still has to choose a party answers 500 | web bff |
After a sign-in that needs a party, GET /api/session answers 500: the session view requires a party and the pending session has none, so the BFF's schema parse throws. It should answer the party-required state or 401. Found by the role walk in Give a person's token the permissions they hold. | ||||
| Rebuild business days when their inputs change, and read them by date range | refdata calendars |
Business days are regenerated only on request with no record of when, and they cannot be read for one year. | ||||
| Reconnect a service's connection pool after the database is recreated | database services resilience |
After compass db recreate, a running service's listener reconnects but its repository pool keeps the dead connections, so the next request fails with 'SSL connection has been closed unexpectedly'. | ||||
| Refdata junction inserts check neither end of the link | refdata sql data_quality |
The currency, pair-convention and party junction inserts check the tenant only, so a link row can name a currency, calendar, group or party that does not exist. | ||||
| Refdata junctions bind their profile where codegen cannot read it | Four refdata junction orgs carry '#+profile: tenant-scoped-junction' in front matter. load_org_junction_model reads frontmatter through a fixed allowlist (product, schema, component, name, name_singular, name_title, name_singular_words, brief, has_tenant_id) that excludes 'profile', so the binding is silently dropped and the junction resolves profile=None, has_tenant_id=None. Rendering sql_schema_junction_create.mustache for these four emits no tenant_id column, while the committed SQL under projects/ores.sql/create/refdata/ still has 'tenant_id uuid not null' plus its RLS policy and index. The committed output is therefore stale, and regenerating refdata would silently strip tenant scoping from currency_currency_groups, party_counterparties, party_countries and party_currencies. The canonical binding point is a '* Flags' section, per _ensure_profile_binding's docstring in org_loader.py:264-276; the five junctions that use it (compute, dq x2, iam, marketdata) all resolve tenant_id=True. Fix is to move the line, then regenerate refdata and confirm the SQL is unchanged. Found while fixing the same defect in the new marketdata market_series_asset_classes junction. | |||||
| refdata's generated wire projection is drifted and no gate covers it | refdata typescript codegen defect |
18 of the generated TypeScript protocol files disagree with the templates that produce them: the write shapes gain party_id, which the C++ header does not carry, and the junction event interfaces go. | ||||
| refdata_party_test inserts a party with no category | sql pgtap refdata bug |
The pgTAP test projects/ores.sql/test/refdata_party_test.sql inserts its first party without party_category, and the party validation trigger refuses an empty category, so the test aborts before its first assertion and plans 12 but runs 0. Give its inserts a category, or test the default where the trigger supplies one. | ||||
| Refresh the stale ER diagram from its generator | The committed projects/ores.sql/modeling/ores_schema.puml lags its own generator by 26 hunks; regenerate and review it on its own branch. | |||||
| Refuse a generated SQL identifier that PostgreSQL truncates into a collision | codegen sql check |
The generator builds index, trigger and policy names that exceed PostgreSQL's 63-byte limit in some forty places, and PostgreSQL truncates them silently; nothing fails when two truncate to the same name. | ||||
| Refuse an empty key list before delete-many renders IN () | codegen repository sql tech_debt shell |
A generated delete-many builds its SQL predicate with an empty IN list when the key it resolves matches no row, and Postgres rejects it with a syntax error at or near ')'. Found during the ores.analytics clean pass: the generated recipe passes the none sentinel and the service answers internal_error with 'Query execution failed'. The same command answers ok when a preceding add created the row, so the condition is 'no row matched', not the entity's key type. The repository should refuse an empty key list with a validation verdict, or treat it as a no-op, rather than emit a statement that cannot parse. | ||||
| Refuse to start services from a mixed build | service provisioning observability |
A partial build after a rebase left ores.marketdata.service linked against an older libores.analytics.quant, so it died with a symbol lookup error at its first curve request and failed provisioning. | ||||
| Regenerate or retire the domain round-trip dataset (resolved) | ore testing coverage |
assets/test_data/domain_roundtrip/ is the second derived artefact of external/ore/examples/ and it is badly out of step. A fresh v17 round-trip writes 566 files; the committed dataset holds 1474. Regenerating would delete 961 files: 946 are empty Portfolio stubs that an older build wrote for every XML it could not parse, and 15 are orphans for Products/SupportedTrades/, a directory upstream has since removed. It would add 53 outputs for examples the v17 sync introduced, including Products/Example_Trades/Credit_CallableBond.xml, and change 177 more, mostly conventions.xml and curveconfig.xml where the v17 schema moved. The dataset also duplicates assets/test_data/golden_dataset/, which the sprint_17 story said it had replaced; the retire task is marked DONE but golden_dataset is alive and named by 13 files. Decide which of the two is canonical before regenerating either. | ||||
| Regenerate the refdata and reporting files that drift from their models on main | refdata reporting codegen |
On main at f4cf29c82c, ten refdata and reporting files do not match their models: day_counter, three curve_volatility entity units, three eventing tests and three create scripts. | ||||
| Regenerate the stale ER diagram and gate it | projects/ores.sql/modeling/ores_schema.puml is a generated artifact (banner: GENERATED FILE - DO NOT EDIT, regenerate with ./projects/ores.codegen/plantuml_er_generate.sh) and it is a month stale. Its last commit was 6610f847fd on 2026-08-07. Regenerating it today produces 2069 changed lines and a 3 MB PNG growth, almost all of it unrelated drift: the trading bond wave, refdata catalog changes, and the marketdata classification work. No CI gate covers it, so nothing catches the drift. The market_series.is_scalar column and the market_observation.point_id nullability were deliberately left undocumented in the diagram by the point-model change set rather than dragging that month of drift into it. Work: regenerate the diagram once, wire the check into the drift gate so it cannot go stale again, and consider dropping the tracked PNG and cmapx in favour of build-only output. | |||||
| Regenerate the synthetic class diagrams without the ORE key | synthetic docs |
ores.synthetic.api.puml and ores.synthetic.core.puml still show ore_key on the FX feed after PR 3152 replaced it with oresmd_uri. Find the tool that draws them and run it. | ||||
| Regenerating every address for every component leaves five f… | Regenerating every address for every component leaves five files that main has not regenerated. doc/recipes/shell/trade_generation_configs/trade_generation_config.org and the two generated TypeScript twins under projects/ores.web/packages/wire-protocol/src/generated/synthetic are missing the trade_generation_config reference_curve_id field, and projects/ores.reporting/core/tests/report_error_eventing_integration_tests.cpp is missing the change_reason_code assignment its template now emits, as is projects/ores.workflow/api/include/ores.workflow.api/domain/workflow_instance.hpp. The models moved on main and compass codegen regenerate was not run afterwards, so check_component_drift reports them on any branch whose codegen tree changes. None is attributable to the branch that found them. | |||||
| Regenerating several components deletes behaviour, because m… | Regenerating several components deletes behaviour, because main's copy of a generated file carries hand-added content the model cannot reproduce. ores.geo: src/CMakeLists.txt was hand-migrated on 2026-07-30 (0a8ea6f7e3) to component_files.cmake and links ores.database.lib, while the flat template still emits file(GLOB_RECURSE) and a different link set; regenerating it left geolocation_service.hpp unable to find ores.database/domain/context.hpp. ores.history/api: src/CMakeLists.txt is a hand-written header-only INTERFACE library, and the generated form asks for sources the directory does not contain. ores.storage/service: config/options.hpp declares a std::string storage_dir and app/application.cpp includes the nats client, the domain service runner, the heartbeat publisher and the local store, all of which regeneration deletes. Each component needs its model to catch up before it can regenerate at all. | |||||
| Register a Riksbank API key | marketdata ir riksbank |
The Riksbank SWESTR API refused this host's calls for five days with 'Out of call volume quota'; a registered key raises the limit and the adapter needs a way to send it. | ||||
| Remove the unused HTTP gateway base URL | web http defect |
httpBaseUrl and discoverHttpBaseUrl() are declared and unused; the browser's only HTTP surface is the BFF, so they are removed rather than documented. | ||||
| Removing a refdata code is not refused while records use it | refdata sql data_quality |
A lookup delete closes the row without checking who refers to it; a record that still uses the code then fails its next save. | ||||
| Report the drafts and who is late | trading reporting drafts report |
A draft states why it is not live and which desk owns the reason. Nothing reports that: an aged draft is invisible, so the desk that should be chasing it cannot see how long it has sat or whose work it is. | ||||
| Represent permissions as bitsets | security iam performance authorisation |
Map each permission code to a bit, hold a caller's grants as one bitset per permission group, and check a permission with boolean logic instead of string comparison; measure first to see whether it is justified. | ||||
| Resolve the claims of a batch write in one read | codegen database performance |
The generated batch write reads each row's version in its own transaction before it inserts, so a batch of N rows costs N round trips; 27 repositories carry it. | ||||
| Restart services after rebuild before provisioning | devops provisioning environment |
Provisioning against services started before a rebuild fails with poll parse errors from stale binaries; restart services after the build. | ||||
| Restarting the synthetic producer stops the market data ingest | nats marketdata synthetic ingest reliability |
Stopping and restarting the synthetic service leaves the market data ingest receiving nothing while the producer reports its feeds running, and restarting the ingest service does not recover it. The ingest is a core NATS subscribe, not a JetStream durable, so the stale-consumer repair does not apply. | ||||
| Retire the Qt entity meta-model doc | codegen documentation qt |
entity_meta_model_cpp_qt.org documents a facet that no longer exists – no Qt templates remain and ores.cpp.qt is in no graph – and still describes the dead history properties as live. | ||||
| Retire the stale-host reaper and its scheduled job | compute |
The lease reaper replaces the reap_work handler and the compute.v1.reap.stale_results scheduled job, which are left in place. | ||||
| Revoke a collection's run grant when the collection is delet… | Revoke a collection's run grant when the collection is deleted. A collection's run grant (feeds_run_as_their_owning_tenant, doc/knowledge/architecture/feed_execution_identity.org) stays standing after its collection is deleted, until a person with iam::run_grants:revoke ends it. The delete of a market data generation config should revoke the grant it holds, as reporting revokes a report definition's grant on unschedule or delete. | |||||
| Running projects/ores.seeder/datasets/acme_corporation/gener… | Running projects/ores.seeder/datasets/acme_corporation/generate_configuration_data.py on main rewrites pricing_model_product_parameters.json: 761 insertions and 185 deletions, with new rows such as the FxCalibration Bootstrap model parameter and shifted positions. The committed JSON and the seed SQL built from it lag the generator. Found while splitting the curve segment by element (98901652-FEC5-4197-BE47-99F0C8453072); that branch restored the file to keep its diff on scope. Regenerate the JSON and the seed SQL in their own change, and consider a check that the committed seed JSON matches its generator. | |||||
| Running the workflow engine tests re-dispatches the deployment's in-flight runs | recover_in_progress() runs at engine construction and re-dispatches every in-progress step of every tenant, which is right for a deployed service resuming its runs and wrong for a test process pointed at the same database: the test re-stamps command_published_at on real runs, so their deadlines restart and a step that should have expired does not. Observed while proving the step deadline live: three test runs pushed a live run's deadline out at 11:20, 11:21 and 11:22. | |||||
| Say which key a service method takes in its signature | The generated service takes every key as const std::string&, so the storage key and the declared key are indistinguishable at the call site; passing the wrong one compiles, returns empty, and looks like a missing record. | |||||
| Scheduler and synthetic entities have no point-in-time list … | Scheduler and synthetic entities have no point-in-time list read yet. PR 2683 made as_of the default for every entity with a validity window, but applied it by merge and left ores.scheduler and ores.synthetic out, because their generated files drift too far from their templates to merge. Their clean-up stories (clean-scheduler, clean-synthetic) regenerate them, which brings as_of with it; each should check its list protocols carry as_of and its services read it. | |||||
| scheduler instances –job filters one page, not the collection | scheduler operations shell bug |
The shell's scheduler instances command filters by job name after the page arrives, and the operation orders executions by time. A narrow –limit therefore selects the newest rows and the filter sees only those: –job e2e-ok –limit 5 printed one of that job's two executions because the other fell outside the five newest rows. The command's help says the filter is page-scoped, which is a workaround rather than a fix. | ||||
| scheduler wakes on a fixed minute grid, not the next due instant | scheduler performance engine bug |
The loop arms a timer for the next wall-clock minute boundary and evaluates every job it holds on each wake, so a scheduler with one daily job wakes 1440 times a day and parses every job's cron expression every time. The due instant is known in advance: the loop should sleep until the earliest next occurrence among the jobs it holds, re-arm when the job set changes, and bound the sleep so a wall-clock adjustment cannot strand a firing. | ||||
| Scope a delete and an unclaimed write to the acting party | service codegen party |
A generated service's delete and a write with no precondition read the current row by key alone, so from a party that sees other parties they act on another party's row of the same key. | ||||
| Security definer functions run as the owner, which row-level… | Security definer functions run as the owner, which row-level security does not bind. Of 595 in the schema, 530 keep the default ACL, so any database role can run them, and 29 set no search_path. The IAM ones include ores_iam_reset_system_fn, ores_iam_provision_tenant_fn, ores_iam_create_initial_admin_fn and the publish-from-dq functions. Revoke execute from public and grant by name as ores_iam_account_exists_fn does, set a search_path on each, and add a check that fails for a new function without both. | |||||
| See the grid's trends by day, weekday and month | compute grid web timeseries |
Show the grid's load, throughput and outcomes as daily averages, monthly averages and averages by day of the week, so that an outlier stands out. | ||||
| Seed an approval kind and an apply step for convention changes | conventions approvals |
Market Risk holds the deciding part and the permission inbox::approvals:decide_market_risk, and no approval kind names a convention. A request holds no pending change and nothing applies a change when the last decider approves. Decide the kind or kinds, where the pending row lives, and the apply step, so the four convention management journeys can raise and decide a request. Found while writing the journeys Decide a convention change, Name a convention set and Retire a convention. | ||||
| Seed the permissions of the ORE parameter value set handlers | codegen tests iam reporting |
test_handler_permissions.py fails on main at c70e30a652: 16 permission codes the reporting ore_parameter value set handlers check, such as reporting::ore_parameter_setting_value_sets:delete, are not in iam_permissions_populate.sql, so the codegen suite is red for every branch. Seed the codes, or name why a handler checks a code no role can hold. | ||||
| Seed the standard desk groups and their members | refdata currencies seed dq |
A new tenant has no desk groups: currencies, pairs, calendars and their links each have a seed dataset, but currency groups and their memberships have no DQ artefact or seed script, so G10, G11, Scandies and the like must be typed by hand. | ||||
| Seeded IR swap series break the market data export | A fresh database seeds oresmd://ir/<ccy>?type=series&instrument=ir_swap"e=rate&fwd_start=0D&tenor=1D rows, and the export refuses them with 'has no ORE key: a series has no ORE key'. One such observation fails the whole export, so every report run dies at gather_market_data until the rows are deleted by hand. | |||||
| Seeded market data covers FX and leaves every currency curve without quotes | On a freshly provisioned environment the acme_demo seed gives FX spot series with observations and IR swap series with none, so a run reaches the grid and the engine fails building every yield curve with 'Could not find quote for Mandatory ID IR_SWAP/RATE/<ccy>/0D/1D/1M'. The series the seed writes are type=series with no term, while the engine asks for term-shapen quotes, so an export cannot match them either way. | |||||
| Serve search, order and history for tenants and parties | web iam refdata record-screens |
The tenant list has a server search but no order, and no tenant history is served, so the tenant page has no History tab. The party read has neither search nor order. Add them on the server so both lists sort and search like the refdata lists, and the tenant page gets its history. | ||||
| Settle the .1 family with the product owner | reporting sensitivity greeks decision |
Five open questions block the .1 design: what .1 means as a number, which greeks and buckets, which market data, which ORE version, and which cycle. | ||||
| Seventy-five entity models in seven components still carry a… | Seventy-five entity models in seven components still carry a Presentation drawer property that nothing reads. | |||||
| Shell completion tests fail with cli 2.3.0 | cli 2.3.0 no longer prefixes nested completions with the menu name, so 16 shell suites fail. | |||||
| Shell recipes state none for checked string columns | shell codegen doc defect |
The generated shell recipes put the token none in every string column of their example commands, including columns with a closed-set check such as trade_type_code. none is only meaningful for list tokens, so a string column takes it verbatim and the example command fails the check it documents. The recipes are generated, so the fix belongs in the codegen that emits the examples, not in the files. | ||||
| Simulated market data: consistent world vs. scenario workspaces | simulated_market_data strategy |
Strategy for simulated market data generation, decided 2026-08-12 (F15). Two use cases: (1) the consistent world, where the system party owns the sim config, publishes the theme once, and every party consumes the same stream into its own per-party series; (2) scenario data, future workspace-scoped work where users create artificial data with permission control and locking. Full decisions in doc/llm/specs/simulated-market-data-strategy.allium. | ||||
| Site build leaves pages whose source was deleted | documentation site build drift |
The site build does not remove built HTML when its org source is deleted, so a renamed or split document keeps serving its old version. | ||||
| Site build unrunnable: killed by the low-memory guard | compass build –direct site is killed by the harness low-memory guard on bright_faraday, in background and foreground alike, leaving doc changes shipping without their main verification. | |||||
| Skills are missing the frontmatter and regulatory function their contract requires | llm skills claude_code contract hygiene |
Fifty-one of eighty SKILL.org files carry no type or level frontmatter, and none of the eighty declares its regulatory function, which the skill contract states must be declared per instance because it cannot be inferred from the type. | ||||
| Smoke the convention record page on a live fleet | No one has looked at the convention record page since the parts were grouped and their payloads nested. The BFF zip is covered by its own suite, but the page itself has not been opened on a provisioned tenant. | |||||
| Split the arrival process from the synthetic generation configs | synthetic data-oriented-design modeling |
fx_spot_generation_config (20 members) and ir_curve_generation_config (21) both carry arrival_mode with branching_ratio, decay and sensitivity beside it. Read from outside the component, those three are the parameters of one arrival mode, a discriminator followed by its columns, and the same block in two types. A reading from the split-the-wide-types re-inventory for the synthetic owner to confirm or argue down. | ||||
| Start the fleet without systemd on macOS and Windows | compass services start/stop/status are systemd-only: they generate units and drive systemctl –user, and the controller/supervisor that used to exec and cascade-stop children was decommissioned when systemd took over. macOS and Windows runners have no systemd, so the nightly jobs cannot bring NATS up: the macOS run fails with 'nats-server did not become ready within 30s' and 'no systemd user unit nats-server-orestudio.service'. The CI suites need a non-systemd supervisor path: spawn nats-server and the ores binaries with a pid file per service, keep the existing log-based readiness gate (the loop already waits on port 20005), and cascade stop through the same pid files so the stop command stays complete. | |||||
| State each family part's cardinality and refuse a family write that breaks it | codegen refdata conventions |
A family model's Parts table names its parts but not how many rows each takes, so the generated family put accepts a commodity future with no contract terms or a cross currency swap with no leg, which the ORE export then refuses. | ||||
| Stop check runs leaving generated files dirty in the working tree | codegen checks snag |
compass check regenerates and compares, and on this environment the comparison leaves files modified: ores.refdata.api/domain/calendar_rule.hpp, then wire-protocol configuration_document_protocol.ts, then curve_bootstrap_config_protocol.ts, each appearing as modified within a minute of the others and sometimes showing an empty diff. Two files had to be reverted by hand in one session, and a generated header's reversion nearly went into a commit. The tree should be unchanged after a read-only check, or the check should name every file it wrote. | ||||
| Storage routes demand a token no C++ caller sends | storage http shell defect |
The storage HTTP routes call auth_required() and check a permission code per operation, but no first-party C++ caller supplies a token: ores.storage.core http_client and storage_transfer have no Authorization support at all, the shell's storage call sites pass only a base URL, and so do the services. Every shell upload and download and every service-side blob transfer therefore answers 401 – compute publish-package, compute download-input, compute download-output, ore upload, and the ore service's report-package handler that downloads the trades and market-data blobs and uploads the tarball. The bus interface is unaffected. | ||||
| Store only the closed days of a calendar | refdata calendars performance |
calendar_dates stores every day of every in-use calendar for each tenant, 473,025 rows, as a full bitemporal entity, while its readers keep only the 31% that are closed. | ||||
| story new wires a feature story into the Hotfixes table | compass agile bug |
The sprint wiring function in compass.py picks the last table whose header names Story and State, and the sprint's Hotfixes table has the same header, so every feature story lands in Hotfixes as BACKLOG. Pick the last Stories table before the Hotfixes heading for a feature story, and the Hotfixes table only for a hotfix; add a test. | ||||
| Story: Clean ores.diff to the component clean standard | codegen clean_standard v0 product_backlog |
Bring ores.diff to the Component Clean Standard (Entity items): tier 1, foundation infrastructure. | ||||
| Story: Clean ores.eventing to the component clean standard | codegen clean_standard v0 product_backlog |
Bring ores.eventing to the Component Clean Standard (All items): tier 1, foundation infrastructure. | ||||
| Story: Clean ores.history to the component clean standard | codegen clean_standard v0 product_backlog |
Bring ores.history to the Component Clean Standard (Protocol items): tier 2, higher infrastructure. | ||||
| Story: Codegen infrastructure follow-ups from DQ commissioning | codegen infrastructure tooling product_backlog |
General codegen infrastructure gaps surfaced while commissioning DQ entities but not specific to DQ: entity-model lint, consolidating the five ores.cpp.nats-* facets, compound natural-key support in lookup_entity/table SQL templates, and migrating the remaining 10 lookup_entity models to domain_entity. | ||||
| Story: Complete the LLM skills catalogue | llm skills claude_code product_backlog |
Finish the skills catalogue that sprint 25 started: the dispatcher, the verification ladder, the eval harness, the writing standards, the duplicate reconciliation and the end-to-end check, plus the codegen findings the catalogue work surfaced. | ||||
| Story: Complete the ORE report configuration | reporting ore model v0 product_backlog |
The remainder of the ORE report configuration: the round trips still missing, the classification that selects a report kind's workflow, the run-input packaging, and the hand-written tables that need models. Split from Model the ORE report configuration as entities at sprint 26 close. | ||||
| Story: Complete the ores.reporting clean-up | codegen clean_standard product_backlog |
The remainder of the ores.reporting clean-up: the shared template defects, the model corrections, the registrar composition, the shell commands, the diagrams and audit record, the input bundle model, and the schedule's definition key. Split from Clean ores.reporting to the component clean standard at sprint 26 close. | ||||
| Story: Default the shell facet on at the profile level | shell codegen cleanup v0 product_backlog |
The last lever of the shell surface story: make ores.cpp.shell-command default on at the profile level once no component would gain an unintended unit. Split from Generate the shell surface of the clean components at sprint 26 close. | ||||
| Story: Extract the remaining component user journeys | ux journeys product_backlog |
The remaining components' user journeys, after the extraction standard and the ores.refdata pass: analytics, the application shell, compute, dq, iam, marketdata, reporting, scheduler, synthetic, trading, workflow and workspace. Split from Extract the user journeys that replace the ores.qt screens at sprint 26 close. | ||||
| Story: Fix the defects the population and report work exposed | product_backlog |
Defects found while populating the ACME books and proving a report runs over them. None is about the trade population itself, and each was filed against that story because that is where it surfaced. | ||||
| Story: Implement the full report pipeline | reporting compute workflow product_backlog |
The remainder of the report pipeline: report pre- and post-processing, the orchestration contract, the substituted and live proofs, the baseline, and the engine's idempotency check in the reporting handlers. Split from Run a full report: scheduling, reporting and compute at sprint 26 close. | ||||
| Story: Implement the user journeys in ores.web | web ux journeys v0 product_backlog |
Programme story for the UX pass: one story per journey group in ores.web, built on one shared journey runtime, in dependency order. | ||||
| Story: Keep counting failed attempts on a locked account | iam web product_backlog |
A locked account still counts its failed sign-in attempts and records the address of each, so a run of attempts against a locked account shows as an attack. | ||||
| Story: Link every reference to its record | web ux product_backlog |
Replace the per-screen address functions with one system-wide mechanism, so every foreign key a web screen shows is a link to the page of the record it names. | ||||
| Story: Make ores.database a composite and host the generated entity | codegen database product_backlog |
The remainder of the read-only entity profile work: make ores.database a composite that hosts the generated entity without the foundation library linking the layers above it. Split from Add a read-only entity profile and make ores.database hostable at sprint 26 close. | ||||
| Story: Model operational authorisation and the client-facing agreement | v0 product_backlog |
Record authorisation as append-only decisions with a derived status and the queue as a read model, and hold the external version and confirmation status on the agreement unit. | ||||
| Story: Move the installation's remaining reads onto its own class | architecture tenancy security rls operations product_backlog |
The roster, the logs, the bus and the versions are facts about the deployment, not about a tenant. Story 58F3FC7C named that class and gave it a policy shape; this story moves the remaining reads onto it. The design is doc/knowledge/architecture/tenant_ownership_and_the_information_flow.org (id 5A5D6490-AF64-4AAF-8B3D-48EF3EDAF3D2). | ||||
| Story: Name the convention sets a report chooses | product_backlog |
Make the conventions a small set of clearly named, clearly purposed sets: a report binds one by choosing it, authoring has its own UX, and the gaps that block the choice are recorded as criteria. | ||||
| Story: Observe a run while it works | workflow observability progress journal ux v0 product_backlog |
A run states what each step is, how far into it the work has come, and what it has done so far, so a person watching a long step sees movement and a person reading a failed run sees why. The capability belongs to the workflow component, because every workflow in the system needs it; the setup journeys are its first consumer. | ||||
| Story: Paint every web badge from the catalogue | web ux badges product_backlog |
Replace the hand-picked Tag tones on state and type values in ores.web with one shared Badge component that paints from the badge catalogue. | ||||
| Story: Ready for business checks | rfb system-testing testing operations development product_backlog |
A battery of system checks a super administrator runs against a live environment, on a tenant created blank for the purpose, that exercises every subsystem in variations and reports as a time series so the environment's health is visible over time. | ||||
| Story: Roll out badge/image/plain-text rendering across classified domain entities | qt badges codegen refdata ux architecture product_backlog |
Consume the completed audit/classification's batched list: annotate each entity with badge_key/image wiring as classified, author any missing badge_definition/badge_mapping or image data, and regenerate, one batch at a time. | ||||
| Story: Session activity: record the size of every NATS message per server | iam nats telemetry product_backlog |
Count the bytes of every NATS message each server receives and sends, and write the totals to the database at a fixed interval, so the session activity has samples to draw. | ||||
| Story: Split ORE Studio services into one container per service | docker architecture deployment product_backlog |
Move from the single-container process-supervisor (ores.controller.service launching/monitoring the other 17 services as child processes) to the idiomatic Podman/container pattern of one process per container, with the orchestrator (podman pod, compose, or k8s) responsible for start ordering and supervision. | ||||
| Support the role grant request roles filter | iam.v1.role_grant_request_roles.list refuses every filter: role_grant_request_role_service.cpp returns filter_not_supported whenever request.filter is set, although the generated filter declares request_id_one_of. The inbox screens therefore read the roles of a page of requests one call per request. Implement request_id_one_of in the repository and service so a page of requests costs one call. | |||||
| Synthetic balance guaranteed swaps have no tranches, so an export of them fails | synthetic trade-population ore export rates |
Trade population books BalanceGuaranteedSwaps with no tranche rows, and the ORE writer requires at least one Tranche, so exporting a tenant after Acme provisioning stops with 'required element Tranche is absent from tranches'. Seen on a recreated database in the trade representation story; to fix when the work turns to trade population. | ||||
| Synthetic tenants and parties, when they return | provisioning synthetic |
The synthetic organisation generator was deleted: it built parties, counterparties, business units, portfolios, books and contacts inside an existing tenant, from a seed, and its only caller was a shell recipe that created a tenant named acme. What a synthetic tenant is worth having is a tenant created from a starting point with synthetic parties in it, which is a step kind or a profile rather than a shell command. | ||||
| Take the shell binary from the preset in the shell recipe check | codegen shell check |
check_shell_recipes.py hard-codes the linux-clang-debug-make shell binary, so it refuses to run in a worktree that builds another preset. | ||||
| Task: A recreated database leaves open browsers on the first-run wizard | web iam compass product_backlog agile |
A browser session opened before a database recreate is held on the first-run wizard and cannot read the starting points. | ||||
| Task: A stale compute node holds a job it cannot submit | compute storage iam product_backlog agile |
A compute node older than the submit protocol claims a job it can never hand back, so the batch never drains. | ||||
| Task: Label a curve binding by its curve | The Series column of a curve binding shows one arbitrary pillar of the curve and hides that the binding writes the whole curve. Label the binding by its curve and say how many pillars it writes. | |||||
| Task: Say which token expired, to whom, and what was waiting | observability iam workflow tooling auth |
A provisioning run died on "Session has expired" with no way to tell which client, which token family, or what it had been waiting for. Add the four records that make the next investigation a lookup. | ||||
| Teach compass the ABANDONED scenario state | The web QA runner has a fourth scenario state, ABANDONED, for a scenario nobody will run. A person sets it by hand in the doc: the State row, a dated note, and ABANDONED in the #+todo line. The test_scenario template and compass do not know it, so the template todo line lacks it and no compass verb sets it. Add it to the template, add a verb that abandons a scenario, and let sprint audit and the indexes treat it as closed. | |||||
| Tenant sessions never get the tenant administration mode | web bff session iam |
The BFF gives every tenant session the application mode, so no real session sees the tenant administration menu the design and the screens expect. | ||||
| Tenant tests fail on a second run against the same database | Tests that write generated tenants collide on tenants_code_uniq_idx when the suite runs again against the same database, because the generated codes repeat between runs. | |||||
| Terminating a tenant leaves its usage intervals open | marketdata billing tenancy |
A tenant terminated while it holds market data subscriptions keeps its subscription and demand intervals open forever: marketdata can no longer write for it, so nothing closes them, and usage summed over open intervals over-counts the tenant. | ||||
| test_handler_permissions fails two tests on main: six permis… | test_handler_permissions fails two tests on main: six permission codes are unseeded, all in ores.reporting/core. reporting::report_errors:read | write | delete in report_error_handler.hpp, and reporting::report_error_scopes:read | write | delete in report_error_scope_handler.hpp. The handlers arrived on 2026-10-16 18:32 with c759acec1f [reporting] Store the errors a report run produces, and their codes were not added to the seeds; the reporting populate has report_error_scope rows but no matching permission rows. Any branch whose codegen check runs sees this: codegen-tests was 1431 passed before that commit and is 1429 passed, 2 failed after it. | |
| Tests leave synthetic rows in the tenant lookups | iam tests data web |
The iam repository tests for tenant types and tenant statuses, and the seed profile tests, write synthetic rows into shared lookup tables and never remove them. After one ctest run a deployment holds 8 junk tenant types (CD 1 to CD 8), 8 junk tenant statuses and 2 junk seed profiles (CD_profile-…), which clutter the roster's filters and the New tenant journey's starting points. | ||||
| Tests share the environment NATS subjects with the running fleet | testing nats marketdata |
The marketdata suite connects with the environment's own subject prefix, so the running fleet consumes and adds messages on the subjects a test counts, and two ingest tests fail while the fleet runs. | ||||
| The :has_batch_read: flag is inert. Twenty trading instrumen… | The :has_batch_read: flag is inert. Twenty trading instrument models set it, and template_variables.org documents it as 'Repository exposes a batch read method', but no generator source and no template reads it. The batch read read_latest(context, <primary key vectors>) is declared in cpp_domain_type_repository.hpp.mustache and implemented in cpp_domain_type_repository.cpp.mustache unconditionally, with no guard. So the flag changes nothing, and it reads as if it did. Either delete the flag from the models and from template_variables.org, or give it a consumer. Found while scoping the composite family get and put in the atomise-the-convention pilot. | |||||
| The @ores/bff dev script cannot start the BFF from its own package | packages/bff/package.json runs its dev script as tsx watch –env-file=../../../.env src/main.ts, and npm runs a workspace script with the working directory set to the package. Both relative paths are then wrong: the env file resolves to projects/.env, which does not exist, and site-config's default <cwd>/config/environments.json resolves to packages/bff/config/environments.json, which does not exist either. The server therefore fails to start with 'node: ../../../.env: not found' or 'Cannot read the site configuration', and it starts only when launched from the workspace root with an explicit path: ORES_WEB_PORT=21803 npx tsx watch –env-file=../../.env packages/bff/src/main.ts. Found while verifying the credentials read routes live, which needs the BFF running from source rather than from the fleet's built dist. Either the script or the site-config default should resolve from the module rather than from the caller's working directory, and the start-up note in the README should match whatever is chosen. | |||||
| The adapter announce test races a live market data service | test flaky marketdata synthetic adapter |
The synthetic service suite test 'the adapter announces again until the service answers' asserts that no reply arrives within 300 ms, but a running ores.marketdata.service adapter supervisor answers the announce subject in that window, so the suite fails whenever the fleet is healthy. Make the test answer-proof: announce with a provider code the catalogue does not hold, so a live supervisor replies rejected and the flag stays false. | ||||
| The assets clean pass dropped the template-image function refdata still calls | assets refdata sql codegen defect |
The assets clean pass regenerated assets_images_create.sql from the model and dropped the hand-written ores_assets_get_template_image_fn. Refdata's LEI party publish still calls it and iam_service is still granted execute on it, so Acme provisioning fails at step 1 with: function ores_assets_get_template_image_fn(unknown) does not exist. | ||||
| The barrier direction belongs on the lookup table | The FX barrier check names the Up and Down styles beside the lookup that holds them. A style added to ores_trading_barrier_types_tbl falls into the no-direction branch, so the check and the table can disagree with no signal. Encode the direction on the lookup row and let the check read it. | |||||
| The batch workflow bridge has no test | compute testing |
The bridge's tenant-scoped removal was wrong and no test saw it; add an integration test that writes a link for one tenant, finishes the batch, polls, and asserts the link is gone. | ||||
| The BFF broker client is slow under concurrent calls | web bff nats performance |
Twenty-eight concurrent requests on one session take about eight seconds; the same requests in sequence take about 0.2 seconds. | ||||
| The bond planner draws its product by the slot's position an… | The bond planner draws its product by the slot's position and the book by the slot's position too, so with an even number of products against two books a product's parity fixes its book: every even-indexed product lands in one book, every odd-indexed one in the other, and no security is ever shared across books. Measured while writing the security naming test: eighty slots over two books produced no security held by both. Two cycles of even length align. Either the product cycle takes a stride coprime with the book count, or the book is drawn from something other than the slot's index. | |||||
| The bond's legs are not on the instrument tab | web trading instrument |
The prototype draws a Legs card for a bond and the trade page shows none, so a coupon or amortising bond cannot be read from its page. | ||||
| The book and portfolio writes carry the party | refdata protocol security codegen |
The refdata book and portfolio models mark party_id as a natural key, so their write records carry it from the client against the server-owned field rule; mark it server_owned as the synthetic feeds now do. | ||||
| The calibrate permission test times out when market data is stopped | testing synthetic gate |
feed_config_calibrate_writes_only_with_the_write_permissions previews the FX class against the shared database; once it holds stored fixings the preview reads each feed's window from the market data service, which the gate stops, so the request times out. It passes in 1.7 s with market data up. Make the test independent of the shared database and the running services. | ||||
| The catalogue carries 253 generated files that no longer match their models | check_component_drift.py –sweep reports that no file this branch touched would change, but 253 files elsewhere in the catalogue would. The registry of components under test is a list of components that are already clean, so a component waiting its turn has no gate at all and its generated output drifts from its models unremarked. The inbox is the clearest example: 117 of its generated registrars no longer match, and the trigger was commit cf89a3edda, Bring every declared subject onto the entity protocol, which changed inbox models after 99e17bd5a8 last regenerated those registrars. Nothing regenerates on build, so the drift sits there. The sweep docstring already states the position – a component's pre-existing drift belongs to that component's own clean-up – so this is a capture about the size of the debt rather than a defect in the gate. Decide whether the catalogue gets a standing regeneration task, or whether each clean-up story carries its component's drift as an explicit first step. | |||||
| The check gate builds on files its drift check rewrote | compass check regenerates drifted components in place and then builds on the result, so a hand-edited build file on main fails the build of every branch that touches that component. | |||||
| The clean-standard item ranges go stale in the component task plans | codegen clean_standard docs agile |
Every clean-* task plan enumerates the standard's section ranges, and the standard has grown twice since the tasks were scaffolded, so the plans name ranges that no longer cover the standard and the five items added later are invisible to the worker. | ||||
| The CMake archetype emits a Qt-era AUTOMOC comment | codegen cmake qt tech_debt |
The component-files archetype writes a Qt-era AUTOMOC comment into 78 checked-in component_files.cmake files, and AUTOMOC is never enabled anywhere in this build. | ||||
| The CMake source-list gate is red on main for thirty components | codegen cmake gate tech_debt |
core.py injects an AUTO-GENERATED FILE marker into every rendered file, including the cmake_component_files units, but the checked-in component_files.cmake files of about thirty components carry no marker. regenerate_cmake_component_files.py –all –check therefore reports roughly 141 stale files on main. The ores.assets clean-standard branch first added the marker tree-wide to turn the gate green, then reverted that as out of scope, so the gate stays red and this capture owns it. | ||||
| The codegen emits ores_dq_<entity>_artefact_create.sql for a… | sql |
The codegen emits ores_dq_<entity>_artefact_create.sql for an entity that turns on the domain_entity_artefact_create property, but emits no matching artefact drop. ores.refdata.calendar_type has both, and ores.refdata.commodity got only the create, so drop.sql leaves the table behind. Found while adding the commodity catalogue; worked around by hand-writing dq_commodities_artefact_drop.sql. | ||||
| The codegen test suite was red on main in seven places | Seven codegen-tests failures sit on origin/main, none of them any branch's. Four RLS fixtures do not carry has_tenant_id (the parser defaults it to true, so a hand-built model dict reads as false and the new validator refuses it) and one has no party_id column; test_sql_name_base's RLS fixture needs one too. test_soft_fk_target expected the trade anchor to be immutable, but [trading] Make every trading entity a regular, versioned table moved it to a regular versioned table, so the trade_id check now reads the current row. Fixed in the working tree; the immutable branch of target_immutable now has no fixture at all, because ores.inbox.delivery_outcome_type is the only immutable entity and nothing references it. | |||||
| The codegen tests write into the working tree | Running the codegen test suite leaves modified generated files behind: two files changed under a run of compass check, and neither is the branch's change. The gate that catches the resulting drift cannot then tell the side effect from the work. | |||||
| The completing step cannot clear a tenant's bootstrap mode | iam variability provisioning correctness bug |
Tenant provisioning seeds each new tenant with system.bootstrap_mode true and onboarding.tenant pending, and its completing step clears both. Both writes are creates over rows the provisioner already made, so the store refuses them: the step completes with a warning, the tenant keeps bootstrap mode, and the login reply tells the tenant's own administrator that provisioning is unfinished. The completing step must write the settings the tenant already holds, stating the version it read. | ||||
| The component class-diagram generator is tracked but run by … | The component class-diagram generator is tracked but run by no gate, so every diagram in the tree is behind the code. | |||||
| The Component Clean Standard undercounts its own items | codegen clean_standard component |
The standard's table holds 49 items. Its own prose says 47, and the two it does not count, G08 and H05, are the two a component can skip in silence. | ||||
| The component diagram parser drops three declaration shapes | codegen diagram plantuml |
generate_component_puml.py misses a base clause that wraps, a static data member, and a member whose initialiser wraps; fixing it changes 72 of 85 components' committed diagrams. | ||||
| The compute engine package cache is keyed by app version id, so a database recreate orphans it | compute grid storage devops |
The wrapper caches a downloaded engine package under a directory named after app_version_id, a per-environment database row UUID: a compass db recreate leaves every cached package unreachable and never reclaims it. | ||||
| The compute service spends 5% CPU polling with nothing to do | compute grid performance polling |
ores.compute.service publishes a NATS request about every half-second, indefinitely, and sits at roughly 5% CPU with no batches in flight. Three timer-driven loops and the dispatcher are the candidates; which one owns the traffic is not yet established. | ||||
| The compute service spends CPU while idle | compute performance |
With no work queued, ores.compute.service used 3.7 percent of a core, the most of any service in a fleet that does nothing else. | ||||
| The conventions pick-lists route answers 502 or 503 on every… | The conventions pick-lists route answers 502 or 503 on every call and has done since before 2026-10-18. Two faults, both in packages/bff/src/conventions.ts. First, its PICK_LISTS loop passes only { filter: null } to readAll, but every one of those lookup subjects requires as_of, so the first entry is refused with bad_request; tenors.ts passes { filter: null, as_of: null } and works, which is the fix. Second, once as_of is passed the loop gets as far as refdata.v1.sub_periods_coupon_types.list and that subject answers 503, so the route still fails and something else is missing for it, either a handler or a subject name. Verified against the running fleet: /api/conventions/pick-lists returns 503 'Cannot reach the message bus' caused by a 503 from that subject, while /api/tenors/pick-lists returns 200. Related: the route's calendars entry also reads calendar_names rather than calendars, the same wrong catalogue the tenor pick list had; that defect is hidden behind the other two. | |||||
| The conventions pick-lists route cannot reach the bus | web bff refdata conventions bug |
/api/conventions/pick-lists answers 503 with a transport error in forty-five milliseconds, while the six lists it reads answer from the shell and /api/books/pick-lists answers from the same route shape. | ||||
| The corpus roundtrip does not cover the CBO example | trading ore test |
The corpus roundtrip walks ORE's Example_Trades. The Products examples hold one more trade, a collateralised bond obligation in Input_CBO, which no test reads and which needs its bond basket from reference data. | ||||
| The CRM ingest bridge reads terminated tenants | marketdata tenancy |
crm_ingest_bridge reads its configs and driver pairs across all tenants with no tenant status check, so a terminated tenant's derived writes fail, as the usage recorder's did. | ||||
| The CRM rates service publishes to nobody | marketdata shell dead-code |
ores.marketdata still computes and publishes CRM rates on marketdata.v1.crm.rates, but the shell crm command, the client crm_rate_formatter and the whole client CRM stack went with the retired Qt matrix, so nothing subscribes and four recipes plus four .ores scripts document a command that no longer exists. | ||||
| The CRM shell recipes call a crm command that no longer exis… | The CRM shell recipes call a crm command that no longer exists. Commit ee4e739a65 (Generate the refdata shell surface) deleted the hand-written crm_commands from ores.shell's application part, but the four recipes under doc/recipes/shell/marketdata/crm/ and their scripts in projects/ores.shell/scripts/library/marketdata/crm_rates_*.ores still send 'crm rates majors' and its siblings. On 2026-10-05 each aborted with 'Wrong command: crm rates majors' against the live fleet. The CRM requests are declared in ores.marketdata.operations (marketdata.v1.crm.rate and marketdata.v1.crm.rates), so opting that operation model into ores.cpp.shell-command would generate the commands again; the recipes would then need the generated command names. | |||||
| The curve_sections scripts were never tangled into the library | shell codegen drift |
bright_faraday's curve_sections recipe is committed but its ten .ores scripts are not, and the shell-script-drift job diffs only tracked files so it never notices. Commit the tangle or drop the recipe's tangle targets. | ||||
| The deleted event never fires, because the delete rule rewrites the delete | codegen sql eventing |
Every generated entity rewrites DELETE into an UPDATE, and every generated notify trigger returns null on UPDATE, so the TG_OP=DELETE branch is unreachable and no component ever publishes a deleted event. | ||||
| The delivery meter keeps rejected counts forever | marketdata billing |
A delivery count the store rejects goes back into the meter and is retried every flush, with no limit, so a count that can never be written grows the meter for the life of the service. | ||||
| The digest tests run from a target the build no longer has | ores.trading.core.digest.tests is not in any CMakeLists: 41346d023c dropped add_subdirectory(digest_tests), so the sources are tracked but never built. CTest still runs the binary left in the build tree, from object files dated 2026-10-16, and it segfaults in tenant_aware_pool, a type that no longer exists. | |||||
| The documented regenerate-all command generates components that do not project | codegen typescript gates |
compass codegen regenerate –all –address ores.ts writes the TypeScript projection for components that never had one, and the added trading tree does not typecheck. | ||||
| The domain header's chrono include is gated wider than the symbol it serves | codegen cpp trading |
The domain class header template emits <chrono> for every entity with audit columns, but the member that needs it also requires the entity to have no audit group. An entity that carries audit_record audit gets the include and never spells std::chrono:: – six trading instrument headers are the only instances. Narrowing the gate to exclude them breaks 26 more headers, because <chrono> also covers chrono-typed columns the commit that added the gate removed from the models. | ||||
| The domain_type_table_io facet renders an operator<< that no… | The domain_type_table_io facet renders an operator<< that no translation unit can call. | |||||
| The drift checks render every component on every branch | codegen checks performance velocity |
component-drift and drift-sweep render 21 and 38 components on every run, 436s of the 785s non-heavy check total, even when only one component moved. | ||||
| The drift gate covers only the registry, and misses output written into another component's tree | codegen drift component |
The drift gate's coverage is the registry, and the registry is a list of model-bearing components rather than of generated files. Two holes follow. An archetype can route a model's output into another component's tree, so no run of either component reaches it. And 4,892 of the tree's 5,829 generated files sit under components the registry does not list, so a cross-component rename that invalidates a model's pasted source block breaks the build silently. | ||||
| The entity_org scaffold writes a Primary key section the entity loader does not read | codegen defect scaffold |
compass add entity_org scaffolds a model whose id column sits under a Primary key heading; ores.codegen.entity reads the key from Columns, so the first regeneration refuses the model it just wrote. | ||||
| The ER diagram PNG cannot be rendered at the current schema … | The ER diagram PNG cannot be rendered at the current schema size. Writing it fails with java.lang.NegativeArraySizeException because the image for 367 tables overflows a 32-bit pixel count, so the committed PNG is still the one main carries and it does not show the tables recent merges added or the bond_future_delivery_basket retirement. The .puml is correct and the drift job checks only it. Fix the render: split the diagram into per-package files, scale it down, or replace the PNG with an SVG that is rendered per package. | |||||
| The event bus logs every event it publishes at INFO | event_bus writes one INFO line per published event, so one corpus import put 566,867 lines in the marketdata service's journal. | |||||
| The evolution screen picker and the object form name a serie… | The evolution screen picker and the object form name a series by four words and its identity fields, such as fx / EUR / fx_option / rate_lnvol · ccy=CHF. The market data URL, oresmd://fx/EUR?type=quote&instrument=fx_option…, is the one name the rest of the product uses, and the screen already opens a series from an oresmd URL in the address. Show the URL as the series name, with the words as a secondary label, so a person can copy it, paste it into a link and read the same name in the shell and the logs. The server already composes the URL from a typed identity (compose_oresmd_uri), so the screen needs no codec of its own. Open questions: whether a long URL fits a select, and whether the words stay as the visible label with the URL on copy. | |||||
| The failed copy ingest test times out under parallel suites | marketdata testing flaky |
a_failed_copy_loses_no_other_tick_and_stores_none_twice_while_the_next_batch_waits timed out at its 60 second wait in 1 of 3 ctest runs at -j 4, and passed in every run alone. | ||||
| The feed ingest small batch test fails in full suite runs | a_small_batch_does_not_pass_the_batches_that_are_in_the_stages fails in full suite runs after its 60 s deadline and passes alone in about 3.5 s; the cause is not yet known. | |||||
| The feed ingest tests fail while the environment's services run | marketdata test |
Two feed ingest loop tests count the rows and republishes their own feed produced, in the environment's database and on its NATS subjects; when the environment's marketdata, official and synthetic services run they add ticks of their own, and the tests fail. | ||||
| The function that creates the first administrator does not refuse a second one | iam security defect |
ores_iam_create_initial_admin_fn grants SuperAdmin and clears bootstrap mode, but it never checks the flag, so anything that can reach the subject can make another super user after setup. | ||||
| The generated eventing history test races its own async re-drive | report_definition_eventing_integration_tests asserts get_definition_history(name).size() == versions.size() immediately after delete_definition, while the service's notification re-drive can still be writing. The assertion is red under database load and green otherwise. The template cpp_nats_integration_test.cpp.mustache carries it for every entity, so the fix is one template line and a regeneration across the components that have the case. | |||||
| The generated handler for a scoped read comments that it che… | The generated handler for a scoped read comments that it checks the permission a write needs, but it checks the read permission. The wording comes from the handler template and appears in every scoped read (78 models). Fix the template and regenerate, not one entity. Found in the review of PR 3200. | |||||
| The generated service code for a scoped read refuses an unso… | The generated service code for a scoped read refuses an unsortable order field, a one-of list over 1000 keys and a subtree scope on a foreign key to another entity. No test reaches those refusals for any of the scoped reads. Test them once in the generator tests, or emit one service test per scoped read. Found in the review of PR 3223. | |||||
| The generated set and save verbs erase a run's timestamps | The generated CRUD set and save verbs treat a workflow run's started_at, completed_at and last_event_at as caller-supplied, so an edit erases the completion times. This undoes the stamping the engine now does, the first time anything edits a workflow. | |||||
| The generated shell get, delete, versions and version never read a minted UUID key | codegen shell generator-defect |
The shell-command template fills a positional key only for a column the caller supplies on a write; a surrogate UUID is minted, so get, delete, versions and version emit the arity check and read nothing, and every one of them sends a default key. | ||||
| The generated shell lost the one-line bulk input for basket constituents and option underlyings | shell trading |
The deleted hand-written units took CODE:weight lists in one positional; the generated per-row commands work but need one call per row. | ||||
| The heavy checks run their suites serially and recreate the database unconditionally | sql checks performance velocity |
ctest and pgtap set no parallel level, and db recreate rebuilds the schema even when the fingerprint already matches the tree, on a path whose build is already about ninety minutes. | ||||
| The host row still carries a dead last-seen column | compute database defect |
The host row still carries last_rpc_time and nothing writes it. The heartbeat used to bump it, which added a bitemporal version per heartbeat and grew the host table by thousands of rows a day; that write is gone and the grid summary judges liveness from the node samples instead. The column remains in the model, the table, the generated entity, the wire protocol and the browser types, and its name promises a value nothing maintains. | ||||
| The i18n catalogue keeps the keys of the deleted screens | web i18n defect |
No check finds an unused key, so the words of the deleted entity screens sit in three catalogues and are translated forever. | ||||
| The IAM seed-profile tests fail on a second run against the same database | iam tests hygiene |
ores.iam.core.tests writes seed profiles whose code is <noun>_profile-<n>, with n counted from zero inside each process. The unique index covers an active code across the whole table, so a second run of the suite collides with the rows the first run left: duplicate key value violates unique constraint seed_profiles_code_uniq_idx on CD_profile-0. Two tests fail, and only a database recreate makes the suite green again. | ||||
| The journeys name a prototype source that moved | web ux journeys docs defect |
Fourteen journey documents point their Prototype section at projects/ores.web/packages/web/src/prototype/, which no longer exists: the prototypes now live under doc/prototypes/ with the hub at doc/prototypes/index.org. Both the Source line and the /prototype route are stale. | ||||
| The junction RLS policy name has no identifier-length guard | The junction create archetype composes its tenant isolation policy name in mustache as {{junction.name}}_tbl_tenant_isolation_policy, because load_org_junction_model never derives an rls_table_base the way the domain entity path does in core.py. PostgreSQL truncates identifiers at 63 bytes with a NOTICE rather than an error, so a junction whose name pushes the policy name past 63 bytes silently gets a different policy name than the template intends, and two long junctions could collide on one truncated name. The longest junction today is currency_pair_convention_calendars at 62 bytes, one under the limit, and it does not opt into RLS, so nothing is broken yet. The fix is to derive rls_table_base for junctions next to sql_name_base and truncate it with the _tbl_tenant_isolation_policy suffix reserved, mirroring the domain path's longest_rls_suffix budget. | |||||
| The junctions of assets, compute and reporting have no history | history junction codegen assets compute reporting |
Three junctions state neither a history nor change events, because their components serve no generic history: the assets image tag, the compute app version platform and the reporting report type configuration type. A link that is closed there is a row whose end is in the past, with nobody able to read it back. The components need a history dispatch and a registrar, as iam, refdata, dq, inbox and marketdata have, and then each junction can state :history: true. Composing change events in the same components is a second step, since assets, compute, inbox, marketdata and reporting compose none today. | ||||
| The legacy entity event mappings remain | eventing codegen |
One hundred and fifty-nine registrations still use the older register_mapping API and depend on the event source converting the trigger's canonical notification for them; migrate them to the generated canonical registrars and delete the older API. | ||||
| The LEI dataset is system-tenant only, so a party cannot read it | dq refdata tenancy defect |
The 38,213 legal entities a provisioned tenant holds sit in the DQ lei_entity artefact under the system tenant (ffffffff-ffff-ffff-ffff-ffffffffffff). A party's session reads its own tenant, so list_lei_entities returns nothing and a credit trade cannot name a reference entity. Legal entities are world data that every party should see, which is the split already recorded as world data versus party configuration; until that split reaches this dataset, no family can reference a legal entity. | ||||
| The listener loss-window test races its own reconnect | database test flake tech_debt |
postgres_listener_service_reconnect_surfaces_loss_window kills the listener's backend, waits for the old backend to be gone, then sends a notification it asserts is lost forever. Nothing stops the listener reconnecting between those two steps, and when it does the notification is delivered like any other: received[0] is the lost payload and the test fails. Seen once in a full 94-suite run on 2026-10-07 (ores.database.tests, postgres_listener_service_tests.cpp:368) and again on 2026-10-16 in a gate run for a branch that touches neither the database component nor the listener; both times it passed on an immediate re-run of the suite alone and in an earlier full run of the same binary. The comment says the wait makes the loss 'guaranteed rather than racy', but expect_gone proves only that the old backend died, not that the listener has not already reissued its LISTEN. The fix is to make the window unambiguous rather than timing-dependent, for example by holding the listener from reconnecting until the lost notification has been sent, or by asserting on the connection-loss counter instead of on which payload arrived. | ||||
| The local check gate is red on main | local_checks failed three checks on main: a junction-events case expected a subject_prefix the events template no longer emits, the storage CMakeLists carries a msgpack-c dependency its model does not state, and the dq_staging ER diagram was not redrawn when a column was added. The first two are fixed; the storage model is open. | |||||
| The local checks each parse the model corpus in their own process | codegen checks performance velocity |
About fifteen checks re-read the model and org corpus independently, and codegen-tests runs 1425 pytest cases single-threaded with no xdist in its venv. | ||||
| The macOS debug CI job runs out of disk | ci macos |
The continuous macOS debug job fails linking with errno 28, and another run's log stops mid-test before the step fails. | ||||
| The market data feeds the ACME reports need, by asset class | marketdata synthetic reporting acme |
A list across asset classes of every market data feed the ACME reports need to run, what the synthetic themes cover today, and what is missing. | ||||
| The market data route test fails on a minimal Acme tenant | pgtap marketdata test acme |
marketdata_route_visibility_test.sql assumes a tenant that people set up holds market data routes and subscriptions, so it fails tests 8 and 10 on a database provisioned from acme_minimal, which subscribes no market data. It passes on an unprovisioned database. The test should find a tenant that has routes, or skip when none does. | ||||
| The marketdata handler export_market_data_to_storage reads a… | The marketdata handler export_market_data_to_storage reads a run's market data as the run identity and makes no permission check at all, so any caller that reaches the subject reads it. Every sibling read in the same family checks a code. Found while tracing why collect_compute_results was refused on compute.v1.workunits.list_by_batch_id. | |||||
| The marketdata import looks up each series with its own query | import_service runs one read_latest_by_uri per distinct series per file, at about 18 ms each, so the corpus walk spends about 280 of its 330 seconds in 15,047 queries. | |||||
| The marketdata service ingest loop fails under parallel ctest | tests flaky marketdata |
Two cases in projects/ores.marketdata/service/tests/app_feed_ingest_loop_tests.cpp fail only when ctest runs them beside three other heavy suites: 'a burst is republished in order' at line 1140 waits for republished = sent, and the backpressure case at line 1310 waits for tap.count() = sent, each with a 60 second wall-clock deadline. Both pass when the suite runs alone, and both failed the same way on main before the hotfix that cleared the six failing checks. The loop is competing for the machine, so the fix is in the suite's timing design: wait on the loop's own progress signal rather than a wall-clock deadline, or give the suite a serial resource lock so it owns the machine. |
||||
| The metrics scrape fixes its schedule in a seed | scheduler variability metrics |
ores.mq.metrics_scrape runs every minute because a populate script says so, and moving it means editing that script and recreating the database. How often an installation scrapes metrics is an installation-level question, so the schedule belongs in a variability system setting. | ||||
| The minimal Acme tenant lacks reference data some example trades need | acme provisioning ore import marketdata |
On a tenant provisioned from acme_minimal, an ORE example bond is refused for its reference curve BENCHMARK-EUR, and an FX worst-of basket swap's constituents are refused because the FX catalogue does not hold TR20H-USD-CAD. The minimal profile should publish the reference data the ORE examples name, or the import should say what to provision. | ||||
| The MXN-TIIE curve config names no overnight convention | refdata_overnight_curve_configs_test fails on a fresh database: the seeded MXN-TIIE config has no overnight index convention of that id. | |||||
| The nightly bot does not regenerate the artefacts the gates check | Three gates catch drift between a source and its generated artefact, and they run on branches only. Main has gone red on the same class twice in two days, on 2026-10-07 (#239AABDC) and 2026-10-08 (#2797). The nightly bot that already merges into main fixes formatting; point it at the regeneration targets too, or make the gates required on the merge queue. | |||||
| The ORE key codec refuses a signed period | marketdata oresmd |
QuantLib reads a period with a sign, such as -1Y, and the typed datum model does not, so the ORE key codec refuses a key ORE would accept. | ||||
| The ORE vocabularies need a read-only marker | refdata ore modeling |
Day counters, calendar names, floating index types, leg types and business day conventions hold spellings ORE must read exactly, but nothing marks them read-only. | ||||
| The parser for an as-of instant, parse_as_of in ores.databas… | The parser for an as-of instant, parse_as_of in ores.database, accepts a date that is not on the calendar, such as 2026-02-30, because the time library normalises it. The request is not refused with as_of_invalid, and the database receives a day that does not exist. The range bound check added in the range members task checks the calendar itself. Do the same for as_of. | |||||
| The per-component link list in src/CMakeLists.txt is hand-ma… | The per-component link list in src/CMakeLists.txt is hand-maintained, not model-derived. Of 94 src/CMakeLists.txt, 93 diverge from the template baseline, in both directions: ores.geo carries Boost::boost, ores.database.lib and ores.telemetry.core.lib while lacking sqlgen::sqlgen, ores.logging.lib, ores.platform.lib, ores.utility.lib and ores.rfl.pch; ores.iam/api adds ores.security.lib. The extra_dependencies slot that exists for exactly this is used by only 5 files. The templates are also behind the 2026-07-30 migration away from file(GLOB_RECURSE): ores.cmake.component.api_src and .core_src still emit it while 88 of the 94 checked-in files now include component_files.cmake. Finishing this means encoding the 94 link lists into their models and bringing the api, core and service src templates onto component_files.cmake. | |||||
| The population cannot book an FX variance swap | The acme_demo trade population aborts partway: the FX variance swap it plans states an end date on or before its start date, and ores_trading_fx_variance_swap_instruments_tbl_check1 refuses it. Every profile that generates trades stops there, so a provisioned tenant gets a partial population. | |||||
| The population work landed without its synthetic half | build main broken synthetic iam |
cb28cc941d calls ores::synthetic::service::routed_code_count, which no header declares, and trade_population_planner.cpp does not build against the instrument batch it is handed. origin/main does not compile, so no C++ suite can run on it. | ||||
| The population writes a party id into the issuer | synthetic trading seeding bug |
A bond issue's issuer is a free-text name, and the generated population puts a party id there, so the trade page has nothing a person can read to show. | ||||
| The pr-raise skill names a script that no longer exists | skills process |
compass-pr-raise asks for scripts/ore_domain_roundtrip_check.py, which is gone, and runs the cmake-sources check with the system python, which lacks the codegen dependencies. | ||||
| The pre-PR checks have no format check, though a nightly job enforces one | compass process |
compass-pr-raise lists no clang-format check for a code change, so unformatted files reach main and only the nightly format workflow reports them. | ||||
| The provision-parties workflow names two subjects that do not exist | workflow provisioning refdata defect |
Its header comment and ores.refdata.protocol.org name refdata.v1.parties.save and iam.v1.account_parties.save; the real subjects are put and put_many. | ||||
| The provision_tenant step is published and never consumed, leaving a tenant half bootstrapped | After a database recreate on merry_newton, compass db recreate then the ACME provisioning script stopped at bootstrap: the tenant_setup_workflow published step 0 (publish_bundle) to iam.v1.ops.provision_tenant_step at 23:11:32 and no service logged receiving it, so the workflow waited 20 minutes and failed, and the tenant stayed in bootstrapping. workflow retry resumed the instance and published the same step again with the same silence. The instance is 14fb17a2-cdda-4d4b-95d6-1b316ff853cf. The system then refuses bootstrap because it is no longer in bootstrap mode, so the tenant cannot be finished and the environment has no usable data. Evidence: journalctl –user -u ores.workflow.service-merry_newton around 23:11:32 shows the step published via stream; the iam service log shows no receipt. Check whether the stream consumer binding survives a recreate, and whether the step should fail loudly instead of waiting 20 minutes. | |||||
| The report error handler permissions are unseeded | The codegen permission check fails on main: report_errors' handler permission codes were never seeded, so two codegen tests fail. It came in with the report error work and nobody noticed because the failure is in a suite that runs on the generator rather than the service. | |||||
| The report-definition eventing re-drive collides with the temporal exclusion constraint | Under a fully parallel ctest run, the notification wait in write_report_definition_publishes_nats_changed_event times out, and the re-drive that is meant to rescue it throws an exclusion-constraint error instead. | |||||
| The reporting report-definition-templates forwarder is dead | reporting protocol defect |
reporting.v1.report-definition-templates.list is registered and forwards to dq's subject, but no client sends it. Its request and response are declared in a handler header rather than a protocol header, so the twin-coverage gate cannot see them. | ||||
| The scheduler and reporting have no journeys | scheduler reporting web ux journeys |
The grid's lineage crosses three areas: the scheduler that fires a run, the report that defines it, and the grid that executes it. The compute group now names the chain, but the scheduler and reporting groups do not exist, so the lineage points at screens no journey describes. | ||||
| The schema drop script leaves 115 functions behind | Running drop/drop.sql removes every table but leaves 115 ores_ functions, 63 of them in refdata, because their drop files are missing, unwired or name a different signature. | |||||
| The seed profile carries a password flag only the web form reads | iam codegen web agile |
inherits_admin_password is stored, mapped, displayed and settable from the shell, and the provisioning path never reads it. The tenant administrator's password is whatever the caller passes to bootstrap setup, and a dataset's staff take their hash from the dataset. Only the web setup journey reads the flag, as the offer to hand the creator's password to the new tenant's administrator. Retiring it is therefore a journey affordance, not a provisioning rule, and it collides with whoever owns the setup journeys. | ||||
| The seed upsert helpers rely on an ON CONFLICT clause the versioning trigger pre-empts | dq sql seed environment |
Twenty-five helpers in create/seed/upsert_functions_create.sql insert with ON CONFLICT DO NOTHING against versioned tables whose BEFORE INSERT trigger refuses a duplicate create, so the clause never fires; each needs the existence check the file's header documents, and a concurrent caller meets the trigger's 23505 rather than a quiet skip. | ||||
| The seeded inflation curve states its index, its conventions… | The seeded inflation curve states its index, its conventions and its calendar, and states no fixings: the market data series identity view holds zero rows for inflation and the seasonality factors table is empty. An inflation swap that names the index therefore resolves the curve and cannot be priced, because the engine has no fixing series to read and no seasonality to apply. Seed a fixing series per index — monthly values against the currency's calendar, the last fixing the curve's use_last_fixing_date points at — and the seasonality factors the index's convention names, so the family's trades price rather than only book. | |||||
| The seeded report definition Intercompany Exposure Matrix (p… | The seeded report definition Intercompany Exposure Matrix (projects/ores.sql/populate/reporting/reporting_report_definitions_populate.sql:205) has schedule_expression '0 6 * * 1,15'. Its fifth field is the day of week, where 15 is out of range (0 to 6), and its description says Monthly cadence. The author probably meant the day of month: '0 6 1 * *' for monthly, or '0 6 1,15 * *' for the 1st and 15th. Any path that parses it with cron_expression::from_string refuses it. Decide which cadence was meant and correct the seed. | |||||
| The series identity field is named identity in every read | Seven requests of the marketdata operations model name a series by a request field called identity. The word does not say a series, or that it is a set of typed fields and not a key. A reader asked what it is. Rename the field to series_identity in every request together, and say in one glossary entry what a series identity is. | |||||
| The service template repeats its stamp comment and reason expression once per member | codegen |
cpp_service.cpp.mustache emits the same three-line comment and the same reason-code expression for every stamped member, and leaves an orphaned comment above them. | ||||
| The services refuse a hand-written list request | web bff trading protocol bug |
A list request must state every member of its filter and its as_of, and it must read the rows from the reply field the response declares. A hand-written request that leaves any of them out is refused as bad_request, so a whole screen shows an error instead of rows. | ||||
| The services roster reply does not state its running window | telemetry compute defect |
The roster read decides running from lost against the server's service_running_window constant, and the reply carries no window, so a screen that states the window in words must write the number itself. The services screen states five minutes; if the constant changes, the screen asserts a window the read does not use. | ||||
| The session door holds no verifier | Signing in over HTTP answers 'Authentication is not configured' on a running deployment, because the door copies the server's verifier before the service runner installs it. Every browser session, and so the only client of the change stream, is blocked until the door asks for the verifier when it needs it. | |||||
| The session read handlers skip the permission check the catalogue grants | projects/ores.iam/core/include/ores.iam.core/messaging/session_handler.hpp guards put_session, put_many_sessions, delete_session and delete_many_sessions with iam::sessions:write and iam::sessions:delete, and list_sessions, get_session and get_many_sessions check no permission at all. The catalogue grants iam::sessions:read ('View active sessions') for exactly this purpose, and the account and login-record reads check their equivalents (iam::accounts:read, iam::login_info:read), so the three session reads are unguarded by oversight. Any authenticated caller can list the tenant's sessions, with client, address, country, byte counters and account. Found while inventorying the routes and operations the credentials journeys need; the Audit sign-ins screen would be built on these reads. | |||||
| The settings build reverts a hand-added compass test | codegen drift compass tech_debt |
compass build –direct settings tangles doc/llm/claude_code_settings.org, which regenerates projects/ores.compass/tests/test_deny_bare_stash_hook.py. Commit 20cd5089d5 hand-added test_compass_does_not_run_a_denied_stash to that generated file without adding it to the org source at line 996, so every settings refresh silently deletes the test. Reproduced twice on 2026-09-23 from feature/clean-assets: run the build, the test disappears (grep count 1 to 0); git checkout restores it. Fix by adding the test block to the org source and re-tangling, or the drift returns on the next bearings next-action. | ||||
| The settings deploy reverts a generated compass test | compass build –direct settings tangles projects/ores.compass/tests/test_deny_bare_stash_hook.py from doc/llm/claude_code_settings.org, so deploying settings regenerates that file. Commit 20cd5089d5 added test_compass_does_not_run_a_denied_stash and the ast import to the tangled file and never updated the org block, so main's committed test and its source disagree. A settings deploy therefore deletes 38 lines, including the regression test that rebuilds every git stash command from compass.py and judges it with the hook's own denied — the test guarding the capture PR flow fix that same commit made. The bearings NEXT ACTION 'refresh .claude/settings.json' triggers it, and the loss reads as an unrelated working-tree edit, which also makes check_component_drift.py –all report the dirty file. Fix is to move the added test into the org source block at doc/llm/claude_code_settings.org line 996, re-deploy, and confirm the file is byte-identical. | |||||
| The settings table hides the installation's rows from a tenant's party | variability settings iam party onboarding |
A tenant session cannot read a setting the installation states once, so a screen cannot say what the deployment enforces, and the wizard flag has read false for every tenant since it was written. | ||||
| The shared change-event schema reads a country-shaped field | web eventing bff defect |
The browser decodes every change notification with a schema whose id field is alpha2_codes, a name from the country event, while the generic entity_change_event publishes entity_ids. Every field has a default, so any non-country subscription succeeds and silently delivers an empty id list. | ||||
| The shell aggregator opts out silently on a missing overview or a misspelt flag | codegen shell |
shell_command_surface finds the overview by a fixed directory depth and returns no surface when it is absent or its flag value is not recognised. | ||||
| The shell history command needs a clear error for a stale key | history shell codegen errors |
Ten entities now read their generic history by the row's own id: party and counterparty contacts, party, counterparty and netting set identifiers, business units, portfolios, portfolio rights, CSA eligible currencies and run grants. A caller that passes the old declared key, such as the shell history command with a contact type, gets the dispatcher's failure text, bad lexical cast, which names neither the entity nor the key it expected. The provider should refuse a value that is not a uuid with a message that names the entity and says the history is read by the row id, and the shell command should say which id to pass. | ||||
| The shell recipes do not carry the arrival columns | shell recipes synthetic codegen coordination |
The fx_spot_generation_config and ir_curve_generation_config entities gained arrival_mode, branching_ratio, decay and sensitivity, but the shell recipes and their generated scripts still pass the old column set, so the CLI cannot author or show a feed's regime. The recipes are tangles of doc/recipes/shell/… and are regenerated with compass build –direct tangle_shell_scripts. They are also the files eager_maxwell has in flight, so this belongs to whoever lands that work rather than being fixed underneath it. | ||||
| The shell reports a tenant provisioned after two of nine steps | provisioning shell snag |
bootstrap setup and provision tenant both print 'All 2 step(s) completed' and 'Tenant provisioned' as soon as the provision_tenant_workflow finishes, while the tenant is still being populated by a 9-step tenant_setup_workflow and eleven bundle publishes that run asynchronously. The same run also prints 'Poll failed (1/5): Workflow instance not found' before declaring success. On a fresh database the shell announced a ready tenant while load_staff and start_market_feeds had not run, so its own progress report cannot be trusted; the only reliable signal is the workflow instance and step tables. Either wait for the setup workflow before reporting success, or say what is still running. | ||||
| The shell script library is untangled | shell codegen drift |
The codegen-generated shell recipes have no tangled .ores scripts in the shipped library, because tangle_shell_scripts is not part of the build or the drift gate; 793 scripts are missing. | ||||
| The shell splits a word at an exclamation mark | shell usability passwords |
ores.shell's REPL tokenizer, the vendored cli library's detail/split.h, makes every ! a token of its own, inside a word as well as at its start. A password such as Abc!def becomes three arguments, and the command reports 'Expected 3 arguments, got 5' with no mention of the !. Quoting or escaping the word avoids it. | ||||
| The shell unit lookup and model discovery can disagree on depth, and the cache never refreshes | codegen shell |
_shell_command_units globs to a depth that must match discover_models, nothing checks they agree, and its lru_cache can serve stale models to a long-lived process. | ||||
| The site build publishes ores.web's node_modules | site docs build |
The documentation site build copies every file under projects/ores.web/node_modules into the site as an attachment. | ||||
| The site page check republishes from file mtimes, not the branch diff | docs checks performance velocity |
compass site page republishes every page whose source mtime beats its published HTML, so a fresh checkout makes the whole corpus look changed; a cold run published 1487 pages and hit the 900s timeout. | ||||
| The skills prune refuses a symlinked entry | compass build –direct skills exits 1 on this checkout. ores/prune-stale-skills (projects/ores.lisp/src/ores-build-skills.el:127) lists .claude/skills/, finds the allium entry (a symlink to .agents/skills/allium, local tooling), finds no doc/llm/skills/allium/SKILL.org source, treats it as stale publish output and calls delete-directory on it; Emacs refuses a symlink and signals 'Removing directory: Not a directory', which aborts the build before kill-emacs 0. The publish phase runs first, so the deployed skills are current; the prune never runs, so genuinely stale outputs stay. The prune should skip symlinked entries: publish output is always a real directory. | |||||
| The staff-photos branch of the Acme seeder generates SQL for… | The staff-photos branch of the Acme seeder generates SQL for column names the assets image table no longer has. projects/ores.seeder/datasets/acme_corporation/generate_sql.py writes acme_staff_photos_populate.sql with the columns key and image_id, while projects/ores.sql/create/assets/assets_images_create.sql declares id and code, so regenerating that script produces a populate that cannot run. The committed script is the correct one and disagrees with its own generator, which is why the generator's output was reverted rather than committed while regenerating the Acme portfolio scripts for the boolean flag change. The other seventeen scripts the same generator writes are in step, so the fault is in this one branch of it, and it is either a stale column list in the assets image model's reader or a rename that reached the generator and not the table. | |||||
| The start_market_feeds provisioning step fails with 'NATS re… | The start_market_feeds provisioning step fails with 'NATS request timed out' on an Acme provision, although the feeds start. On swift_curie (2026-10-13, branch feature/move-the-duplicated-dq-models-onto-their-owners, which does not touch the feed path) the step on iam.v1.ops.provision_tenant_step was published at 23:58:49 and failed at 00:00:03, 74 seconds later. All five Acme parties then held 55 feed bindings each and ticks kept arriving in ores_marketdata_market_observations_tbl. The request timeout is shorter than the time the step needs to bind and start 275 feeds, so the run records a failed step for work that succeeded. Fix: answer the request before the feeds start, or raise the timeout for this step, or start the feeds per party. | |||||
| The store never canonicalises the business day convention | ores.refdata.core's curve-configuration round trip asserts that the store keeps one code per business day convention, and nothing does it: stored_business_day_convention has one caller in the tree, the test. Also as_stored turns an absent convention into an empty string, which the round trip then reports as a lost value. | |||||
| The structure completion has no caller | trading web structure completion grouping |
complete_structure writes a structure, its members and takes every leg live in one unit, and nothing calls it: the grouping screen and the book-a-trade flow still write the structure and then each member through the entity writes, which leaves the legs drafts and lets a half-grouped deal stand. | ||||
| The surface slices journey ends with two checks: calendar ar… | The surface slices journey ends with two checks: calendar arbitrage (total variance must not fall as expiry grows at a fixed strike) and butterfly arbitrage (the density implied by each smile must not be negative). No server operation returns total variance along an expiry axis or an implied density, so the screen can only say the checks are absent. Add the two checks as server reads over a surface, and show their result under the surface plot. Needs a decision first on which axis conventions are supported: the demo surfaces hold ATM, 25RR and 25BF, which are not strikes, so the checks need a strike or delta axis or a conversion. | |||||
| The synthetic generator ignores a column's default_value unless the column also carries a generator block | codegen generator-defect synthetic-data tech_debt |
cpp_domain_type_generator.cpp.mustache honours a column's declared default_value only when the model also supplies a generator block; with no block it assigns a random faker value, silently discarding the default. Found on ores.assets.image.mime_type, whose model declares image/svg+xml and whose SQL column default is the same, yet every synthetic image was written with a random noun. Fixed for assets by restating the literal in a generator block; the template fix would touch all 53 models that declare default_value. | ||||
| The synthetic market data scope check never reaches its check constraint | sql pgtap synthetic |
synthetic_market_data_generation_config_scope_test.sql test 6 expects error 23514 from the scope check constraint, but a tenant-existence trigger raises 23503 first, because the test uses a tenant id that does not exist. The suite fails on origin/main with no branch changes. | ||||
| The synthetic population carries its generated values in a p… | synthetic |
The synthetic population carries its generated values in a per-family bag: trade_terms is a std::variant of bond_terms, commodity_terms, rate_terms, fx_terms, equity_terms and now credit_terms, and equity_terms alone is about forty members. The planner fills it, the writer reads it and constructs the real trading domain rows from it. | ||||
| The telemetry log query escapes SQL by hand | telemetry sql security |
build_where_clause() interpolates the component and message_contains filters into LIKE patterns with std::format and manual quote escaping, where every other repository binds its values. | ||||
| The tenant purge has no pgTAP test | ores_iam_purge_tenant_fn now deletes every tenant-scoped trading table, instruments included, and passes the anchor's guard through the immutable purge switch. It was proved only by hand against the provisioned ACME tenant in a rolled-back transaction (103 rows in 9 tables to 0 in 90). A pgTAP test that books a trade with an instrument for a test tenant, purges it and asserts no trading row is left would lock the behaviour in. | |||||
| The test helpers isolate by test run, not by test. scoped_database_helper takes its tenant from the environment, so every test in one run shares that tenant, and a test binary run by hand with the .env tenant shares it across runs too. This is by design (the helper says no truncation is needed), but nothing says that a test must therefore use keys of its own. Two marketdata tests broke other suites intermittently by writing to a surface another suite reads, and a two-party import test failed on its first import because an earlier test had left the same surface in the shared tenant. Write the convention down in the helpers and in the testing guide: one currency pair or curve id per test, and fresh ids for anything a test writes. Consider a helper that makes a tenant of its own for tests that need one. | The scoped test helper shares one tenant across tests, so a surface or a series one test writes is still there for the next. The helper's comment says each test run uses an isolated tenant, but without a test tenant in the environment it falls back to the system tenant, and the plain helper does the same. Two marketdata tests broke other suites intermittently because of it, and a test that imports a file twice under two parties failed on the first import for the same reason. Make each scoped helper create and use a tenant of its own, or state in its comment that it does not, and give the marketdata tests one currency pair each only as long as that holds. | |||||
| The tick_clock first-gap test fails since the random phase | Main's commit 7484ed7f97 gave periodic arrival a random phase drawn from a default seed, so the first gap is 0.001 times 0.5928 (0.00059284461651668) and the tick_clock test that expects a full period fails in ores.analytics.quant.tests, in unity and non-unity builds alike. | |||||
| The ticks hypertable grows without bound on the Apache edition | marketdata database timescaledb |
TimescaleDB runs the Apache edition, which has no retention job, so the seven-day retention the ticks table declares is never set and the table keeps every row. | ||||
| The ticks smoke fails on a fresh database | compass smoke ticks reports that the adapters accepted 66 of the 86 ids demanded, so the gate fails on a database provisioned from scratch. The reporting work is not affected, but a fresh environment cannot pass its own smoke until this is understood. | |||||
| The ticks smoke fails on the demand no feed serves | marketdata synthetic smoke |
After a database recreate, compass smoke ticks provisions Acme, sees 30 ticks arrive and then fails: the bloomberg adapter accepted 66 of the 86 ids demanded and rejected 20. The synthetic service announces 362 ids for that provider, 296 of them unknown to any feed, so the demo profile demands market data this build does not generate. The check is a gate for an environment and cannot go green until the demand matches the feeds, or the smoke reports the gap without failing. | ||||
| The timeline page formats a date with date.getMonth() where … | The timeline page formats a date with date.getMonth() where it needs getMonth() + 1, and pads neither the month nor the day, so it writes the wrong month and an unpadded day. src/timeline/Timeline.tsx:444 returns String(getFullYear()) + '-' + String(getMonth()) + '-' + String(getDate()), which for 2026-10-18 gives 2026-9-18. The correct local-date helper already exists as loadedIso in src/ui/loadedLabel.ts, which reads the local clock and pads both fields; the resolve screen uses it. Outside that page the repo has no other caller of the broken form. Fix is to reuse loadedIso and delete the local formatter. | |||||
| The tree has no way to send an email, and password recovery needs one | The Rescue access and Entry journeys need a single-use, time-limited password-recovery link delivered to the address on the account. Nothing in the tree can send it: there is no SMTP client, no mail service and no template pipeline, and no table stores a recovery token. ores_iam_accounts_tbl carries email; ores_iam_account_credentials_tbl carries password_hash, service_password_hash and totp_secret; ores_iam_login_info_tbl carries password_reset_required and nothing token-shaped. The candidate subjects are iam.v1.ops.request_password_reset and iam.v1.ops.complete_password_reset, since neither is an entity verb. This is platform capability rather than a credentials screen, because sign-up verification, notifications and alerting will want the same delivery path, and it carries the usual security obligations: token entropy, single use, expiry, rate limiting, and not disclosing whether an address exists. Raised by the product owner while accepting the Rescue access prototype, after the screen was changed from an administrator-typed password to a recovery link. | |||||
| The TypeScript field-group import has no unit test for a cross-component group | codegen web |
_group_import derives the owner and the relative path from the qualified name, and only the web typecheck catches a wrong path. | ||||
| The V04 recipe replay needs the checkout .env exported, and … | The V04 recipe replay needs the checkout .env exported, and fails in a way that blames login. | |||||
| The vendored ORE manifest's digest depends on the locale | tooling ore reproducibility |
update_ore_samples.sh orders the vendored paths with sort, which follows the locale, before it hashes them, so the tree_sha256 in external/ore/xsd/manifest.json is en_GB order and differs under the C locale. The ORE file seed check reproduces it by calling sort the same way; the digest should order the paths by bytes, with LC_ALL=C, so it is the same on every machine. | ||||
| The web workspaces pin every dependency exactly and repeat the shared ones | Every package.json under projects/ores.web pins a third-party dependency to an exact version, and zod, vitest, tsx and @types/node are declared in several packages. A bump of one declaration leaves two copies of a library in the tree, and zod 4.6.6 in one package and 4.6.5 in the others made the bff typecheck run out of memory. | |||||
| The web's generic list registries still decide per resource … | The web's generic list registries still decide per resource whether a list sends as_of. records.ts and classifications.ts carry an asOf flag and add as_of only where it is set. Since PR 2683 every generated entity list accepts as_of, so the flag describes nothing: a resource without it cannot ask for a past instant, though the server would answer. Retire the flag, or set it everywhere, and let every list offer the point-in-time read. | |||||
| The workflow engine depends on the components that commission it | workflow architecture dependencies |
ores.workflow's registrar includes dq, ore, refdata and reporting and calls their registration functions, so the engine cannot build without four components that should depend on it. The definitions are C++ lambdas, so they compile into the engine's process. Removing the inversion needs workflow definitions as data, which modelling the workflows would produce. Found by the ores.workflow clean-up (P04 detail) and never filed. | ||||
| The workflow engine leaves completed_at and the published marker unwritten | workflow engine defect |
workflow_instance.completed_at and .last_event_at were never written by the engine or by any trigger. Both are now written at the transitions the engine already knew about; the recovery pass already stamps command_published_at. | ||||
| Three iam shell recipe library directories have no committed… | Three iam shell recipe library directories have no committed scripts on main. | |||||
| Three segment leaves the contract has no row for | The extractor reads PillarChoice, DuplicatePillarPolicy, Priority and MinDistance from the ORE source, but the guide explains them in prose and never lists them as items, so no term carries a text and the contract writes no row. Taken by task 2A7C0F5B. | |||||
| Three services default their storage base URL to a port the server does not use | storage http configuration defect |
ores.trading, ores.marketdata and ores.reporting default http-base-url to http://localhost:8080, while the http server listens on 21000, and their units pass no override. Every storage call from those services fails to connect. | ||||
| to_iso8601_utc emits a space separator, so the name and the platform overview overstate the format | platform datetime api_contract doc |
to_iso8601_utc formats as YYYY-MM-DD HH:MM:SSZ, with a space, which is not ISO 8601; the platform overview calls it ISO 8601. Either the separator becomes T or the name and the overview stop claiming the standard. | ||||
| Trace a process run over a set of trades | trading trade_activity trade_set process traceability |
Record an enumeration of the processes, a table per run of a process with its own id and an FSM over its evolution, and make that run id the foreign key the trade groups carry for their inputs and outputs, so a process can be undone or repeated. Pilot one process before adding the rest. | ||||
| Trading structure identifiers have no row level security | The er-diagram check's strict validation reports that ores_trading_structure_identifiers_tbl has tenant_id and no ENABLE ROW LEVEL SECURITY in any create script, so a tenant could read another tenant's rows through it. The rls-widenings check does not see it because it looks for widenings, not for a missing guard. Add the guard and a policy, and confirm the table's other tenant-scoped siblings have theirs. | |||||
| Try distcc on host newton (Debian on WSL) to shorten how lon… | Try distcc on host newton (Debian on WSL) to shorten how long each build holds a host build slot. Builds queue on the two host slots, the abstract AF_UNIX names @ores-build-slot-a and @ores-build-slot-b, across about ten worktrees, and a wait can last an hour while the compile takes minutes. ccache already hits 87.7 percent of compiles, so distcc only helps on misses, which are the costly files after a regenerated header. Conditions: newton needs the same clang as this host (Debian clang 21.1.8); plain distcc ships large preprocessed sources, and pump mode needs the same vcpkg tree and paths on newton; linking, preprocessing and all tests stay local; compass ties a slot to -j6, so a higher -j for the remote part needs new slot accounting so this host is not overloaded. Check the network path from WSL. Measure first: compare slot hold time for one build with and without distcc. Separately, the old slot-b lock file named bright_faraday since 2026-10-10 with a dead pid (200392). The abstract-socket lock cannot go stale because the kernel frees the name when the holder exits, and `compass build –status` reports the live holder plus, for a free slot, the last holder this checkout recorded; check that before adding tooling. | |||||
| Turn ORE's memory reports into node memory samples | compute telemetry ore monitoring |
ORE writes six memory-use lines per run (peak and current memory at the start and end of the analytics and the pricing analytic). The wrapper now stores them as debug log lines. Parse them into node samples so the grid screen can chart the memory each node uses. | ||||
| Twelve permission codes the iam handlers check are still not… | iam permissions codegen |
Twelve permission codes the iam handlers check are still not seeded, so only the bare wildcard reaches those operations. check_handler_permissions.py derives the codes from the handler files and compares them to iam_permissions_populate.sql; iam is deliberately outside its REGISTRY because of this gap, which means the gate does not protect iam at all. The twelve are iam::account_contact_informations:write and :delete, iam::account_statuses:write and :delete, iam::account_types:write and :delete, iam::sessions:delete, iam::tenants:write, iam::tenant_statuses:write and :delete, and iam::tenant_types:write and :delete. Each is the same shape as the iam::roles:write gap that the bundle write closed: the generated handler asks for the resource's :write or :delete while the seed defines a different action for the same resource (for example iam::tenants:update, which the generated tenant write does not check). The seed is the side to move, because the generator emits <component>::<plural>:write and <component>::<plural>:delete unconditionally for every entity, so a handler cannot be given a different code without a model or template change. Closing all twelve lets iam join the REGISTRY in projects/ores.codegen/scripts/check_handler_permissions.py, after which the gate fails any future iam handler whose code no seed defines. The same audit is worth running for the other components that are still outside the registry. | ||||
| Twenty-four component source lists are stale against the generator | codegen cmake drift component |
regenerate_cmake_component_files.py –all –check wants to change 24 committed component_files.cmake lists across analytics, assets, compute, workspace and others. Every flagged file is byte-identical to origin/main, so the drift is on main and no component's own clean pass has run the generator since its sources moved. | ||||
| Twenty-four generated notify triggers still emit the retired entity_ids payload | codegen eventing sql |
The shared postgres event listener parses every notification as the canonical entity_event_notification and returns on a parse failure, so the fifteen refdata, eight trading and one dq notify triggers that still emit the retired entity_ids payload drop every entity event for those tables. PR 3 regenerated marketdata's six, which is the one component under test; the other three need the same regeneration. | ||||
| Two components register the same shell command name, and the… | Two components register the same shell command name, and the first registration wins. The DQ shell part registers a menu called report_definitions through dq_commands::register_commands (repl.cpp:105), and the reporting part registers its own report_definitions menu later (repl.cpp:116). The DQ one takes precedence, so the reporting entity's shell commands are unreachable: a request for report_definitions list arrives at the DQ service as dq.v1.report_definitions.list, and the recipes generated for reporting's signatures are rejected by the DQ menu with 'Expected 8 arguments, got 9'. Nothing detects a duplicate menu name. Evidence: projects/ores.shell/application/src/app/repl.cpp:105 and :116, projects/ores.shell/application/src/app/commands/dq/dq_commands.cpp:48, and the reporting service log, which shows no request while the DQ service log shows the query. | |||||
| Two generated inventories are stale in components outside the test list | codegen gate defect |
regenerate_cmake_component_files.py –all –check reports ores.synthetic, ores.utility and ores.workspace stale, and regenerate_physical_space_inventories.py –check reports ores.doc.http-recipe.org stale. All four are pre-existing on main and none is in COMPONENTS_UNDER_TEST, which is why no gate is red. | ||||
| Two parties' bond configs name one security and mean two issues | The population aborts writing a bond issue that a second config already stored, because a security's name states currency, term and product but not the party whose issuer it names. Two legal entities of one tenant therefore share a security id and disagree about its issuer, and the store refuses the second write. | |||||
| Two populate scripts were never wired into a recreate | scheduler_populate.sql seeds an MQ statistics scrape job and trading_sample_data_populate.sql books demonstration trades, but no root script includes either, so no database has ever had them. Decide whether to wire each one or delete it. | |||||
| Two protocol headers have no TypeScript twin (resolved) | codegen typescript gates |
Resolved: the blotter takes the trade summaries filter, and the market regime has a model. The protocol-twins check fails on main. The blotter model opts out because codegen cannot project a message type from another protocol, and the market regime protocol header has no model at all. | ||||
| Unify legal entity identity and model the calculation agent | trading refdata identity |
Two related gaps found while documenting trade modelling: a trade role cannot name one of our own legal entities, so the common case of the booking party being calculation agent is unrepresentable; and the dispute consequence that follows from designating a calculation agent is recorded nowhere. | ||||
| Use the free public volatility indices as calibration source… | Use the free public volatility indices as calibration sources for the vol surfaces of other asset classes. FX has no free implied vol source (checked 2026-11-03 in the task Document the volatility surface architecture), but some asset classes have a published index. FRED carries Cboe indices such as VIX (VIXCLS, equity), and Cboe also publishes indices for oil, gold, emerging markets and longer equity horizons; check which FRED carries today and which are discontinued. Each FRED Cboe series is marked Copyrighted: Citation Required, and its storage terms are unread, so read Cboe's and FRED's terms before any fetcher stores a value. The ICE BofA indices on FRED, MOVE among them, forbid reproduction without ICE's written permission and keep only three years of observations, so they are out. An index is a single implied vol level, so at best it sets the ATM level of one tenor; the shape still comes from the derived calibration source. A fetcher for FRED needs an API key, which the public sources adapter keeps under its secrets. | |||||
| Value a trade against a market snapshot | trading web valuation pricing structure snapshot |
The structure page's Price tab is a valuation, and the product has none: nothing values a trade, a leg or a structure, so the tab states the gap. When valuation arrives it answers a figure, the market snapshot the figure was struck against and when that snapshot was read, for a structure as a whole and for a package leg by leg. | ||||
| View a report's runs from its definition screen | The report definition screen says what a report is configured to run, but not what it has actually run. There is no way to walk from a definition to its runs, so a person who has just changed a definition cannot see whether the next run behaved, and a person investigating a failure starts from the grid's job list instead of from the report. | |||||
| Wait for the services' connections to close before the database recreate drops it | compass database check |
The gate's db check runs services stop and then db recreate, and the drop can fail with 'database is being accessed by other users' because a stopped service's session is still open, which leaves the old schema in place and fails every database suite after it. | ||||
| What a time series plot must do | reporting plotting timeseries ux web |
The owner's three requirements for a time series plot: the window's high, low and change in the header with the high and the low marked on the plot, statistics for a selected range with a crosshair readout, and overlays with a difference mode. Captured as requirements and not as a design. Neither reporting prototype meets any of the three, and no plotting work is scheduled. | ||||
| What is a trade's size across asset classes? | The structure page drew a notional column because the prototype draws one. A bond states a notional, a rate trade states an amount per leg, an FX trade states bought and sold amounts, and the families cannot be read by one rule. What should a screen state as a trade's size, if anything? | |||||
| Workflow recovery fails on test tenants left by ctest | workflow testing |
A fleet started on a database the full ctest run used logs a recovery error for every open workflow instance of an inactive test tenant, and a step-deadline error for every test workflow; a clean database logs none. | ||||
| Workflow tests leave in-progress runs behind in every database they touch | workflow tests hygiene |
The workflow test suites create runs in a per-run tenant and never remove them; terminating the tenant closes the tenant row but leaves its workflow instances and steps in progress. The dev database had 102 such runs, and every workflow service restart re-dispatches all of them. | ||||
| World data versus party configuration | synthetic party refdata conventions |
Split the data into world data, which every party sees the same, and party configuration, which each party owns; synthetic data writes only world data. | ||||
| Write a currency pair and its convention together, and check the pair code | refdata fx currency_pairs |
The pair and its one-to-one convention are two writes, the pair code is not checked against its legs, and the pair list cannot be filtered by currency. | ||||
| Write books without an approval request where no approval is needed | refdata approval ore import sandbox |
Every book write now passes an approval gate, so the ORE import cannot create the books it imports into, and a sandbox import fails the same way. A sandbox, and any context that needs no four-eyes control, must be able to write books directly. | ||||
| Write the rest of a booked trade | trading booking |
The instrument writer leaves three gaps: the bond remainder members, the child-to-header check and the round trip for every family. Close them so book_trade writes whatever the export reads. |