Skip to content

Commit c0777ed

Browse files
committed
[fix.ci.ρ.D8+] align contracts, docs, and clean-schema vocabulary
The failed CI run exposed four independent drift classes: public error unions omitted the idempotency conflict, the route-hook test accidentally required NumPy, documentation and twin semantics still used retired registry fields, and app.object_kind lagged the canonical scientific vocabulary by thirty values. This commit closes each at its authoritative boundary and adds migration 048 rather than rewriting released history.
1 parent 1c8992f commit c0777ed

12 files changed

Lines changed: 151 additions & 49 deletions

‎ARCHITECTURE.md‎

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Invocation kernel
2020
│ │ │
2121
│ │ └─ Inline / Thread / Process / Remote
2222
│ └─ field cache + generic method-version result cache
23-
└─ 28 executable scientific Methods
23+
└─ 30 executable scientific Methods
2424
│
2525
┌──────────┼──────────┐
2626
▼ ▼ ▼
@@ -90,7 +90,7 @@ PostgreSQL is the durable authority:
9090
- `app.command_trace` and `app.v_command_observation` retain semantic-command outcomes,
9191
latency, cache, actor and linked-Job evidence for the architecture twin.
9292

93-
Migrations are forward-only and content-hash checked. Migrations 000–038 are the
93+
Migrations are forward-only and content-hash checked. Migrations 000–048 are the
9494
current schema history.
9595

9696
## Client application
@@ -101,12 +101,63 @@ the separate truth for connected scientific capability. `AppShell` owns routing
101101
`ScientificContextStore` owns Program, focus, selection and the application's only
102102
staleness generation; `SceneService` owns one mol* instance that survives navigation.
103103

104-
Twelve of thirty Views currently expose connected modules across Programs, Design,
104+
Thirteen of thirty Views currently expose connected modules across Programs, Design,
105105
Structures, Campaigns, Synthesis, Experiments, Knowledge and Runs. Existing chemistry
106106
facets are modules over the shared scene and context. Molecule embedding, fields,
107107
surface MEP and torsion strain enter through semantic commands; long results return by
108108
Job and content-addressed artifacts.
109109

110+
The browser has two explicit runtime tiers built from one shared ESM graph. `shell.ts`
111+
boots routing, context, commands, theme and human-facing Workspace projections without
112+
importing mol* or RDKit. The first in-app navigation to a Scene route dynamically imports
113+
the molecular runtime without replacing the document; later Workspace and Scene changes
114+
reuse that module and the single `SceneService` instance. Program, ML, voice and
115+
scientific-chart code remain route- or visibility-owned chunks. Both the RDKit JavaScript
116+
bootstrap and WASM binary are fetched only when a chemistry-dependent surface is opened.
117+
The module registry projects real facet surfaces directly—there is no module-host or
118+
view-state adapter between the registry and the DOM. Production bundles also omit the
119+
generated-command integrity walk: that invariant is enforced by build and test gates.
120+
121+
Desktop navigation owns one browser-local expanded/collapsed preference through the
122+
`RailController`; the responsive mobile rail deliberately ignores that desktop geometry.
123+
This is presentation state only and never enters Program, scientific-context or evidence
124+
records.
125+
126+
Background work is visibility-aware and single-owner. The shell coalesces Program
127+
refreshes and publishes one state event to Workspace and Compute projections; hidden
128+
legacy surfaces are not populated. Off-screen graphs, charts and Gantt views defer both
129+
their runtime download and rendering. The ML control-room refresh loop suspends in hidden
130+
tabs, refreshes volatile Jobs and attention every 15 seconds, refreshes capability
131+
metadata on a five-minute/manual cadence, and fingerprints snapshots before replacing
132+
the DOM. Palette updates subscribe to scene state instead of polling. Chemistry results
133+
have one generation-aware cache that is invalidated on molecule, ligand-target and
134+
cutoff changes, preventing both repeated WASM work and stale cross-molecule facets.
135+
136+
Three cross-cutting human layers deepen the existing Views without creating new product
137+
surface area. The Journey Rail projects one durable Program and Work Item across
138+
Question, Understand, Design, Decide, Make, Test and Learn; it delegates its visible
139+
"next" action to the existing governed handoff controller rather than bypassing command
140+
preconditions. The lazily loaded Evidence Inspector classifies a selected record as
141+
observed, computed, inferred, proposed or unresolved, then reports missing identity,
142+
observation time, method version, frozen inputs, provenance, artifacts, digest declaration
143+
and evidence boundary without upgrading presence into validation. Program disclosures and
144+
the comfortable/compact density preference are browser-local reading state, never durable
145+
scientific state.
146+
147+
The shell also carries one five-level reading contract across every Workspace and the ML
148+
control room: **Signal (1) → Visual (2) → Structured (3) → Explanation (4) → Audit (5)**.
149+
This is explicit component metadata rather than an inferred font-size heuristic. `Scan`
150+
prioritizes state and visual flow, `Work` balances canonical records with explanation, and
151+
`Audit` opens provenance and raw records. The preference is browser-local. No mode deletes,
152+
hides, reclassifies, or mutates scientific evidence; high-difficulty material remains
153+
keyboard reachable through progressive disclosure.
154+
155+
The all-route performance gate covers the thirty routable Views. The 2026-08-13 local
156+
matrix verified a roughly 943 KB cold payload for non-scene routes, four font files per
157+
route, no eager RDKit payload, no eager scientific-visual payload on ordinary Workspace
158+
routes, and no initial long task on the Program overview. Scene routes deliberately pay
159+
the mol* runtime cost; that boundary is kept separate from the compact application shell.
160+
110161
## Runtime topology
111162

112163
- `dirac-fields.service` on `:8901` is the one application/scientific control plane.
@@ -148,7 +199,7 @@ rebuilds. The model can therefore calibrate observed command latency and outcome
148199
addition to detecting drift, ranking static hotspots and estimating dependency radius.
149200
It still cannot predict unseen inputs or autonomously change the architecture; that is
150201
the L4 boundary. The platform substrate is complete against its approved DoD; the
151-
product capability is explicitly partial (currently 8/8 Workspaces represented and 12/30 Views connected)
202+
product capability is explicitly partial (currently 8/8 Workspaces represented and 13/30 Views connected)
152203
even though the navigable product shell is complete at 8/8 and 30/30.
153204

154205
`scripts/digital_twin_scope.json` is the ownership boundary. The watcher recursively

‎README.md‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ parts of one scientific decision system rather than separate tools.
8282

8383
## Construction status
8484

85-
Dirac currently defines 8 stable Workspaces and 30 routable Views, of which 12 are
86-
connected to working modules. The contract layer contains 79 versioned semantic Commands
87-
over 83 canonical ObjectKinds and 28 scientific Method manifests behind one invocation
85+
Dirac currently defines 8 stable Workspaces and 30 routable Views, of which 13 are
86+
connected to working modules. The contract layer contains 92 versioned semantic Commands
87+
over 83 canonical ObjectKinds and 30 scientific Method manifests behind one invocation
8888
path. PostgreSQL owns Programs, Jobs, attempts, artifacts, relations, provenance and
8989
execution control.
9090

@@ -148,8 +148,11 @@ npm run build:dirac
148148
node_modules/.bin/http-server build/dirac -p 1360 -g -c-1 -a 0.0.0.0 -P http://127.0.0.1:1360?
149149
```
150150

151-
Open <http://localhost:1360/>. The first load fetches the vendored RDKit WASM bundle;
152-
after that the browser cache supplies it.
151+
Open <http://localhost:1360/>. Workspace, Knowledge, Runs and ML routes load the compact
152+
application shell only. Molecular scene routes load mol*; the RDKit JavaScript bootstrap
153+
and WASM binary are fetched only when a chemistry-dependent surface or semantic layer is
154+
opened. Program, ML, voice and scientific visual runtimes are split and loaded only by
155+
the route or visible surface that owns them.
153156

154157
On the canonical workstation, **do not run that server command**: `dirac-web.service`
155158
already owns the one allowed web port, 1360. Rebuild with `npm run build:dirac` and reload

‎STATUS.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ validation. A green contract or transport gate does not validate a scientific mo
1111
| Capability | Current evidence |
1212
|---|---|
1313
| Canonical domain | 83 ObjectKinds and 27 controlled relation kinds; ObjectRef types generated for Python and TypeScript |
14-
| Semantic Commands | 79 registered Commands with schemas, actor identity, mutation policy, required-Job policy and typed errors |
15-
| Scientific Methods | 28 Method manifests behind one InvocationService |
16-
| Durable schema | 39 forward-only migrations, `000` through `038` |
14+
| Semantic Commands | 92 registered Commands with schemas, actor identity, mutation policy, required-Job policy and typed errors |
15+
| Scientific Methods | 30 Method manifests behind one InvocationService |
16+
| Durable schema | 49 forward-only migrations, `000` through `048` |
1717
| Product shell | 8 Workspaces and 30 routable Views |
18-
| Connected UI | 12 of 30 Views connected to 15 composable modules; the remaining 18 are explicit shells |
18+
| Connected UI | 13 of 30 Views connected to 17 composable modules; the remaining 17 are explicit shells |
1919
| Interfaces | HTTP v2, Python SDK, CLI and generated safe MCP projection share the command boundary |
2020
| Execution | durable JobStore plus inline, thread, process, local GPU and Kubernetes/Kueue adapters |
2121
| Results | content-addressed artifacts, method-current caches, provenance and command observations |
@@ -66,7 +66,7 @@ those present files and contracts; they should not be interpreted as a release t
6666
## Scope verdict
6767

6868
The command/method/job/artifact substrate and the complete navigation shell exist. The
69-
product remains partial: 12/30 Views are connected, application-grade HCI action semantics
69+
product remains partial: 13/30 Views are connected, application-grade HCI action semantics
7070
are still being migrated, and individual scientific Methods need method-specific validation
7171
before prospective claims can be made. Workflow completeness and scientific validity are
7272
separate acceptance gates.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
-- 048 · align the public ObjectKind vocabulary with scientific durable objects.
2+
--
3+
-- Scientific Motif objects were introduced behind a domain-specific enum in
4+
-- 037. Public ObjectRef validation is governed by app.object_kind, so the two
5+
-- vocabularies must contain the same canonical values exposed by
6+
-- contracts/domain/object-kinds.json.
7+
BEGIN;
8+
9+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'protein_structure_source';
10+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'prepared_receptor_state';
11+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'binding_site_hypothesis';
12+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'complex_hypothesis';
13+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'pose_hypothesis';
14+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'pose_ensemble';
15+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'conformer_ensemble';
16+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'conformer_hypothesis';
17+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'submitted_compound_record';
18+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'chemical_entity';
19+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'chemical_state_ensemble';
20+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'chemical_microstate';
21+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'parameterized_system';
22+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'simulation_run';
23+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'free_energy_transformation';
24+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'evidence_item';
25+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'evidence_snapshot';
26+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'method_run';
27+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'method_outcome';
28+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'quality_assessment';
29+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'routing_action';
30+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'decision_snapshot';
31+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'resource_lease';
32+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'method_release';
33+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'policy_release';
34+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'condition';
35+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'assumption';
36+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'transformation';
37+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'dataset_snapshot';
38+
ALTER TYPE app.object_kind ADD VALUE IF NOT EXISTS 'model_release';
39+
40+
INSERT INTO meta.migration (filename,sha256,content_sha256,hash_source)
41+
VALUES ('048_object_kind_scientific_alignment.sql','\xeedc2d832ba50a8870535cb02b5e3c77588edff80fba28de21026a91228ab26f'::bytea,
42+
'\xeedc2d832ba50a8870535cb02b5e3c77588edff80fba28de21026a91228ab26f'::bytea,'content')
43+
ON CONFLICT (filename) DO NOTHING;
44+
45+
COMMIT;

‎backend/tests/test_execution_identity.py‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def capture_invoke(_method_id, queued_payload, **kwargs):
210210

211211
def test_stateful_route_hook_is_called_once_per_admission(self):
212212
from catalog import MethodCatalog
213-
from invocation import InvocationService
213+
from invocation import HandlerResult, InvocationService
214214

215215
class StatefulExecutor:
216216
kind = "remote"
@@ -229,7 +229,16 @@ def execute(fn, *args):
229229

230230
executor = StatefulExecutor()
231231
service = InvocationService(MethodCatalog.load(), executor=executor)
232-
result = service.invoke("molecule.embed", {"smiles": "CCO"})
232+
handler_result = HandlerResult(result={
233+
"molecule": {
234+
"kind": "molfile",
235+
"content": "stateful route test molfile content" + " " * 16,
236+
"dimensionality": 3,
237+
}
238+
}, artifacts=[("molecule.molfile", b"stateful route test molfile")])
239+
with mock.patch("catalog.MethodSpec.handler",
240+
return_value=lambda _payload, _ctx: handler_result):
241+
result = service.invoke("molecule.embed", {"smiles": "CCO"})
233242
self.assertTrue(result["ok"])
234243
self.assertEqual(executor.calls, 1)
235244
self.assertEqual(result["meta"]["execution_identity"]["executor_adapter"],

‎contracts/iface.d.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export type ErrorCode =
1717
| 'BAD_HOST' | 'CANCELLED' | 'INTERNAL' | 'NOT_FOUND'
1818
| 'DB_UNAVAILABLE' | 'AUTH_REQUIRED' | 'FORBIDDEN'
1919
| 'RATE_LIMITED' | 'QUOTA_EXCEEDED' | 'TLS_REQUIRED'
20-
| 'INVALID_PARAMETERS';
20+
| 'INVALID_PARAMETERS' | 'IDEMPOTENCY_CONFLICT';
2121

2222
/** Discriminated union — a molfile alone is lossy (frontend review, blocker 3). */
2323
export type Ligand =

‎contracts/iface.pyi‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ErrorCode = Literal['PARSE', 'UNCONVERGED', 'UNPARAMETERIZED', 'BUDGET',
1616
'BAD_HOST', 'CANCELLED', 'INTERNAL', 'NOT_FOUND',
1717
'DB_UNAVAILABLE', 'AUTH_REQUIRED', 'FORBIDDEN',
1818
'RATE_LIMITED', 'QUOTA_EXCEEDED', 'TLS_REQUIRED',
19-
'INVALID_PARAMETERS']
19+
'INVALID_PARAMETERS', 'IDEMPOTENCY_CONFLICT']
2020
JobState = Literal['queued', 'running', 'done', 'failed', 'cancelled'] # seam: app.job (PLANNED)
2121

2222
class EmbedMeta(TypedDict):

0 commit comments

Comments
 (0)