assertledger 1.4.0 → 1.5.0
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.
- package/README.fr.md +5 -2
- package/README.md +5 -2
- package/conformance/schema-extensions.json +15 -0
- package/dist/build-info.json +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +213 -8
- package/dist/cli.js.map +1 -1
- package/dist/contracts/index.d.ts +467 -4
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +256 -3
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/qualification.d.ts +528 -0
- package/dist/contracts/qualification.d.ts.map +1 -0
- package/dist/contracts/qualification.js +357 -0
- package/dist/contracts/qualification.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +46 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/qualification.d.ts +17 -0
- package/dist/core/qualification.d.ts.map +1 -0
- package/dist/core/qualification.js +571 -0
- package/dist/core/qualification.js.map +1 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +81 -4
- package/dist/diagnostics.js.map +1 -1
- package/dist/engine/adapters/bun-native.d.ts +35 -0
- package/dist/engine/adapters/bun-native.d.ts.map +1 -0
- package/dist/engine/adapters/bun-native.js +179 -0
- package/dist/engine/adapters/bun-native.js.map +1 -0
- package/dist/engine/adapters/bun-test-designated-profile.d.ts +23 -0
- package/dist/engine/adapters/bun-test-designated-profile.d.ts.map +1 -0
- package/dist/engine/adapters/bun-test-designated-profile.js +24 -0
- package/dist/engine/adapters/bun-test-designated-profile.js.map +1 -0
- package/dist/engine/container.d.ts +7 -0
- package/dist/engine/container.d.ts.map +1 -1
- package/dist/engine/container.js +22 -7
- package/dist/engine/container.js.map +1 -1
- package/dist/engine/git-regression.d.ts.map +1 -1
- package/dist/engine/git-regression.js +9 -2
- package/dist/engine/git-regression.js.map +1 -1
- package/dist/engine/index.d.ts +14 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +828 -97
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/qualification.d.ts +154 -0
- package/dist/engine/qualification.d.ts.map +1 -0
- package/dist/engine/qualification.js +725 -0
- package/dist/engine/qualification.js.map +1 -0
- package/dist/engine/test-closure.d.ts +39 -0
- package/dist/engine/test-closure.d.ts.map +1 -0
- package/dist/engine/test-closure.js +513 -0
- package/dist/engine/test-closure.js.map +1 -0
- package/dist/engine/witness-import.d.ts +31 -0
- package/dist/engine/witness-import.d.ts.map +1 -0
- package/dist/engine/witness-import.js +224 -0
- package/dist/engine/witness-import.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +65 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/sdk/index.d.ts +292 -3
- package/dist/sdk/index.d.ts.map +1 -1
- package/dist/sdk/index.js +39 -1
- package/dist/sdk/index.js.map +1 -1
- package/docs/container-isolation.md +6 -0
- package/docs/migration-orchestration-qualification-v1.md +109 -0
- package/docs/migration-verification-v4.md +94 -0
- package/docs/orchestration-qualification.md +167 -0
- package/docs/reference.md +7 -0
- package/docs/witness-import.md +67 -0
- package/examples/orchestration/README.md +68 -0
- package/examples/orchestration/consumer-obligations.json +101 -0
- package/examples/orchestration/workspace/bitbucket-pipelines.yml +10 -0
- package/examples/orchestration/workspace/command-shape.test.mjs +25 -0
- package/examples/orchestration/workspace/commands.mjs +14 -0
- package/examples/orchestration/workspace/completion.mjs +39 -0
- package/examples/orchestration/workspace/faults.json +1 -0
- package/examples/orchestration/workspace/native.test.ts +4 -0
- package/examples/orchestration/workspace/package.json +6 -0
- package/examples/orchestration/workspace/packages/app/package.json +12 -0
- package/examples/orchestration/workspace/packages/app/verdict.txt +1 -0
- package/examples/orchestration/workspace/packages/leaf/package.json +9 -0
- package/examples/orchestration/workspace/packages/leaf/verdict.txt +1 -0
- package/examples/orchestration/workspace/pnpm-lock.yaml +170 -0
- package/examples/orchestration/workspace/pnpm-workspace.yaml +2 -0
- package/examples/orchestration/workspace/task.mjs +23 -0
- package/examples/orchestration/workspace/turbo.json +38 -0
- package/examples/orchestration/workspace/wrapper.mjs +45 -0
- package/integrations/bun/driver.d.mts +30 -1
- package/integrations/bun/driver.mjs +215 -6
- package/integrations/bun/preload.mjs +186 -5
- package/integrations/bun-native/README.md +86 -0
- package/integrations/bun-native/driver.mjs +396 -0
- package/integrations/bun-native/preload.mjs +375 -0
- package/integrations/skill/SKILL.md +25 -5
- package/package.json +1 -1
- package/schemas/evidence-manifest.v4.json +995 -0
- package/schemas/qualification-execution-request.v1.json +571 -0
- package/schemas/qualification-plan.v1.json +528 -0
- package/schemas/qualification-receipt.v1.json +821 -0
- package/schemas/qualification-replay-result.v1.json +37 -0
- package/schemas/verification-request.v4.json +590 -0
- package/schemas/witness-import-request.v1.json +231 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Verification v4: designated Bun tests, closure-scoped links and declared isolation
|
|
2
|
+
|
|
3
|
+
Verification request and evidence manifest v4 add three things a v3 campaign cannot express. V1 to
|
|
4
|
+
v3 schema bytes, parsers, adapters and historical manifests are unchanged and replayable; every
|
|
5
|
+
refusal they apply still applies to them.
|
|
6
|
+
|
|
7
|
+
## Existing Bun tests, run by name
|
|
8
|
+
|
|
9
|
+
The `bun-test-designated` adapter verifies an existing `bun:test` test instead of a new candidate
|
|
10
|
+
file. A candidate names the test and, optionally, the first line of the failure it must produce:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"id": "gate-routing",
|
|
15
|
+
"test": { "file": "tools/gates.test.ts", "path": ["gate routing", "keeps docs"] },
|
|
16
|
+
"expectedFailure": "error: expect(received).toContain(expected)"
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`path` is the describe path ending with the test name. The adapter is declared as
|
|
21
|
+
`{ "kind": "bun-test-designated", "executable": "bun", "testTimeoutMs": null }`; `testTimeoutMs`
|
|
22
|
+
sets Bun's per-test timeout (`bun test --timeout`) and must be shorter than
|
|
23
|
+
`timeoutMsPerExecution`. `null` keeps Bun's default of 5 seconds.
|
|
24
|
+
|
|
25
|
+
Each run executes only that test, selected by an anchored, escaped `--test-name-pattern`. The
|
|
26
|
+
taxonomy is the one every adapter applies:
|
|
27
|
+
|
|
28
|
+
- red is only an assertion failure attributed to the designated test: a failure thrown inside it by
|
|
29
|
+
a `bun:test` built-in matcher, in Bun's matcher message form, or by `assertSame`; with an expected
|
|
30
|
+
line, its first message line must be equal to it;
|
|
31
|
+
- a timeout is never red, including a test that Bun timed out and whose callback threw a matcher
|
|
32
|
+
failure afterwards; nor is a crash, a hook failure, a collection or compile error, a custom matcher,
|
|
33
|
+
a matcher usage error, a forged message, or a test that is not found (`NO_TEST_DISCOVERED`);
|
|
34
|
+
- repeated runs that diverge make the candidate `UNSTABLE`.
|
|
35
|
+
|
|
36
|
+
Controls load every designated file without running a test. They show that each world evaluates the
|
|
37
|
+
file and its imports and still registers the designated test exactly once. The designated test file
|
|
38
|
+
must not be rewritten by any world (`DESIGNATED_TEST_OVERLAID`).
|
|
39
|
+
|
|
40
|
+
Every campaign first runs the designated preflight: fixed probes, including a synchronous test that
|
|
41
|
+
overruns its timeout and then fails a matcher, must each produce their expected outcome, or the
|
|
42
|
+
campaign stops.
|
|
43
|
+
|
|
44
|
+
## Repository links judged against the executed tests
|
|
45
|
+
|
|
46
|
+
A v4 campaign collects the repository's links instead of refusing the first one. A link that leaves
|
|
47
|
+
the repository root (`REPOSITORY_LINK_ESCAPES_ROOT`) or lies on the module closure of a test the
|
|
48
|
+
adapter executes (`REPOSITORY_LINK_IN_TEST_CLOSURE`) refuses the campaign, and the error names its
|
|
49
|
+
path. When a test's imports are computed or absolute, the closure is unbounded and any link refuses
|
|
50
|
+
the campaign (`TEST_CLOSURE_UNBOUNDED`). The others are left out of the snapshot and listed, sorted,
|
|
51
|
+
in `evidenceContext.repository.omittedLinks`, which the decision digest covers.
|
|
52
|
+
|
|
53
|
+
The closure follows literal `import`, `export … from`, `import()`, `require()` and `mock.module()`
|
|
54
|
+
specifiers, `tsconfig`/`jsconfig` paths, workspace packages, including their installed
|
|
55
|
+
`node_modules` entry, declared dependencies of installed packages, and `bunfig.toml` test preloads.
|
|
56
|
+
It does not cover files a test reads at run time; that limitation is recorded in the manifest.
|
|
57
|
+
|
|
58
|
+
`doctor` applies the same rule to the tests the framework would discover, and reports the closure
|
|
59
|
+
as non-blocking when it is unbounded. A link through which a runner could discover a test, named as
|
|
60
|
+
a test itself or a directory holding one, is in the closure. `analyze`, `audit` and v1 to v3
|
|
61
|
+
campaigns still refuse any link.
|
|
62
|
+
|
|
63
|
+
## Snapshot options
|
|
64
|
+
|
|
65
|
+
`repository.includeDependencies` keeps `node_modules` in the snapshot and its digest as found;
|
|
66
|
+
AssertLedger neither installs nor verifies it. `repository.git` is `excluded`, the snapshot without
|
|
67
|
+
Git metadata, or `synthesized`: the snapshot is committed once into a fresh repository with a fixed
|
|
68
|
+
identity and date and no hooks, template or global configuration, honoring its own `.gitignore`.
|
|
69
|
+
The tree identity and Git version are recorded in `evidenceContext.repository.git`. The source
|
|
70
|
+
repository's own `.git` and history never enter the snapshot.
|
|
71
|
+
|
|
72
|
+
## Declared isolation
|
|
73
|
+
|
|
74
|
+
`isolation` is one of:
|
|
75
|
+
|
|
76
|
+
- `container`: a fresh container per execution from a digest-pinned local image, through the
|
|
77
|
+
operator's runtime argv, for example the native WSL2 engine
|
|
78
|
+
`["wsl.exe","-d","Ubuntu","--exec","docker"]`. The designated adapter runs there; `bun-test`
|
|
79
|
+
with candidate files is still refused in a container (`BUN_TEST_CONTAINER_UNSUPPORTED`).
|
|
80
|
+
- `trusted-local`: unsandboxed, level `UNSANDBOXED`.
|
|
81
|
+
- `windows-native`: unsandboxed on a Windows host for tests that only run natively there, level
|
|
82
|
+
`WINDOWS_NATIVE_UNSANDBOXED`. It is never implied: the request declares the kind, the operator
|
|
83
|
+
acknowledges it (`--allow-windows-native-execution`), and it is refused on any other host
|
|
84
|
+
(`WINDOWS_NATIVE_HOST_REQUIRED`).
|
|
85
|
+
|
|
86
|
+
The level is in `isolation.level` of every manifest and in every witness summary, and the decision
|
|
87
|
+
digest binds it.
|
|
88
|
+
|
|
89
|
+
## Compatibility
|
|
90
|
+
|
|
91
|
+
`verify` and the SDK's `verifyV4` accept v4 requests; `replay` accepts v1 to v4 manifests. The v4
|
|
92
|
+
request, v4 manifest and witness import request schemas are added to the post-conformance schema
|
|
93
|
+
lock; the frozen v1 bundle and its root digest are unchanged. To replay a recorded red/green
|
|
94
|
+
witness, see [witness import](witness-import.md).
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Orchestration qualification v1
|
|
2
|
+
|
|
3
|
+
## Delivery contract
|
|
4
|
+
|
|
5
|
+
Deliver a named, version-pinned qualification profile with a sealed obligation inventory, executable
|
|
6
|
+
reference/fault/neutral worlds, independent observations, deterministic receipts and domain-aware
|
|
7
|
+
replay. A test-only receipt cannot satisfy a cache, wrapper, selection or CI obligation.
|
|
8
|
+
|
|
9
|
+
The public reproduction is authored from scratch. Private consumer sources and resources are not
|
|
10
|
+
distributed. Approval gates, brokers, shared skills and merge authorization are outside this change.
|
|
11
|
+
|
|
12
|
+
## Work and acceptance
|
|
13
|
+
|
|
14
|
+
1. Inventory the published CLI/SDK/MCP and consumer version/test forms; preserve concurrent work.
|
|
15
|
+
2. Add versioned contracts/core and qualify native Bun assertions without changing frozen v1-v4.
|
|
16
|
+
3. Execute real pinned Turbo cold/warm/invalidation, selection and failure propagation campaigns.
|
|
17
|
+
4. Expose CLI/SDK/MCP, retain receipts/replay and the obligation matrix; run `pnpm check`.
|
|
18
|
+
5. Freeze the aggregate candidate and obtain independent proof-integrity review before publishing PR.
|
|
19
|
+
|
|
20
|
+
Contracts/core and Bun collection are authored in separate worktrees. The lead integrates, owns the
|
|
21
|
+
campaign, verifies the complete candidate and publishes. Operational errors never earn detection.
|
|
22
|
+
|
|
23
|
+
## Qualification boundary
|
|
24
|
+
|
|
25
|
+
Local configuration analysis, local command execution and hosted CI observation are separate
|
|
26
|
+
obligations. No local fixture establishes Bitbucket execution. Unknown/omitted consumer suites stay
|
|
27
|
+
open. A qualified public reproduction does not establish whole-consumer readiness.
|
|
28
|
+
|
|
29
|
+
`trusted-local` is explicitly unsandboxed. Digests establish replay integrity and domain binding;
|
|
30
|
+
they do not authenticate the producer or cause test reexecution.
|
|
31
|
+
|
|
32
|
+
## Existing capabilities and the consumer
|
|
33
|
+
|
|
34
|
+
The existing `verify` CLI, SDK `verify`/`verifyV2`/`verifyV3`/`verifyV4`, MCP verification tools and versioned
|
|
35
|
+
manifest replay remain available. Node uses its owned reporter and shallow `ERR_ASSERTION`
|
|
36
|
+
attribution. The frozen Bun v3 profile admits only errors issued by `assertledger/bun` helpers.
|
|
37
|
+
The integrated v4 baseline also supports designated Bun tests with native expectations and imported
|
|
38
|
+
witness execution. Its controls load/register a selected test without executing it; this qualification
|
|
39
|
+
profile executes its declared complete suites in the reference and neutral worlds.
|
|
40
|
+
Those paths prove their declared test campaign; they do not supply Turbo, wrapper or hosted-CI
|
|
41
|
+
qualification. The native qualification collector retains a separate event/JUnit protocol and
|
|
42
|
+
passive matcher boundary, and reuses the v4 parser's per-test timeout refusal rule.
|
|
43
|
+
The existing structured-command v1 protocol requires exit zero for `PASS`; it cannot represent a
|
|
44
|
+
successful propagation check whose tested command intentionally exits seven. This extension reuses
|
|
45
|
+
the bounded process runner, canonical hashing, Node reporter and existing versioned contracts.
|
|
46
|
+
|
|
47
|
+
Source inspection of the incident consumer found Bun **1.4.2**, pnpm **12.9.1** and Turbo **2.11.7**;
|
|
48
|
+
the Vitest compatibility dependency is **5.0.3**. Thirty workspace manifests declare tests, nine
|
|
49
|
+
declare E2E, and ten delivery suites use `node:test` under Bun. Actual forms include callback
|
|
50
|
+
contexts, generated registrations, TypeScript/TSX, helper imports, native assertions, preloads,
|
|
51
|
+
isolation, filters and a development-condition test route. These pins and counts are an inventory,
|
|
52
|
+
not qualification of those private suites. The published reproduction contains independently
|
|
53
|
+
authored generic sources only.
|
|
54
|
+
|
|
55
|
+
The new Bun profile pins the full runtime revision and qualifies five passive native matchers and
|
|
56
|
+
three Node assertions. Its [capability boundary](../integrations/bun-native/README.md) names every
|
|
57
|
+
qualified form. Unsupported assertions, active operands, custom matchers, absent files, skips,
|
|
58
|
+
hooks, compilation/collection failures and no tests stay operational. They cannot earn detection.
|
|
59
|
+
|
|
60
|
+
## Actions, observations and decisions
|
|
61
|
+
|
|
62
|
+
An operator seals the inventory, worlds, actions and exact expected checks before execution. Only
|
|
63
|
+
candidate file overlays on explicitly allowed paths are accepted afterward. The sealed plan digest
|
|
64
|
+
must be anchored outside candidate control; this API does not create an authority or security boundary.
|
|
65
|
+
|
|
66
|
+
Adapters collect facts. The pure core compares them with the operator checks, requires stable
|
|
67
|
+
reference and neutral runs and the specifically declared target mismatches in every attempt.
|
|
68
|
+
Missing reports, duplicates, contradictions, unobserved suite files and undeclared mismatches are
|
|
69
|
+
not admission. Receipts list `coveredGuaranteeIds`, `openGuaranteeIds`, reasons and check IDs.
|
|
70
|
+
|
|
71
|
+
| Guarantee | Action and observations | Oracle | Executable discriminant |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| Extracted command tests | Owned Node reporter, actual started files and TAP completion | Positive discovery, assertion attribution, exit consistency | Changed command shape |
|
|
74
|
+
| Native Bun tests | Pinned runtime, signed event pipe, JUnit concordance, actual files | Matcher-issued error belongs to the same test | Changed native assertion value; getter/crash refusals |
|
|
75
|
+
| Selection | Real Turbo summary, selected IDs and dependency closure | Exact required task IDs | Required dependency removed; actual empty filter |
|
|
76
|
+
| Cache | Cold/warm/invalidation; fresh external execution traces; deleted/restored output bytes | Required executions and hashes equal expected values | Forgotten input; incomplete restoration; wrongly cached disabled task |
|
|
77
|
+
| Propagation and wrappers | Actual leaf → Turbo → wrappers → terminal exit, fresh semantic completion report and required-stage traces | Exact expected nonzero exit, matching attestation and mandatory trace | Absorbed exit, omitted stage, empty filter, later success, stale success; ordinary throws/compile/spawn errors stay operational |
|
|
78
|
+
| CI configuration | Bun YAML parser outside the mutated candidate route; anchors resolved; step/stage/parallel ancestry, conditions and triggers retained | Required route/step/command/execution-policy relationships | Pull-request gate disconnected, conditional gate, manual gate |
|
|
79
|
+
| Hosted CI | Independently signed external observation | Pinned observer, exact commit/base/plan/input, executed steps and terminal success | Bad signature, wrong domain, missing/skipped step, failed terminal |
|
|
80
|
+
| Receipt/replay | Strict parsing, recomputed bindings, decisions, digests and external domain | Complete evidence matches its actual validity domain | Tamper, resealed summary forgery, duplicate/missing/rebound report, changed mechanism |
|
|
81
|
+
|
|
82
|
+
The public campaign executes fifteen fault worlds, reference and neutral twice. Cache directories
|
|
83
|
+
are distinct for each world/attempt and reused only between that attempt's ordered phases. Task
|
|
84
|
+
traces use a fresh nonce and a file outside the cache on every action. A cached log is never an
|
|
85
|
+
execution observation. Configurations, tool binaries, environments and source inputs are sealed;
|
|
86
|
+
the loaded proof mechanism has a separate digest. Root dependency directories are excluded from
|
|
87
|
+
this snapshot profile; repositories needing them require an explicit admitted dependency snapshot.
|
|
88
|
+
|
|
89
|
+
## CLI, SDK and MCP
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
assertledger qualification-plan plan.json
|
|
93
|
+
assertledger qualify request.json --allow-unsafe-execution
|
|
94
|
+
assertledger qualification-replay receipt.json --domain current-domain.json
|
|
95
|
+
assertledger qualification-ci receipt.json --observation signed-pipeline.json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`qualify` exits 0 for `QUALIFIED`, 3 for `OPEN`, 2 for `REJECTED`; unauthorized execution and invalid
|
|
99
|
+
replay exit 4. SDK methods are `sealQualificationPlan`, `qualifyOrchestration`, `replayQualification`
|
|
100
|
+
and `admitQualificationCi`. MCP exposes plan, replay and CI import in read-only mode; execution is
|
|
101
|
+
available only when the server operator enabled unsafe execution, within its allowed repository roots.
|
|
102
|
+
|
|
103
|
+
Structured command observations can additionally use `observe.report`: the adapter writes canonical
|
|
104
|
+
JSON plus a newline to `ASSERTLEDGER_QUALIFICATION_RESULT_FILE`, with exactly `protocolVersion`,
|
|
105
|
+
`nonce` and `facts`. The nonce is `ASSERTLEDGER_QUALIFICATION_NONCE`. These facts remain in the
|
|
106
|
+
`report` namespace and never override engine-measured process facts. Missing, incomplete, stale or
|
|
107
|
+
noncanonical reports become collection failures. Such reports are adapter-reported observations.
|
|
108
|
+
|
|
109
|
+
For the `command` adapter, a normal zero exit supplies `commandOutcome: PASS`. A numeric nonzero
|
|
110
|
+
exit is operational unless the fresh canonical report additionally attests
|
|
111
|
+
`facts.commandOutcome: EXPECTED_FAILURE` and `facts.exitCode` equal to the engine-measured exit.
|
|
112
|
+
The collector exposes that admitted semantic outcome separately from `report`; report fields never
|
|
113
|
+
replace the measured exit. The public fixture writes the report only after normal leaf/wrapper
|
|
114
|
+
completion, checks each child report before forwarding a nonzero exit, and emits no completion
|
|
115
|
+
on spawn errors, signals, null statuses, ordinary exceptions or compilation failures. Completion
|
|
116
|
+
reports are trusted-local adapter statements, not authenticated evidence: a malicious unsandboxed
|
|
117
|
+
candidate can forge them. They cannot select operator checks or establish hosted CI admission.
|
|
118
|
+
The Turbo summary collector has no qualified nonzero completion protocol; a numeric Turbo
|
|
119
|
+
failure remains a collection error even when its summary is present. The propagation fixture
|
|
120
|
+
qualifies its terminal command separately through the leaf/wrapper completion chain.
|
|
121
|
+
|
|
122
|
+
The CI configuration collector retains the complete route/step/stage/parallel ancestry, positions,
|
|
123
|
+
conditions, manual/automatic triggers and parallel fail-fast settings. Commands alone do not
|
|
124
|
+
establish an unconditional gate. This narrow local profile supports only the documented execution
|
|
125
|
+
fields; other step/group fields and pipeline kinds are refused as collection failures rather than
|
|
126
|
+
silently projected away. Preserved conditions are configuration facts, not a claim that a hosted
|
|
127
|
+
runner evaluated or executed them.
|
|
128
|
+
|
|
129
|
+
## Independent hosted CI admission
|
|
130
|
+
|
|
131
|
+
`ciTrust` is part of the operator-sealed plan, including a pinned Ed25519 public key, observer,
|
|
132
|
+
repository URI identity (`workspace/repository`) and required step command digests. No local
|
|
133
|
+
campaign generates this trust root or a hosted-pipeline observation. The external observer signs
|
|
134
|
+
canonical JSON `{domain: "ASSERTLEDGER_CI_OBSERVATION_V1", statement: unsignedStatement}`.
|
|
135
|
+
The statement names the pipeline URL/identity, repository, exact commit/base, plan/input/candidate
|
|
136
|
+
digests, actual executed steps and terminal result. The key's owner must observe those facts through
|
|
137
|
+
an independently trusted CI channel. A signature alone cannot establish that its signer is honest.
|
|
138
|
+
|
|
139
|
+
CI import accepts only an intact existing receipt with that unchanged trust root. Unit signing
|
|
140
|
+
fixtures test the verifier; they are never observations of Bitbucket. No real consumer pipeline
|
|
141
|
+
observation is delivered by this local public campaign, so the consumer's hosted CI obligation stays open.
|
|
142
|
+
|
|
143
|
+
## Replay and reuse
|
|
144
|
+
|
|
145
|
+
Replay recalculates schema, integrity, completeness, deterministic decisions and the optional
|
|
146
|
+
external validity domain. `reexecuted` and `producerAuthenticated` are always false. It does not
|
|
147
|
+
rerun tests, authenticate local observations or independently confirm a pipeline. The CI verifier
|
|
148
|
+
checks a supplied observation signature against the trust policy; it does not authenticate the
|
|
149
|
+
receipt maker or infer a hosted observation from local execution.
|
|
150
|
+
|
|
151
|
+
For reuse, supply the current externally trusted plan/candidate/input/commit/base and loaded
|
|
152
|
+
`mechanismDigest`. An old saved domain file establishes its original domain only. Changed tools,
|
|
153
|
+
inputs, environment, scope, adapters or proof policy invalidate the dependent qualification. Every
|
|
154
|
+
change to the proof mechanism or policy requires fresh independent validation. Receipt replay never
|
|
155
|
+
grants approval or merge authority.
|
|
156
|
+
|
|
157
|
+
## Compatibility and delivery
|
|
158
|
+
|
|
159
|
+
The four qualification v1 schemas are additive. Existing verification/manifest v1–v4, conformance
|
|
160
|
+
v1 projections, schema bytes and the old extension lock remain unchanged. The new schema lock is
|
|
161
|
+
separate. [Migration notes](migration-orchestration-qualification-v1.md) describe opt-in adoption.
|
|
162
|
+
|
|
163
|
+
The complete candidate is verified with `pnpm check`, package smoke, the pinned public campaign,
|
|
164
|
+
negative gate witnesses and a fresh independent aggregate proof review. Local verification, hosted
|
|
165
|
+
GitHub CI, review and PR publication are separate delivery facts. Consumer readiness is conditional
|
|
166
|
+
on the [required obligation inventory](../examples/orchestration/consumer-obligations.json), never
|
|
167
|
+
on the public profile's success alone.
|
package/docs/reference.md
CHANGED
|
@@ -22,6 +22,8 @@ assertledger analyze . --json
|
|
|
22
22
|
assertledger schema verification-request --json
|
|
23
23
|
assertledger verify assertledger.request.json --allow-unsafe-execution --json
|
|
24
24
|
assertledger verify assertledger.container-request.json --container-runtime '["docker"]' --json
|
|
25
|
+
assertledger verify assertledger.windows-request.json --allow-windows-native-execution --json
|
|
26
|
+
assertledger import-witness witness.json --out evidence --allow-unsafe-execution --json
|
|
25
27
|
assertledger replay assertledger.manifest.json --json
|
|
26
28
|
assertledger provider --json
|
|
27
29
|
assertledger export assertledger.export-request.json --json
|
|
@@ -69,6 +71,11 @@ results go to stdout. Diagnostics go to stderr. `assertledger mcp` reserves stdo
|
|
|
69
71
|
trusted-local campaign and sets the request's local acknowledgement before validation. The flag does
|
|
70
72
|
not create a sandbox.
|
|
71
73
|
|
|
74
|
+
`--allow-windows-native-execution` authorizes a v4 request with `windows-native` isolation on a Windows
|
|
75
|
+
host, recorded as `WINDOWS_NATIVE_UNSANDBOXED`; it cannot be combined with the other backend flags.
|
|
76
|
+
`import-witness` replays a recorded red/green witness under exactly one operator-chosen backend; see
|
|
77
|
+
[witness import](witness-import.md) and the [v4 migration guide](migration-verification-v4.md).
|
|
78
|
+
|
|
72
79
|
A v2 request with `container` isolation runs without that flag: each execution uses a fresh
|
|
73
80
|
container from a digest-pinned local image through the operator's `--container-runtime` JSON argv,
|
|
74
81
|
which defaults to `["docker"]`. `check` selects the same backend with `--container-image`. Combining
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Witness import
|
|
2
|
+
|
|
3
|
+
`assertledger import-witness` replays a recorded red/green witness as a v4 campaign and verifies it.
|
|
4
|
+
The witness states what was observed; AssertLedger observes it again under its own taxonomy.
|
|
5
|
+
|
|
6
|
+
## Request
|
|
7
|
+
|
|
8
|
+
A `witness-import-request.v1.json` document names:
|
|
9
|
+
|
|
10
|
+
- `repository`: the root, exclusions, `includeDependencies` and the `git` mode, as in a
|
|
11
|
+
[v4 request](migration-verification-v4.md);
|
|
12
|
+
- `adapter`: `bun-test-designated`, with its executable and per-test timeout;
|
|
13
|
+
- `test` and `expectedFailure`: the existing designated test and the first line of its failure;
|
|
14
|
+
- `targets`: each mutated file with its `beforeDigest`, the SHA-256 of the bytes it replaces, and
|
|
15
|
+
its mutated `content`;
|
|
16
|
+
- `neutral`: an operator-supplied neutral control and its reason, or `null`;
|
|
17
|
+
- `requiredAttempts` and `timeoutMsPerExecution`.
|
|
18
|
+
|
|
19
|
+
Each target must still hold its base bytes (`WITNESS_TARGET_BASE_MISMATCH`) and its content must
|
|
20
|
+
differ from them (`WITNESS_TARGET_UNCHANGED`).
|
|
21
|
+
|
|
22
|
+
## Campaign
|
|
23
|
+
|
|
24
|
+
The repository is the reference world, the targets form the one target world, and the neutral
|
|
25
|
+
control is the operator's, or an identity control whose limit the manifest states. The policy is
|
|
26
|
+
fixed: every attempt in the target world must be an assertion failure attributed to the designated
|
|
27
|
+
test with the expected line, and every reference and neutral attempt must pass.
|
|
28
|
+
|
|
29
|
+
## Backend
|
|
30
|
+
|
|
31
|
+
The witness never selects its backend. The operator passes exactly one of:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
assertledger import-witness witness.json --out evidence --container-image oven/bun@sha256:DIGEST \
|
|
35
|
+
--container-runtime '["wsl.exe","-d","Ubuntu","--exec","docker"]'
|
|
36
|
+
assertledger import-witness witness.json --out evidence --allow-unsafe-execution
|
|
37
|
+
assertledger import-witness witness.json --out evidence --allow-windows-native-execution
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`--env NAME` replaces the default host environment allowlist of a local backend. Without a backend
|
|
41
|
+
the command refuses with exit code 4 and writes nothing.
|
|
42
|
+
|
|
43
|
+
## Output
|
|
44
|
+
|
|
45
|
+
`--out` must be a new directory outside the repository. It receives `executed-request.json`,
|
|
46
|
+
`summary.md` and, written last, `manifest.json`. The summary states the verdict, every observation,
|
|
47
|
+
the isolation level and the limitations; `--json` prints the manifest instead. The exit code follows
|
|
48
|
+
the verdict. Accept the witness only on `VERIFIED` plus `assertledger replay <manifest> --json`
|
|
49
|
+
with `valid: true`.
|
|
50
|
+
|
|
51
|
+
## A repository with installed dependencies
|
|
52
|
+
|
|
53
|
+
A Bun workspace installed with the isolated linker holds links in `node_modules`. Replay such a
|
|
54
|
+
witness from an archive of the exact revision with a hoisted install, and keep the dependencies in
|
|
55
|
+
the snapshot:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
git -C <repository> archive --format=tar --output=archive.tar <revision>
|
|
59
|
+
tar -xf archive.tar -C witness-repository
|
|
60
|
+
cd witness-repository
|
|
61
|
+
bun install --frozen-lockfile --linker hoisted --ignore-scripts
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Set `includeDependencies: true`. Workspace packages stay linked in `node_modules`; a link outside
|
|
65
|
+
the designated test's closure is left out and recorded, and one inside it refuses the import. A
|
|
66
|
+
test that asks Git for its tracked files needs `git: "synthesized"`. When a snapshot copy is slow
|
|
67
|
+
to read the first time, for example under on-access scanning, declare a per-test timeout that fits.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Public orchestration qualification
|
|
2
|
+
|
|
3
|
+
This independently authored workspace reproduces the evidence gap behind incident #911:
|
|
4
|
+
two extractible `node:test` assertions check command shapes and keep passing while actual
|
|
5
|
+
cache, failure propagation and pipeline routing faults are present. It contains no private
|
|
6
|
+
consumer source, URLs, credentials or hosted infrastructure.
|
|
7
|
+
|
|
8
|
+
The named profile `public-turbo-orchestration-2.11.7-bun-1.4.2` requires Turbo 2.11.7,
|
|
9
|
+
Bun 1.4.2, pnpm 12.9.1 and the exact executable identities recorded in its manifest.
|
|
10
|
+
Run the builder under Node with `tsx`, providing absolute paths to those executables:
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
node node_modules/tsx/dist/cli.mjs scripts/qualify-orchestration-profile.ts --turbo=/absolute/turbo --bun=/absolute/bun --pnpm=/absolute/pnpm --output=/absolute/evidence --commit=reviewed-commit --base=reviewed-base
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
On Windows `--pnpm` names the installed native `pnpm.exe`, rather than a PowerShell
|
|
17
|
+
shim, Corepack entry point or shell string. The selected tool directories precede the
|
|
18
|
+
operator's PATH. PATH and essential Windows environment values are sealed in the plan.
|
|
19
|
+
No tool installation is performed by the campaign builder.
|
|
20
|
+
|
|
21
|
+
Provision qualification tools in a separate disposable directory, preserving its generated
|
|
22
|
+
lockfile, rather than adding dependencies to AssertLedger or a consumer repository:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
pnpm --dir /absolute/qualification-tools add --ignore-scripts --save-exact turbo@2.11.7 pnpm@12.9.1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use the platform-specific native Turbo and pnpm executables inside that directory's
|
|
29
|
+
`node_modules/.pnpm` distributions. Install Bun 1.4.2 separately using the documented
|
|
30
|
+
platform installation method and pass its real executable. The builder probes versions
|
|
31
|
+
and hashes executable bytes. It deliberately refuses a different version. Provisioning
|
|
32
|
+
needs registry access; fixture setup runs offline with lifecycle scripts disabled.
|
|
33
|
+
Workspace links and normalized lockfiles are prepared before cold cache actions.
|
|
34
|
+
|
|
35
|
+
The operator's manifest declares seven obligations before execution. Reference and
|
|
36
|
+
documentation-only neutral worlds must pass. Fifteen declared fault worlds must mismatch
|
|
37
|
+
their named discriminants in two independent attempts. The leaf, Turbo and both wrapper
|
|
38
|
+
layers must return 7, as observed on this pinned profile. The expected nonzero reference result is not classified as a regression
|
|
39
|
+
assertion or a successful target kill.
|
|
40
|
+
Each layer validates the fresh nonce-bound semantic completion of its failed child, then emits
|
|
41
|
+
its own report with the observed exit. Ordinary errors, compilation failures and missing child
|
|
42
|
+
executables cannot supply that report. The trusted-local fixture reports are not authenticated.
|
|
43
|
+
|
|
44
|
+
Turbo build actions select the application and its leaf dependency. Each attempt has an
|
|
45
|
+
independent local cache, reused only across cold, warm and input-invalidation actions.
|
|
46
|
+
Warm actions delete generated outputs. Observations collect the real Turbo JSON summary,
|
|
47
|
+
selected task IDs, input task hashes, cache states, hashes of both required outputs, and
|
|
48
|
+
fresh action-specific nonce traces written by executing tasks. Cached console output does
|
|
49
|
+
not establish execution. The `check` task has caching disabled and must execute twice.
|
|
50
|
+
|
|
51
|
+
The cache worlds omit the verdict input, omit a restored output, or wrongly cache the
|
|
52
|
+
uncached task. Propagation worlds absorb an exit code, omit a mandatory stage, select no
|
|
53
|
+
work, overwrite failure with a later successful command, or reuse a seeded success.
|
|
54
|
+
The selected-task world removes the required dependency from the task graph. The CI worlds
|
|
55
|
+
disconnect the pull-request gate, add an unfulfilled changeset condition or make the gate manual
|
|
56
|
+
while preserving its command. The parser retains execution policy and full stage/parallel/step
|
|
57
|
+
ancestry, and refuses unsupported execution fields. It is an engine-owned asset outside the route
|
|
58
|
+
it observes. Configuration observation does not establish hosted execution.
|
|
59
|
+
|
|
60
|
+
Outputs are `manifest.json`, `receipt.json`, `replay.json`, `matrix.json` and
|
|
61
|
+
`incident-reproduction.json`. The builder exits nonzero if the profile is not QUALIFIED,
|
|
62
|
+
replay fails, or command-shape extraction detects an orchestration fault unexpectedly.
|
|
63
|
+
|
|
64
|
+
This public profile qualifies only its named local obligations. It never declares the
|
|
65
|
+
private consumer ready. Private suites, preloads, wrappers, browser/E2E/coverage behavior
|
|
66
|
+
and hosted Bitbucket execution require their own profile and evidence. Static CI routing
|
|
67
|
+
and local commands cannot discharge a hosted-pipeline obligation. Replay checks integrity
|
|
68
|
+
and deterministic semantics; it does not run commands again or authenticate their producer.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profileId": "modelo-suite-911-consumer-v1",
|
|
3
|
+
"consumerReady": false,
|
|
4
|
+
"qualificationStatus": "OPEN",
|
|
5
|
+
"inventoryAuthority": "operator inventory from consumer source inspection; independent from candidate selection",
|
|
6
|
+
"sourcePins": {
|
|
7
|
+
"bun": "1.4.2",
|
|
8
|
+
"pnpm": "12.9.1",
|
|
9
|
+
"turbo": "2.11.7",
|
|
10
|
+
"vitestCompatibility": "5.0.3"
|
|
11
|
+
},
|
|
12
|
+
"suiteGroups": [
|
|
13
|
+
{
|
|
14
|
+
"id": "workspace-tests",
|
|
15
|
+
"declaringManifests": 30,
|
|
16
|
+
"extraction": "UNAVAILABLE",
|
|
17
|
+
"status": "OPEN"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "workspace-e2e",
|
|
21
|
+
"declaringManifests": 9,
|
|
22
|
+
"extraction": "UNAVAILABLE",
|
|
23
|
+
"status": "OPEN"
|
|
24
|
+
},
|
|
25
|
+
{ "id": "bun-node-delivery", "suiteFiles": 10, "extraction": "UNAVAILABLE", "status": "OPEN" },
|
|
26
|
+
{
|
|
27
|
+
"id": "repository-shell",
|
|
28
|
+
"suiteFiles": null,
|
|
29
|
+
"extraction": "UNAVAILABLE",
|
|
30
|
+
"status": "OPEN",
|
|
31
|
+
"reason": "exact executed shell suite inventory requires consumer campaign"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"requiredObligations": [
|
|
35
|
+
{
|
|
36
|
+
"id": "complete-consumer-test-suites",
|
|
37
|
+
"kind": "tests",
|
|
38
|
+
"status": "OPEN",
|
|
39
|
+
"required": true,
|
|
40
|
+
"reason": "private complete suites have not been executed in this public campaign"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "consumer-preloads-and-test-forms",
|
|
44
|
+
"kind": "tests",
|
|
45
|
+
"status": "OPEN",
|
|
46
|
+
"required": true,
|
|
47
|
+
"reason": "Vitest compatibility, mocks, DOM, isolation, development conditions and filter forms need exact-consumer witnesses"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"id": "consumer-task-selection",
|
|
51
|
+
"kind": "selection",
|
|
52
|
+
"status": "OPEN",
|
|
53
|
+
"required": true,
|
|
54
|
+
"reason": "public dependency-selection witnesses qualify the public fixture, not the consumer graph"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "consumer-turbo-cache",
|
|
58
|
+
"kind": "cache",
|
|
59
|
+
"status": "OPEN",
|
|
60
|
+
"required": true,
|
|
61
|
+
"reason": "actual consumer configuration, persisted cache and dependencies need cold/warm/invalidation evidence"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "consumer-error-propagation",
|
|
65
|
+
"kind": "propagation",
|
|
66
|
+
"status": "OPEN",
|
|
67
|
+
"required": true,
|
|
68
|
+
"reason": "actual consumer command route requires its own leaf-to-terminal witness"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "consumer-wrappers",
|
|
72
|
+
"kind": "wrapper",
|
|
73
|
+
"status": "OPEN",
|
|
74
|
+
"required": true,
|
|
75
|
+
"reason": "shell/container/preflight wrapper closure requires actual route evidence"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "consumer-ci-configuration",
|
|
79
|
+
"kind": "ci-config",
|
|
80
|
+
"status": "OPEN",
|
|
81
|
+
"required": true,
|
|
82
|
+
"reason": "public YAML qualification is separate from the consumer configuration"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "consumer-ci-local-commands",
|
|
86
|
+
"kind": "ci-local",
|
|
87
|
+
"status": "OPEN",
|
|
88
|
+
"required": true,
|
|
89
|
+
"reason": "actual local CI commands and coverage gate must execute with controlled inputs"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "consumer-bitbucket-pipeline",
|
|
93
|
+
"kind": "ci-live",
|
|
94
|
+
"status": "OPEN",
|
|
95
|
+
"required": true,
|
|
96
|
+
"reason": "no independent exact-commit/base executed-step and terminal pipeline observation supplied"
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"reusableQualification": "public-turbo-orchestration-2.11.7-bun-1.4.2 only under its exact receipt validity conditions",
|
|
100
|
+
"mergeAuthority": false
|
|
101
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { failCommandArgs, wrapperCommandArgs } from "./commands.mjs";
|
|
4
|
+
|
|
5
|
+
test("structured Turbo failure selection", () => {
|
|
6
|
+
assert.deepEqual(failCommandArgs({ cacheDirectory: "mock-cache" }), [
|
|
7
|
+
"run",
|
|
8
|
+
"fail",
|
|
9
|
+
"--filter=@public/app...",
|
|
10
|
+
"--cache=local:rw",
|
|
11
|
+
"--cache-dir=mock-cache",
|
|
12
|
+
"--summarize",
|
|
13
|
+
]);
|
|
14
|
+
assert.deepEqual(failCommandArgs({ emptySelection: true, cacheDirectory: "mock-cache" }), [
|
|
15
|
+
"run",
|
|
16
|
+
"fail",
|
|
17
|
+
"--filter=!@public/*",
|
|
18
|
+
"--cache=local:rw",
|
|
19
|
+
"--cache-dir=mock-cache",
|
|
20
|
+
"--summarize",
|
|
21
|
+
]);
|
|
22
|
+
});
|
|
23
|
+
test("structured wrapper command", () => {
|
|
24
|
+
assert.deepEqual(wrapperCommandArgs("wrapper.mjs"), ["wrapper.mjs", "orchestrator"]);
|
|
25
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function failCommandArgs({ emptySelection = false, cacheDirectory }) {
|
|
2
|
+
return [
|
|
3
|
+
"run",
|
|
4
|
+
"fail",
|
|
5
|
+
emptySelection ? "--filter=!@public/*" : "--filter=@public/app...",
|
|
6
|
+
"--cache=local:rw",
|
|
7
|
+
`--cache-dir=${cacheDirectory}`,
|
|
8
|
+
"--summarize",
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function wrapperCommandArgs(wrapperPath) {
|
|
13
|
+
return [wrapperPath, "orchestrator"];
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
|
|
4
|
+
export function complete(exitCode) {
|
|
5
|
+
writeFileSync(
|
|
6
|
+
process.env.ASSERTLEDGER_QUALIFICATION_RESULT_FILE,
|
|
7
|
+
`${JSON.stringify({
|
|
8
|
+
facts: { commandOutcome: exitCode === 0 ? "PASS" : "EXPECTED_FAILURE", exitCode },
|
|
9
|
+
nonce: process.env.ASSERTLEDGER_QUALIFICATION_NONCE,
|
|
10
|
+
protocolVersion: "1.0.0",
|
|
11
|
+
})}\n`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function execute(executable, args, suffix) {
|
|
16
|
+
const report = `${process.env.ASSERTLEDGER_QUALIFICATION_RESULT_FILE}.${suffix}`;
|
|
17
|
+
rmSync(report, { force: true });
|
|
18
|
+
const result = spawnSync(executable, args, {
|
|
19
|
+
stdio: "inherit",
|
|
20
|
+
env: { ...process.env, ASSERTLEDGER_QUALIFICATION_RESULT_FILE: report },
|
|
21
|
+
});
|
|
22
|
+
if (result.error || result.signal || result.status === null) {
|
|
23
|
+
throw new Error("PUBLIC_CHILD_OPERATIONAL_FAILURE", { cause: result.error });
|
|
24
|
+
}
|
|
25
|
+
if (result.status !== 0) {
|
|
26
|
+
// A normal failed leaf must attest completion through each wrapper. Numeric
|
|
27
|
+
// exits, compiler diagnostics and thrown errors are not semantic attestations.
|
|
28
|
+
const document = JSON.parse(readFileSync(report, "utf8"));
|
|
29
|
+
if (
|
|
30
|
+
document.protocolVersion !== "1.0.0" ||
|
|
31
|
+
document.nonce !== process.env.ASSERTLEDGER_QUALIFICATION_NONCE ||
|
|
32
|
+
document.facts.commandOutcome !== "EXPECTED_FAILURE" ||
|
|
33
|
+
document.facts.exitCode !== result.status
|
|
34
|
+
) {
|
|
35
|
+
throw new Error("PUBLIC_CHILD_COMPLETION_MISSING");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result.status;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
initial
|