Story: Workspaces: finish the feature
Table of Contents
This page documents a story in Product backlog — inbox. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
Goal
Finish the workspace feature. Two concrete user-visible outcomes:
- The Live workspace is properly set up and every workspace-aware entity behaves correctly under it (the default, always-on data context every user starts in).
- Users can create stand-alone / temporary workspaces – isolated, named data contexts that inherit from Live but don't pollute it – for use cases like importing ORE samples to explore without touching production data.
This story consolidates every workspace-related capture and story
scattered across the backlog and past sprints (see * Decisions for
the full inventory) into one place, so the feature can be finished as
a single coherent piece of work instead of drip-feeding partial
pieces.
Prior work already done (do not re-do)
- Sprint 17 "Workspace" (../../../versions/v0/sprint_17/workspace/story.org):
bitemporal schema, service layer, CRUD UI, lifecycle operations
(archive/etc), codegen propagation of
workspace_id(Phases 1-4), Data Workshop UI tree (Open/Add/Edit/Archive/Delete). DONE. - Sprint 18 "Add support for running ORE samples" (../../../versions/v0/sprint_18/ore_samples_support/story.org): workspace promoted to a full standard entity (history, generated detail dialog); ORE sample import creates a named, isolated workspace end-to-end (Track 1 of the original import-tracks design); Data Import Session window; results surfaced back in the workspace context. DONE.
- Sprint 20 codegen org-model migration for the workspace model. DONE.
- Sprint 23 workspace history-dialog migration to the generic
HistoryDialog. ABANDONED – superseded by the Qt-commissioning task folded into this story (see Tasks).
Current architecture (already implemented, see
projects/ores.workspace/core/modeling/multi_workspace.org): Live
workspace is a per-tenant row using the well-known sentinel UUID
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa, seeded automatically for every
tenant; workspace hierarchy/inheritance resolution via a recursive
CTE; three-tier permission model; session-wide (not yet per-window)
workspace activation in the Qt client.
What's explicitly NOT done yet (the actual gap)
- Track 2 – production live trade import: Pending Book,
is_livemarkers on reference data, a generalised Data Import Session UI (FpML/CSV/manual sources, not just ORE XML), apendingtrade FSM state, and the booking/promotion workflow that moves a trade from a temporary holding area into the Live workspace. Fully designed in Data Import Session and Workflow Partial-Success (STATUS: MINED, but only Track 1 was ever converted into shipped work – Track 2 was explicitly out of scope of the Sprint 18 story) – never implemented. This is the connection point with the Trade Blotter story below: a temporary holding location for trades before they are "promoted" into the Live workspace. - Per-window workspace selector (side-by-side comparison of the same data under two workspaces) – deferred/future in the architecture doc.
- "Clone to workspace" action on report definitions – unchecked in the original design's Phase 4.
- Workspace storage/size reporting (Baobab-style visualisation) – open question, deferred.
- Whether every workspace-impacted entity actually has full, consistent, codegen-generated workspace-aware UI/service/repo support (vs. hand-patched per entity) is unknown – this is exactly what the audit task below establishes.
Status
| Field | Value |
|---|---|
| State | STARTED |
| Parent sprint | Product backlog — inbox |
| Now | Trading instrument codegen pilot landed (equity_position_instrument); the three instrument-port tasks have been re-parented to the Port trading instruments to codegen story in Sprint 25 (see Decisions). |
| Waiting on | Nothing directly. |
| Next | Continue workspace-specific follow-ups (audit-driven items); instrument conversions now track in their own story. |
| Last touched | 2026-08-08 |
Acceptance
- Code audit complete: every entity that should be workspace-aware is inventoried, along with whether it has codegen-generated workspace-scoping support (analogous to the existing pagination/page codegen support) or hand-patched support, and what common hand-crafted logic exists that codegen should absorb so new entities get workspace support automatically.
- Live workspace confirmed correct end-to-end for every
workspace-aware entity (no silent fallback bugs, no entity that
forgot the
workspace_idcolumn or query filter). - Users can create a stand-alone/temporary workspace and import ORE samples into it without touching Live data (this already works per Sprint 18 – acceptance here is confirming it still holds and is not regressed, plus closing the open codegen-drift/commissioning follow-ups below).
- The three open codegen follow-up items are resolved: workspace
entity model drift fixed, workspace-cpp safe drift applied
(
has_party_id+ hand-crafted service/repository/protocol restored correctly), andores.qt.workspacefully commissioned into codegen.
Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Audit: current state of the workspace feature (backend + UI) | DONE | 2026-08-04 | 2026-08-04 | Establish where we actually are before scoping further workspace work: inventory every entity impacted by workspace_id, whether it has a codegen-generated workspace-aware widget (analogous to page/pagination support), what is hand-crafted vs generated, and what common hand-crafted logic should be pulled into codegen so future entities get workspace support for free. |
| Upgrade repository template: exact-match workspace_id to resolution-order inheritance | DONE | 2026-08-04 | 2026-08-05 | The cpp_domain_type_repository.cpp.mustache has_workspace_id block generates workspace_id == wid (exact match) instead of workspace_id = ANY(:resolution_order) with DISTINCT ON deduplication – so single-parent workspace inheritance, the headline feature of the whole design, does not function for any entity today. Upgrade the template and re-verify against every one of the 21 currently-covered entities. |
Decisions
- Three pre-existing tasks are left in place under their current
parent stories rather than re-parented here (re-parenting would
break their branch metadata and blocked_on links) – tracked as
in-flight component work this story depends on:
- Fix workspace entity model drift (Codegen developer experience improvements story) – mirrors the refdata drift-fix that succeeded; now unblocked.
- Apply safe drift to workspace-cpp (Refactor ores.codegen C++
generation story, Sprint 25) –
has_party_idflag, restore hand-crafted service/repository/protocol. ItsWaiting onstill points at a stale pilot-task reference; needs re-triage when picked up (the pilot's real-world equivalent – refdata's zero-diff drift – is already achieved via a different, superseding initiative). - Commission ores.qt.workspace into codegen (own inbox story) – inventory ores.qt.workspace entities, run full-stack codegen, migrate history dialogs to the generic HistoryDialog.
- Audit complete (see the audit task's
* Result=/=* Notesfor full detail). Corrects the initial hypothesis above: there is no missing Qt-side codegen flag to build, unlike pagination – workspace scoping is already generic and shared at the network layer (WorkspaceContext=/=EntityController=/=ClientManagerinjectingX-Workspace-Idon every request), so every Qt widget is workspace-aware for free regardless of whether its entity is hand-crafted or generated. The real, per-entity gap is entirely in the service/repository query layer:- Of 46 tables carrying
workspace_id, only 21 have codegen coverage (13 raw flag + 8 via theworkspace-scoped-lookupprofile); 25 don't, includingbook=/=portfolio(models exist, flag was simply never added) and ~20 hand-crafted trading instrument sub-types with no model at all. Correction (found while landing the inheritance-query fix, PR #1846): this was wrong aboutbook=/=portfolio– both use thefk-scoped-childprofile, whose own defaults sethas_workspace_id: true. The original audit only checked the raw flag and theworkspace-scoped-lookupprofile by name, missing that other profiles supply the same default. Corrected count: 23 tables genuinely uncovered (all ~20 hand-crafted trading instrument sub-types), not 25. - Biggest finding: the
has_workspace_idrepository template generates an exact-match predicate, not the resolution-order inheritance query the architecture doc describes as the target design – so single-parent inheritance, the headline feature of the whole concept, does not function for any entity today. - Two follow-up tasks filed to close these: fixing the inheritance query (affects all 21 covered entities equally, likely the higher- priority one), and backfilling the 25-table coverage gap.
- Of 46 tables carrying
- Inheritance-query fix landed (see the task's
* Result=/=* Notesfor full detail). Fixed the template's list-all method to useworkspace_id IN (chain)when a resolution chain is set (the end-to-end plumbing for this already existed and needed no changes). Verified against the 8 profile-based refdata convention entities: zero-diff regen, clean build, all tests pass including a new permanent test proving inheritance actually works.- The 13 trading
has_workspace_identities could not be regenerated/verified in this pass: their models use a legacy primary-key heading format a separate, already-tracked task (Fix legacy Primary key heading blocking codegen regen on 70+ models) is responsible for fixing repo-wide. The template fix itself is generic and needs no further work – once that prerequisite lands, regenerating those 13 entities picks up inheritance automatically. reporting.report_definitionhas its own hand-writtenread_latest_with_resolution(a per-workspace loop + name-based dedup, appropriate for its name-keyed override semantics) – left untouched; could be migrated onto the now-fixed generated path as a small separate cleanup, not required.
- The 13 trading
- Trading instrument sub-type codegen decision (see the task's
* Resultfor full detail): decided to bring the ~20 hand-crafted trading instrument sub-types under codegen rather than accept them as permanently hand-crafted. Proven via anequity_position_instrumentpilot: zero-diff regen across every facet, full build green, all tests pass. Found and fixed three genuine, systemic codegen bugs along the way that affect every identity/audit-field-group-nested entity (not just this one): the generator facet never implemented field-group nesting; primary-key columns didn't inherit the identity-group flag in core.py; the service facet never generated a batch-get wrapper despite the repository supporting one. Follow-on task filed to convert the remaining ~19 entities, most of which additionally need task 836BB4CE (legacy Primary key heading) landed or worked around per-entity first. - Instrument-port tasks re-parented (2026-08-08): the three
instrument-codegen tasks this story carried – the decision/pilot
(Decide fate of ~20
hand-crafted trading instrument sub-types missing codegen models),
the conversions (Convert
remaining ~19 hand-crafted trading instrument sub-types to codegen
models), and the NATS eventing facet work
(Wire NATS eventing
templates into codegen and generate DB-write-to-NATS integration
tests) – moved UUID-intact via
compass task moveinto the new Port trading instruments to codegen story in Sprint 25, where the bulk of the work now tracks. This story keeps its workspace-specific tasks (audit, inheritance query). The decision record itself stays here as history.
Out of scope
- Track 2 / production live trade import mechanics themselves – tracked in the separate, dependent Trade Blotter story.