feat(observatory): add portable calculation profiles
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
# ADR 0047: Verified portable Observatory result publication
|
||||
|
||||
Date: 2026-08-31
|
||||
Status: accepted as a backend foundation; production validators, transport and
|
||||
executor wiring remain blocked
|
||||
|
||||
## Context
|
||||
|
||||
The durable Observatory queue deliberately treats a Worker `succeed` call as a
|
||||
transport acknowledgement. Its `result_id` and SHA-256 do not prove that an
|
||||
artifact exists, that it was computed from the admitted source, that it obeys
|
||||
the selected RunDefinition, or that it has observation-only authority. Publishing
|
||||
that acknowledgement directly as a LAB session would let incomplete, corrupt or
|
||||
mislabelled output enter the same catalog as immutable evidence.
|
||||
|
||||
The current canonical LAB V1 result is a separate preserved legacy result. It
|
||||
must not be reinterpreted as a portable v2 result, rewritten with new provenance,
|
||||
or used as evidence that the portable executor exists.
|
||||
|
||||
## Decision
|
||||
|
||||
Portable results cross a new backend-only verification boundary implemented in
|
||||
`k1link.observatory.portable_result_contract` and
|
||||
`k1link.observatory.portable_result_publisher`. The boundary does not change the
|
||||
queue, the source-admission service, Session API, setup projection, UI, K1,
|
||||
Simulation, or the legacy canonical publisher.
|
||||
|
||||
A Worker-side assembler must produce one directory whose basename is the
|
||||
SHA-256 of its canonical `manifest.json`. The manifest schema is
|
||||
`missioncore.observatory-portable-result-package/v1`; JSON bytes are canonical
|
||||
UTF-8 with sorted keys and no insignificant whitespace. Its separately hashed
|
||||
identity binds:
|
||||
|
||||
1. queue `job_id`, request identity, execution identity, submission receipt and
|
||||
claim generation;
|
||||
2. source Session, catalog snapshot, source bundle, capability manifest and
|
||||
source-adapter identities;
|
||||
3. the complete portable RunDefinition identity, including source requirements,
|
||||
components, models, resource profile, result contract, executor and authority;
|
||||
4. result id, result schema, result kind and result-contract SHA-256;
|
||||
5. a canonical, role-sorted artifact list with confined relative paths, media
|
||||
types, byte lengths and SHA-256 identities;
|
||||
6. observation-only authority.
|
||||
|
||||
Exactly one non-empty `result-document` JSON artifact is required. Package roots,
|
||||
the manifest, every path component and every artifact are checked without
|
||||
following symlinks outside the package. The queue's terminal result SHA must equal
|
||||
the canonical manifest SHA and the package directory name.
|
||||
|
||||
Before catalog publication, the server also:
|
||||
|
||||
- resolves the exact `(setup_id, definition_sha256)` in the portable registry and
|
||||
proves every recorded queue field equals the resulting RunDefinition;
|
||||
- rejects not-installed executors and the reserved legacy
|
||||
`lab-v1-vegetation-shadow-<sha256>` namespace;
|
||||
- rechecks the current SessionStore catalog snapshot;
|
||||
- reads both source-admission documents from
|
||||
`observatory-portable-source-contracts/<sha256>.json`, verifies their bytes,
|
||||
schemas, cross-links, adapter, source and authority;
|
||||
- invokes a validator registered by exact result-contract SHA-256;
|
||||
- copies the package manifest and all output artifacts into the central immutable
|
||||
content-addressed artifact store and records its manifest id;
|
||||
- publishes one idempotent `LabSessionBinding` through `SessionStore`.
|
||||
|
||||
There is intentionally no generic “JSON looks plausible” validator. An unknown
|
||||
result contract fails before artifact-store or SessionStore mutation. A validator
|
||||
must understand the exact result schema and determine that the result document
|
||||
and supporting artifacts are accepted evidence.
|
||||
|
||||
## Calculation-profile provenance
|
||||
|
||||
The publisher does not read a browser selection or infer a profile from a result
|
||||
name. It requires a server-owned policy bound to the exact definition id, version
|
||||
and SHA-256. The resulting immutable provenance contains
|
||||
`missioncore.observatory-calculation-profile/v1` with:
|
||||
|
||||
- `setup_id`;
|
||||
- full display name;
|
||||
- origin `archived-definition`;
|
||||
- definition id, version and SHA-256.
|
||||
|
||||
It also stores a SHA-256 of that calculation-profile document. A later Session API
|
||||
projection can therefore read `calculation_profile` from the result's provenance
|
||||
instead of reporting whichever setup happens to be selected now.
|
||||
|
||||
No replay capability is invented. The portable result package is preserved in
|
||||
the central artifact store, while a result-schema-specific viewer/replay adapter
|
||||
must be accepted separately before the catalog binding can claim visual replay.
|
||||
|
||||
## Current fail-closed blockers
|
||||
|
||||
The publisher and focused contract tests are implemented, but the end-to-end
|
||||
production loop remains unavailable for concrete reasons:
|
||||
|
||||
1. neither `recorded-eomt-ddrnet-review-v2` nor
|
||||
`m49-tgs-portable-review-v2` has an installed exact result-contract validator;
|
||||
2. the current Worker protocol returns only `result_id` and manifest SHA-256; it
|
||||
has no accepted package upload/CAS handoff that gives Mission Core the matching
|
||||
content-addressed directory;
|
||||
3. portable executor releases that emit this package contract are not installed
|
||||
and physically accepted on Worker 006;
|
||||
4. the application has not registered definition-bound calculation-profile
|
||||
publication policies or wired the publisher into the terminal Worker flow;
|
||||
5. no result-schema-specific replay-capability adapter has been accepted.
|
||||
|
||||
These are explicit blockers. The backend must not fabricate a package, reuse a
|
||||
legacy result, trust a Worker success receipt, guess model/profile provenance, or
|
||||
expose an enqueue/result promise to bypass them.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Queue success and Observatory publication remain distinct evidence states.
|
||||
- Exact retry is safe: content-addressed artifact publication and the immutable
|
||||
SessionStore binding are idempotent; a conflicting result id fails closed.
|
||||
- Source, definition, model, resource-profile and calculation-profile identities
|
||||
remain available in one portable provenance document.
|
||||
- Artifact-store writes may leave harmless immutable unreferenced objects if the
|
||||
final SessionStore transaction detects a conflict; they cannot overwrite an
|
||||
existing identity.
|
||||
- The legacy canonical LAB V1 result and its admission logic remain byte-for-byte
|
||||
outside this publisher.
|
||||
Reference in New Issue
Block a user