tracegrove 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,199 +0,0 @@
1
- {
2
- "schemaVersion": "workflow.portable-environment-profile/v1",
3
- "ref": {
4
- "id": "example.profile.alongside_runner",
5
- "revision": "1",
6
- "digest": {
7
- "algorithm": "sha256",
8
- "hex": "e4996a6cd34d28fdecc35d1b6fbef4b7e38301c7133137a43d833d1833e53e56"
9
- }
10
- },
11
- "scope": {
12
- "ownerId": "example.owner",
13
- "tenantId": null,
14
- "visibility": "owner_private"
15
- },
16
- "sourceSelectionRef": {
17
- "id": "example.source-selection",
18
- "revision": "1",
19
- "digest": {
20
- "algorithm": "sha256",
21
- "hex": "ab392664423be621da6bb048313f6531356bd96333edb3938dce0b97cad0f277"
22
- }
23
- },
24
- "buildRef": {
25
- "id": "example.build",
26
- "revision": "1",
27
- "digest": {
28
- "algorithm": "sha256",
29
- "hex": "7e261d3ba9878d05db4c5c6baa3e4a2db1a584c3d2f5f0628b4a1c78f43f5e42"
30
- }
31
- },
32
- "configurationRef": {
33
- "id": "example.non-secret-config",
34
- "revision": "1",
35
- "digest": {
36
- "algorithm": "sha256",
37
- "hex": "74afc8ef6b145b02ec9bb478dfdefdadb225fc6f7c6a729760b525ca83476e55"
38
- }
39
- },
40
- "target": {
41
- "mode": "alongside_runner",
42
- "workspaceRef": {
43
- "id": "example.workspace",
44
- "revision": "1",
45
- "digest": {
46
- "algorithm": "sha256",
47
- "hex": "8e1f432465350d78268d8b77cee90f0715de9e46a650df4235f2a74894fa52b1"
48
- }
49
- },
50
- "hostPlanRef": {
51
- "id": "example.host-plan",
52
- "revision": "1",
53
- "digest": {
54
- "algorithm": "sha256",
55
- "hex": "bc6a1e45f33b36d86dbce570145d739f81e757d620e6a973f641905ad11aff21"
56
- }
57
- },
58
- "launchRecipeRef": {
59
- "id": "example.launch-recipe",
60
- "revision": "1",
61
- "digest": {
62
- "algorithm": "sha256",
63
- "hex": "ea08051425f1b814abb6bc69d036429beb70df5b2a142f94bd1dcfe3df7cabd4"
64
- }
65
- }
66
- },
67
- "endpoints": [
68
- {
69
- "id": "app",
70
- "resolverRef": {
71
- "id": "example.app-endpoint",
72
- "revision": "1",
73
- "digest": {
74
- "algorithm": "sha256",
75
- "hex": "a6b3d24ad9a0af002a55a8ac10805e763bedd7b3e5fc0a714a3d59fecc129b81"
76
- }
77
- },
78
- "source": "launch_reported"
79
- }
80
- ],
81
- "readiness": {
82
- "endpointId": "app",
83
- "path": "/health",
84
- "method": "GET",
85
- "expectedStatus": 200,
86
- "timeoutMs": 20000
87
- },
88
- "capabilities": [
89
- {
90
- "id": "surface.http",
91
- "version": 1,
92
- "required": true
93
- }
94
- ],
95
- "dependencyPlanRefs": [],
96
- "personaCredentials": [
97
- {
98
- "personaRef": {
99
- "id": "example.persona.owner",
100
- "revision": "1",
101
- "digest": {
102
- "algorithm": "sha256",
103
- "hex": "6e993a3445b5165be1d544736fadaa7d46d65c63d07ed71b1552bb51a5bd0813"
104
- }
105
- },
106
- "secretRef": {
107
- "id": "example.app-persona-credential",
108
- "revision": "1",
109
- "digest": {
110
- "algorithm": "sha256",
111
- "hex": "e90cf65d59c84838c7dd77bec933794873024e2c93cf8252a4079e494a04c4f8"
112
- }
113
- }
114
- }
115
- ],
116
- "executionPolicyRef": {
117
- "id": "example.execution-policy",
118
- "revision": "1",
119
- "digest": {
120
- "algorithm": "sha256",
121
- "hex": "f5150e48ea518c445afe198f0c7d643b4645faaeb4fe3d6d007d79209dc4de59"
122
- }
123
- },
124
- "executionSecretRefs": [],
125
- "network": {
126
- "policyRef": {
127
- "id": "example.network-policy",
128
- "revision": "1",
129
- "digest": {
130
- "algorithm": "sha256",
131
- "hex": "858db25db4c84793dd49f8bce7d12c9900326669c502880e1f5267895119efd2"
132
- }
133
- },
134
- "enforcement": "host",
135
- "inbound": "loopback_only",
136
- "egress": "explicit_allowlist",
137
- "allowedEndpointIds": [
138
- "app"
139
- ]
140
- },
141
- "data": {
142
- "mode": "none"
143
- },
144
- "ownership": {
145
- "leasePolicyRef": {
146
- "id": "example.lease-policy",
147
- "revision": "1",
148
- "digest": {
149
- "algorithm": "sha256",
150
- "hex": "0cc0aa82f73b5bf800d872d90a515772246e60a1f26c0b827c823a1256afb26d"
151
- }
152
- },
153
- "cleanupPlanRef": {
154
- "id": "example.cleanup-plan",
155
- "revision": "1",
156
- "digest": {
157
- "algorithm": "sha256",
158
- "hex": "af70f7ee71e47a2ba88e31da4d90bcf0cd8a991cb24b937245704f17d5f6b1db"
159
- }
160
- },
161
- "cleanupReserveMs": 10000
162
- },
163
- "artifacts": {
164
- "destinationRef": {
165
- "id": "example.artifact-destination",
166
- "revision": "1",
167
- "digest": {
168
- "algorithm": "sha256",
169
- "hex": "86b317ba249de72c702be4390a57b7bcd090aa5fdb086fe16e64479efa4f9fca"
170
- }
171
- },
172
- "durability": "export_required",
173
- "redactionPolicyRef": {
174
- "id": "example.redaction-policy",
175
- "revision": "1",
176
- "digest": {
177
- "algorithm": "sha256",
178
- "hex": "ebe43b36aeba3427ee4be196757f1cc3d4acb47c34f02928f40ed0cf008d0a8c"
179
- }
180
- },
181
- "retentionMs": 86400000,
182
- "maxBytes": 16777216
183
- },
184
- "limits": {
185
- "wallMs": 120000,
186
- "cpu": 1,
187
- "memoryMb": 1024,
188
- "diskMb": 256,
189
- "maxRequests": 100,
190
- "maxBrowserActions": 0,
191
- "maxProviderCalls": 0,
192
- "maxAgentCalls": 0,
193
- "maxSpendCents": 0
194
- },
195
- "allowedReplayModes": [
196
- "fresh_execution",
197
- "evidence_playback"
198
- ]
199
- }
@@ -1,183 +0,0 @@
1
- {
2
- "schemaVersion": "workflow.portable-environment-profile/v1",
3
- "ref": {
4
- "id": "example.profile.external_staging",
5
- "revision": "1",
6
- "digest": {
7
- "algorithm": "sha256",
8
- "hex": "ce613297287d6c80046cf21ea9439ec5cecbd01db2facba9cdd0721e89af5045"
9
- }
10
- },
11
- "scope": {
12
- "ownerId": "example.owner",
13
- "tenantId": null,
14
- "visibility": "owner_private"
15
- },
16
- "sourceSelectionRef": {
17
- "id": "example.source-selection",
18
- "revision": "1",
19
- "digest": {
20
- "algorithm": "sha256",
21
- "hex": "ab392664423be621da6bb048313f6531356bd96333edb3938dce0b97cad0f277"
22
- }
23
- },
24
- "buildRef": {
25
- "id": "example.build",
26
- "revision": "1",
27
- "digest": {
28
- "algorithm": "sha256",
29
- "hex": "7e261d3ba9878d05db4c5c6baa3e4a2db1a584c3d2f5f0628b4a1c78f43f5e42"
30
- }
31
- },
32
- "configurationRef": {
33
- "id": "example.non-secret-config",
34
- "revision": "1",
35
- "digest": {
36
- "algorithm": "sha256",
37
- "hex": "74afc8ef6b145b02ec9bb478dfdefdadb225fc6f7c6a729760b525ca83476e55"
38
- }
39
- },
40
- "target": {
41
- "mode": "external_staging",
42
- "deploymentRef": {
43
- "id": "example.deployment",
44
- "revision": "1",
45
- "digest": {
46
- "algorithm": "sha256",
47
- "hex": "8076c13e2f647e540083550833a8160c5e089fb199c9453ab5aecd598c9228fb"
48
- }
49
- }
50
- },
51
- "endpoints": [
52
- {
53
- "id": "app",
54
- "resolverRef": {
55
- "id": "example.app-endpoint",
56
- "revision": "1",
57
- "digest": {
58
- "algorithm": "sha256",
59
- "hex": "a6b3d24ad9a0af002a55a8ac10805e763bedd7b3e5fc0a714a3d59fecc129b81"
60
- }
61
- },
62
- "source": "external_deployment"
63
- }
64
- ],
65
- "readiness": {
66
- "endpointId": "app",
67
- "path": "/health",
68
- "method": "GET",
69
- "expectedStatus": 200,
70
- "timeoutMs": 20000
71
- },
72
- "capabilities": [
73
- {
74
- "id": "surface.http",
75
- "version": 1,
76
- "required": true
77
- }
78
- ],
79
- "dependencyPlanRefs": [],
80
- "personaCredentials": [
81
- {
82
- "personaRef": {
83
- "id": "example.persona.owner",
84
- "revision": "1",
85
- "digest": {
86
- "algorithm": "sha256",
87
- "hex": "6e993a3445b5165be1d544736fadaa7d46d65c63d07ed71b1552bb51a5bd0813"
88
- }
89
- },
90
- "secretRef": {
91
- "id": "example.app-persona-credential",
92
- "revision": "1",
93
- "digest": {
94
- "algorithm": "sha256",
95
- "hex": "e90cf65d59c84838c7dd77bec933794873024e2c93cf8252a4079e494a04c4f8"
96
- }
97
- }
98
- }
99
- ],
100
- "executionPolicyRef": {
101
- "id": "example.execution-policy",
102
- "revision": "1",
103
- "digest": {
104
- "algorithm": "sha256",
105
- "hex": "f5150e48ea518c445afe198f0c7d643b4645faaeb4fe3d6d007d79209dc4de59"
106
- }
107
- },
108
- "executionSecretRefs": [],
109
- "network": {
110
- "policyRef": {
111
- "id": "example.network-policy",
112
- "revision": "1",
113
- "digest": {
114
- "algorithm": "sha256",
115
- "hex": "858db25db4c84793dd49f8bce7d12c9900326669c502880e1f5267895119efd2"
116
- }
117
- },
118
- "enforcement": "host",
119
- "inbound": "none",
120
- "egress": "explicit_allowlist",
121
- "allowedEndpointIds": [
122
- "app"
123
- ]
124
- },
125
- "data": {
126
- "mode": "none"
127
- },
128
- "ownership": {
129
- "leasePolicyRef": {
130
- "id": "example.lease-policy",
131
- "revision": "1",
132
- "digest": {
133
- "algorithm": "sha256",
134
- "hex": "0cc0aa82f73b5bf800d872d90a515772246e60a1f26c0b827c823a1256afb26d"
135
- }
136
- },
137
- "cleanupPlanRef": {
138
- "id": "example.cleanup-plan",
139
- "revision": "1",
140
- "digest": {
141
- "algorithm": "sha256",
142
- "hex": "af70f7ee71e47a2ba88e31da4d90bcf0cd8a991cb24b937245704f17d5f6b1db"
143
- }
144
- },
145
- "cleanupReserveMs": 10000
146
- },
147
- "artifacts": {
148
- "destinationRef": {
149
- "id": "example.artifact-destination",
150
- "revision": "1",
151
- "digest": {
152
- "algorithm": "sha256",
153
- "hex": "86b317ba249de72c702be4390a57b7bcd090aa5fdb086fe16e64479efa4f9fca"
154
- }
155
- },
156
- "durability": "export_required",
157
- "redactionPolicyRef": {
158
- "id": "example.redaction-policy",
159
- "revision": "1",
160
- "digest": {
161
- "algorithm": "sha256",
162
- "hex": "ebe43b36aeba3427ee4be196757f1cc3d4acb47c34f02928f40ed0cf008d0a8c"
163
- }
164
- },
165
- "retentionMs": 86400000,
166
- "maxBytes": 16777216
167
- },
168
- "limits": {
169
- "wallMs": 120000,
170
- "cpu": 1,
171
- "memoryMb": 1024,
172
- "diskMb": 256,
173
- "maxRequests": 100,
174
- "maxBrowserActions": 0,
175
- "maxProviderCalls": 0,
176
- "maxAgentCalls": 0,
177
- "maxSpendCents": 0
178
- },
179
- "allowedReplayModes": [
180
- "fresh_execution",
181
- "evidence_playback"
182
- ]
183
- }
@@ -1,133 +0,0 @@
1
- # Immutable Git source resolution
2
-
3
- `workflow-verify source-resolve --input repositories.json --output source.json --json` freezes explicit local base/head selections across repositories. It exports a sealed owner-private source-resolution document containing the `RevisionMatrix`, full binary-capable diffs, changed paths and before/after blob bytes. Exit zero means source resolution succeeded; it is not a case review, execution verdict or deployment proof.
4
-
5
- Create a local request using the public typed SDK (the repository reference below is a local label, not a registered remote identity):
6
-
7
- ```js
8
- import { writeFileSync } from 'node:fs';
9
- import { localScope, digestOfValue } from 'workflow-verify';
10
-
11
- writeFileSync('repositories.json', JSON.stringify({
12
- scope: localScope(),
13
- repositories: [{
14
- repositoryRef: { id: 'application', revision: '1',
15
- digest: digestOfValue({ kind: 'local-git-binding', name: 'application' }) },
16
- root: '.', base: 'HEAD~1', head: 'HEAD',
17
- }],
18
- }, null, 2), { flag: 'wx', mode: 0o600 });
19
- ```
20
-
21
- Roots in CLI requests resolve relative to the request file. Library callers supply their own trusted local mappings. Both worktrees and bare repositories are supported; selecting a nested directory cannot silently bind its parent repository. The CLI accepts only the process's `localScope()` and writes new output files privately without overwriting existing evidence. Public JSON schemas include the Git request and resolution contracts.
22
-
23
- `resolveGitSources(request, authorize)` requires a trusted host authorization callback before reading each repository. `GitSourceReader(matrix, bindings, authorize)` implements citation object reads and full-diff reads after restart. Bindings contain only `repositoryRef` and `root`; they do not re-resolve branch expressions. A reader refuses another scope/repository, substituted matrix rows, unavailable objects and changed full-diff bytes. Citation validation still checks exact file/excerpt digests. A later dirty checkout or moved branch does not change the selected immutable commit identities.
24
-
25
- Git invocation uses argument arrays and [documented end-of-options handling](https://git-scm.com/docs/git-rev-parse), reads commit objects rather than worktree files, and disables replacement objects, inherited Git routing variables, external diff/text-conversion helpers, terminal prompts and lazy fetching. [Git's diff options](https://git-scm.com/docs/git-diff) define the helper exclusions. Selected commits and their tree closure are checked against Git object hashes; captured/read blobs are rehashed independently too. SHA-1 and SHA-256 Git object IDs are preserved in full. This does not create an authenticated issuer or attest a remote repository or deployed target; the host owns the Git executable, source mappings, protected object storage and admission policy.
26
-
27
- No fetch, checkout, model call or review approval occurs. Missing or multiple merge bases block until a registered alternative revision policy exists; an empty base is never invented. Renames are represented as deletion/addition with detection disabled. Changed symlinks, submodules, unsupported paths/modes, oversized blobs and incomplete output block instead of dropping coverage.
28
-
29
- Bounds: 32 repositories, 500 changed paths, 1 MiB per captured/cited blob, 4 MiB per full diff/tree listing/tree object, 8,192 trees per selected commit, 32 MiB of captured payload bytes and ten seconds per Git command. CLI input is at most 256 KiB. The artifact includes changed blobs and full diffs, not every source object: later citation reads require the selected objects in an authorized Git store. Full source-object transport remains separate work.
30
-
31
- The output is a `RevisionMatrix`, not a complete runtime `SourceSelection` or qualified source-to-target proof. Independent element/coverage checking, reviewed source admission, hosted lifecycle storage and execution wiring remain separate gates. Tests use real temporary repositories, including dirty/moved checkouts, bare and SHA-256 repositories, corrupt objects, denied/revoked scope, missing objects, oversized blobs, configured helpers and the actual source/built CLI.
32
-
33
- ## Run selected revisions independently
34
-
35
- Materialize complete regular-file trees from the frozen resolution using an explicit
36
- authorized local repository mapping. Relative `--root` paths resolve beside the
37
- input JSON. Output directories must not exist, and their parent must already exist.
38
-
39
- ```sh
40
- tracegrove source-materialize --input source.json --repository application --root . --side base --output ./base-snapshot
41
- tracegrove source-materialize --input source.json --repository application --root . --side head --output ./head-snapshot
42
- tracegrove test --config ./base-snapshot/source/tracegrove.config.yaml --source-snapshot ./base-snapshot/snapshot.json
43
- tracegrove test --config ./head-snapshot/source/tracegrove.config.yaml --source-snapshot ./head-snapshot/snapshot.json
44
- ```
45
-
46
- Each output contains `source/` and a sealed `snapshot.json` with the resolution and
47
- repository references, exact commit, side, and every file's original Git mode,
48
- byte count and SHA-256 digest. `materializeGitSnapshot(input, authorize)` exposes
49
- the same operation through the SDK. Authorization runs before object reads and
50
- again before output allocation. No fetch, checkout, dependency installation, app
51
- execution, Git filters or hooks occur during materialization. Later `test` runs
52
- execute trusted project code and use the ordinary compiler and app identity checks.
53
-
54
- The reader validates the commit/tree closure and independently rehashes every blob,
55
- including unchanged files. It refuses an empty tree, symlinks, submodules, unsupported
56
- modes, nonportable names, case/Unicode aliases, more than 10,000 files, blobs over
57
- 1 MiB, or more than 32 MiB of file bytes. These are complete-coverage limits: it
58
- never silently excludes a file to make a snapshot pass. A private output is created
59
- only after all object reads succeed; the manifest is written last, and write failure
60
- removes only the directory this operation exclusively created. Existing output is
61
- preserved. The host filesystem and Git executable remain trusted.
62
-
63
- The CLI regression test creates a real authorization bug and its fix in separate
64
- commits, freezes them, dirties the checkout and moves its branch. Separate CLI
65
- processes run the identical saved flow against both materialized revisions: the
66
- base fails the ownership assertion and the head passes. Both bundles are re-read
67
- and re-reduced, app digests match the snapshot's source bytes, and cleanup is
68
- confirmed. CI repeats this through the built distribution and retains both sealed
69
- bundles, source trees, snapshot manifests and resolution in `source-regression-proof`.
70
- Another process can verify those bundles or rerun either snapshot without discovery;
71
- the artifact README gives the exact commands. Locally, set
72
- `TRACEGROVE_SOURCE_PROOF_DIR` to a new directory when running
73
- `tests/cliGitSnapshot.test.ts` to retain the same proof.
74
-
75
- A snapshot is mutable after publication; its manifest describes the captured
76
- bytes. `test` and `compile` accept `--source-snapshot` for an explicit per-command
77
- binding. Compilation checks the manifest, local owner scope and every pinned file.
78
- The frozen launch plan includes that binding; the trusted supervisor checks the
79
- files again, copies only pinned inputs into its private owned workspace, and
80
- starts the app there. Untracked files cannot enter the launch copy. Post-plan drift
81
- in any pinned file, including files outside the entrypoint's source glob, blocks
82
- startup. The supervisor owns and removes the private copy after stop, startup
83
- failure or controlling-client disconnect.
84
-
85
- Pinned launches support the Node file, FastAPI module and canonical Django launch
86
- templates. Opaque eval/shell wrappers and entrypoints outside the snapshot are
87
- refused. The attestation binds the supervisor-computed source digest and snapshot
88
- reference; saved-bundle verification rechecks the exact file closure and manifest
89
- digests. Dependency installations, interpreter binaries and application environment
90
- remain separately supplied inputs; this is not a process sandbox or a complete
91
- dependency attestation. The CLI refuses snapshots from another local scope.
92
-
93
- New snapshots carry [Git object proofs](git-object-proof.md). The supervisor checks the
94
- actual private tree against blob/tree/commit object identities and records that fact.
95
- Metadata-only checks remain distinct from actual-file verification. A self-sealed
96
- manifest does not prove who resolved its commit, remote repository ownership or deployed
97
- identity. This is not a runtime `SourceSelection`. The host does not yet populate repository observations
98
- or promote qualification from this manifest. Authenticated resolver/admission
99
- policy, reviewed lifecycle execution and hosted activation remain separate work.
100
-
101
- ## Keep scenarios in one workbench
102
-
103
- Application input can be selected independently of the config and saved flows.
104
- `app.root` is resolved inside the selected snapshot; flows, personas and config
105
- continue to come from the workbench. No team config rewrite is needed.
106
-
107
- ```sh
108
- tracegrove settings --dir ./workbench --source-snapshot ./snapshots/head/snapshot.json
109
- tracegrove test --config ./workbench/tracegrove.config.yaml
110
- tracegrove settings --dir ./workbench --working-tree
111
- ```
112
-
113
- The CLI snapshot path is relative to the calling directory, as with the existing
114
- one-run `test --source-snapshot` override. The saved path is relative to the
115
- workbench. An explicit one-run override takes precedence over the saved choice.
116
- Settings preserves the agent/model/budget preferences and rejects conflicting
117
- input switches before writing any preference.
118
-
119
- Grove's **Settings → Verification input** offers **Check snapshot** before
120
- **Use this snapshot**. Checking reads and validates bytes and the launch template;
121
- it launches no application and writes no compile output. Saving records the
122
- manifest's exact reference. Replacing the manifest or changing a pinned file
123
- blocks runs until reviewed again; there is no automatic fallback to working tree.
124
- **Use working tree** clears the local selection without deleting a snapshot.
125
-
126
- The Run page separates **Next run input** from **Recorded run request**. The latter
127
- is reconstructed from the frozen host plans in re-verified saved evidence, even
128
- after a preference change. Unreadable or inconsistent evidence shows unavailable,
129
- never the current default. A recorded request describes local inputs; it does
130
- not establish that an application successfully launched or grant hosted qualification.
131
- Discovery's branch selector only scans routes and does not change run input.
132
- Python dependencies may be supplied by the workbench's `.venv` or explicit
133
- `app.python`; neither dependencies nor environment are sealed by the source pin.
Binary file
@@ -1,13 +0,0 @@
1
- # Durable local plan review
2
-
3
- `LocalReviewStore` connects `editPlan` and `reviewPlan` to the existing `LocalLedger`. Construct it with an already opened ledger, editable-plan identity, exact scope and trusted host implementations of `authorize` and `validateSources`. Its `ports()` implements `PlanReviewPorts`; no permissive authority or source-check fallback is installed.
4
-
5
- `initialize(plan)` stores an unreviewed immutable draft at edit revision one. `stage(plan)` adds another immutable revision without changing the editable revision or current review. The staged draft gains neither approval nor execution authority. `editPlan(store.ports(), token, stagedRef)` then atomically advances editable revision and clears approval. Re-staging identical bytes is a no-op; changing bytes under the same document identity/revision is refused.
6
-
7
- Review commits recheck the current actor and policy after source checking, compare the storage version, and append the projection, review and source-validation records in one journal entry. Authorization revocation, substituted scope, missing independent validation, immutable-reference collisions and competing writers publish no losing review. Source validation is persisted with its exact plan/change-model/revision-matrix/policy bindings. Reopening the ledger recovers the review and those records together. Local collections are bounded to 500 plans, reviews and validations; exhaustion fails rather than discarding history.
8
-
9
- The journal stores private local state behind the single-writer controller lock. Writes check ownership, serialize and validate before consuming a sequence, synchronize the journal and its directory, and cache only the serialized bytes. Reads and append results are copies. An uncertain write stops both reads and writes through that handle; close it and reconcile the persisted journal before continuing. Closed handles and replaced writer ownership also refuse current-state reads. A truncated or unterminated record is retained and refuses reopening; this change never trims or repairs evidence automatically. Recovery acquires the new writer identity before recording interrupted work.
10
-
11
- This is a protected local-host adapter, not distributed fencing, a tenant ACL, a signed external issuer or a replacement for the shared OrgX authority decision. The host must protect the state directory from candidate processes and supply authenticated admission and the registered independent source checker. Do not accept local approval records as hosted authority merely because their hashes verify. No new database table, paid call, deployment or live database change is required by this adapter.
12
-
13
- Tests cover actual journal bytes, reopen recovery, concurrent review arbitration, staged edits, authorization revocation, forged actor/policy fields, missing validation, caller mutation, serialization failure, failed synchronization, replaced writer ownership and unterminated records. Source authorization/checking in the persistence tests is explicitly simulated. [Source promotion](source-promotion.md) reuses its actual approved snapshot and current-review guard. [Local scenario storage](local-scenario-store.md) supports structural transitions, registered qualification execution, result retention and explicit atomic activation. Hosted coordination acceptance, CLI lifecycle commands and activated regression execution remain open.
@@ -1,91 +0,0 @@
1
- # Durable local scenario registration
2
-
3
- `LocalScenarioStore` implements `ScenarioPorts` on the existing `LocalLedger`.
4
- It persists definitions, selections, pending qualification admissions and semantic
5
- invalidation together. It supplies `resolveAdmission(ref, scope)` for reading an
6
- actual registered record, rather than accepting a producer document as registration.
7
-
8
- ```ts
9
- const store = new LocalScenarioStore(ledger, scenarioId, scope, authority);
10
- await store.initialize(definition, [qualificationMatrix, selectedRound]);
11
- const admission = await registerQualificationRound(store.ports(), token, {
12
- selectionManifestRef: selectedRound.ref,
13
- stateLeaseRefs: provisionedStateLeaseRefs,
14
- });
15
- ```
16
-
17
- The authenticated host must provide all three authority methods. There is no
18
- permissive default:
19
-
20
- - `authorize(scope, action)` checks the current owner and policy. Reads are
21
- authorized too; registration/invalidation recheck authorization before publication.
22
- - `validateDefinition(definition)` checks the complete reviewed source, replay,
23
- policy, target and matrix closure. Initialization requires the host to have
24
- already authorized promotion and structural validation. It does not create an
25
- approval or turn a draft into an accepted native plan.
26
- - `validateStateLeases(admission)` is a read-only check that the host actually
27
- provisioned fresh state and can reserve the supplied leases for this admission.
28
- The store does not provision resources, establish an issuer or infer freshness
29
- from a caller-generated UUID. The host remains responsible for synchronizing its
30
- external authority and physical lease checks with its controller.
31
-
32
- Source-derived definitions additionally require `reviewStore: reviews`, the
33
- `LocalReviewStore` that owns the same ledger. Its current approved source snapshot
34
- and synchronous fence are composed with the three host methods. Do not substitute a
35
- serialized approval object or a callback that only checks the review before an await.
36
- The fence is checked again immediately before registry writes. Qualification context
37
- also carries its sealed plan, review and validation into the execution bundle.
38
-
39
- Repeated identical input documents are stored once, including when the selected
40
- round is the qualification matrix itself. Different bytes under the same immutable
41
- document identity are refused.
42
-
43
- One bounded registry per scope makes lease claims atomic across scenarios sharing
44
- that registry. A commit checks the scenario version, exact allowed projection
45
- transition, complete selection/allocation, epoch and immutable definition bindings.
46
- It then rechecks authorization and the registry version and appends the projection
47
- and admission in one synced record. Competing writers publish one winner. A lease
48
- identity cannot be reused by changing its revision/digest or by selecting another
49
- scenario in the same scope. Other scopes and distributed resource pools need their
50
- own trusted coordination owner; this is not a tenant isolation boundary.
51
-
52
- `stage(definition, selections)` stores an immutable replacement without changing
53
- the current definition, epoch, approval or coverage. Re-staging identical bytes
54
- is a no-op. `invalidateScenario` must name a new revision of the same definition;
55
- it retains history, advances the epoch, clears activation authority and degrades
56
- the projection. Invalidation that commits while registration checks state makes
57
- the older registration lose its CAS. Direct port calls cannot manufacture an
58
- active projection or skip the epoch/version rules.
59
-
60
- Reopening the ledger recovers admission and projection together. If a commit's
61
- acknowledgement is lost, inspect the registered history and resolve its immutable
62
- admission reference. An old token conflicts; it does not register another attempt.
63
- Historical reads do not establish current execution or activation authority.
64
- Caller mutations cannot rewrite returned or stored records. Closed, ownership-lost
65
- or uncertain ledger handles retain the underlying ledger's refusal behavior.
66
-
67
- The prototype permits 100 scenarios, 500 total admissions and 2,000 definition/
68
- selection records in one registry. Exhaustion requires archival indexing; history
69
- is never silently dropped. The state directory must stay private to the trusted
70
- controller and inaccessible to candidate processes. Local hashes and projection
71
- states are not signatures or hosted approval receipts.
72
-
73
- The [terminal result index](qualification-results.md#durable-local-terminal-results)
74
- retains complete rounds through the existing result sink. The
75
- [activation adapter](scenario-activation.md#local-atomic-storage) publishes the active
76
- projection, receipt and assessment records in one scenario-registry append.
77
- `propose` and the [structural validation adapter](scenario-structure.md) separate
78
- staging a proposal from compiling its frozen execution closure and entering validating
79
- state. The same operation can revalidate a semantically edited, degraded definition.
80
- This adapter does not install physical lease provisioning, hosted source/issuer
81
- authorization or CLI lifecycle commands. [Source-plan promotion](source-promotion.md)
82
- uses actual current approved review storage to register proposed scenarios.
83
- [Registered qualification execution](qualification-registration.md#executing-a-registered-round)
84
- requires a separate authenticated runtime owner and uses the admission's allocated
85
- cell identities. Requests without that owner and all activated regression requests
86
- remain refused. A registration record cannot relabel trial evidence as qualification.
87
-
88
- Tests use real journal bytes, reopen recovery and competing operations. Host
89
- authentication, structural promotion and physical lease checks are explicitly
90
- simulated in those storage tests. No live database, paid model or OrgX decision is
91
- created or approved by this adapter.