diff --git a/.github/workflows/client-v1-conformance.yml b/.github/workflows/client-v1-conformance.yml index 0061e4ad..be5b78b1 100644 --- a/.github/workflows/client-v1-conformance.yml +++ b/.github/workflows/client-v1-conformance.yml @@ -8818,14 +8818,14 @@ jobs: @('scripts\owned-temp-directory.mjs', 6965, 'a9c55c85cf2b7d70310d278bafd2c8e7695d66f4ae38b9c3f1f12fce0b442095'), @('scripts\phase1-artifact-secret-scan.mjs', 21183, 'be0ec302b9c4372f232d6bd1efcba873fd3380cc5de7f756cd0b9eeeec07222a'), @('scripts\phase1-conformance-lock.mjs', 48544, '2d8db4e5442fe2f585c0b005d2b059832b27d88047441e0e7dbc26dc22a00e99'), - @('scripts\phase1-conformance.mjs', 199227, 'fc232db10c270ec92fcd700ad44e213c04abee01492c9804f82643b4513b2199'), + @('scripts\phase1-conformance.mjs', 199944, '67ba91257a71c36c7d91ef01796c5a348d106e40b4a6f1ef59fde6980a5ba584'), @('scripts\phase1-evidence-contract.mjs', 15088, '24180ae03835fa6aac45559682adb3c1e626bab76466eddc55b9e2300f0a2b7f'), @('scripts\phase1-evidence-runtime.mjs', 6078, '3d227c354e6d908c5912d2b8244336e3b79c3bbd4dec79b0ad219ed65b8cb159'), @('scripts\phase1-linux-secret-service.mjs', 4270, 'ddf834c6f57853c5116b4b1f345952a218ff0687c5d741737c68e20bc2ecda92'), @('scripts\phase1-macos-keychain.mjs', 5091, 'ab0c2dd08cf606d9502f5da206175707d471d99f484e8c8c79b5b08a5772b9a4'), @('scripts\phase1-process-supervisor.mjs', 3820, '16b51fb1a33b4bfef98daca549aacf5dc2d2c098cfbd664753b69c940d1e6f6c'), @('scripts\phase1-schema-v2-evidence.mjs', 51642, 'a7cab994aa0ee97baceb4b2c475ec1ff253ae5681f39e2c3d15fb1035b2d2387'), - @('scripts\phase1-schema-v2-producer.mjs', 165661, '4e938521a6436c3441781b91f0e0f52fe6e3ac6f44faedfcab0458b144ccd714'), + @('scripts\phase1-schema-v2-producer.mjs', 168581, '023b65fbf2a6b29dc8a85c14e0eb002f5e10751308f5af372505ba75273a8beb'), @('scripts\process-owned-artifact-root.mjs', 11205, '9ee158453044cd57b91c77c50262092a91993c6b1533b6584c61e1cbadfd794a'), @('scripts\supervised-exec.mjs', 2875, 'a5edfd985b934d3b46247a0da3141682c411d30bb582edf87ae7b29791dad65b'), @('scripts\supervisor-status.mjs', 854, 'ac332ca7b6b040ecc846088bb3a6ad5e7112a0454eb3ea71d2a819d55e64254e') @@ -9510,14 +9510,14 @@ jobs: ['scripts/owned-temp-directory.mjs', [6965, 'a9c55c85cf2b7d70310d278bafd2c8e7695d66f4ae38b9c3f1f12fce0b442095']], ['scripts/phase1-artifact-secret-scan.mjs', [21183, 'be0ec302b9c4372f232d6bd1efcba873fd3380cc5de7f756cd0b9eeeec07222a']], ['scripts/phase1-conformance-lock.mjs', [48544, '2d8db4e5442fe2f585c0b005d2b059832b27d88047441e0e7dbc26dc22a00e99']], - ['scripts/phase1-conformance.mjs', [199227, 'fc232db10c270ec92fcd700ad44e213c04abee01492c9804f82643b4513b2199']], + ['scripts/phase1-conformance.mjs', [199944, '67ba91257a71c36c7d91ef01796c5a348d106e40b4a6f1ef59fde6980a5ba584']], ['scripts/phase1-evidence-contract.mjs', [15088, '24180ae03835fa6aac45559682adb3c1e626bab76466eddc55b9e2300f0a2b7f']], ['scripts/phase1-evidence-runtime.mjs', [6078, '3d227c354e6d908c5912d2b8244336e3b79c3bbd4dec79b0ad219ed65b8cb159']], ['scripts/phase1-linux-secret-service.mjs', [4270, 'ddf834c6f57853c5116b4b1f345952a218ff0687c5d741737c68e20bc2ecda92']], ['scripts/phase1-macos-keychain.mjs', [5091, 'ab0c2dd08cf606d9502f5da206175707d471d99f484e8c8c79b5b08a5772b9a4']], ['scripts/phase1-process-supervisor.mjs', [3820, '16b51fb1a33b4bfef98daca549aacf5dc2d2c098cfbd664753b69c940d1e6f6c']], ['scripts/phase1-schema-v2-evidence.mjs', [51642, 'a7cab994aa0ee97baceb4b2c475ec1ff253ae5681f39e2c3d15fb1035b2d2387']], - ['scripts/phase1-schema-v2-producer.mjs', [165661, '4e938521a6436c3441781b91f0e0f52fe6e3ac6f44faedfcab0458b144ccd714']], + ['scripts/phase1-schema-v2-producer.mjs', [168581, '023b65fbf2a6b29dc8a85c14e0eb002f5e10751308f5af372505ba75273a8beb']], ['scripts/process-owned-artifact-root.mjs', [11205, '9ee158453044cd57b91c77c50262092a91993c6b1533b6584c61e1cbadfd794a']], ['scripts/supervised-exec.mjs', [2875, 'a5edfd985b934d3b46247a0da3141682c411d30bb582edf87ae7b29791dad65b']], ['scripts/supervisor-status.mjs', [854, 'ac332ca7b6b040ecc846088bb3a6ad5e7112a0454eb3ea71d2a819d55e64254e']], diff --git a/docs/phase1-conformance.md b/docs/phase1-conformance.md index b1b8d11f..74cfe0cf 100644 --- a/docs/phase1-conformance.md +++ b/docs/phase1-conformance.md @@ -1046,6 +1046,12 @@ owned-artifact cleanup retain an earlier execution failure instead of replacing it. Captured command output, filesystem paths, and the underlying error remain private in-memory causes and are not serialized into the public failure result. +Checkout failures identify the Chat, SDK, Cave, Coven, integrity, validator, or +producer boundary. Evidence finalization failures identify report construction, +operator-state capture, isolation, assertions, evidence construction, serialization, +scanning, or retention. These allowlisted diagnostics survive nested stage wrappers; +underlying command output and private paths remain excluded from public errors. + Frozen consumer failures are further bounded to authority verification, artifact loading, harness creation, offline installation, isolation checks, Cave fixture matching, packed build, packed verification, or cleanup. The @@ -1091,20 +1097,20 @@ The later SDK validator repin must use these exact committed file bytes: | File | Bytes | SHA-256 | | --- | ---: | --- | -| `.github/workflows/client-v1-conformance.yml` | 463,033 | `6f1a362be64f1bb0a6bac5980ac4acb87af7fed525a33d55ace9d111b9238fe3` | +| `.github/workflows/client-v1-conformance.yml` | 463,033 | `e76c4361fb94c0b9525680f2aac176ca377174665b0323b5aefaf219fa452d02` | | `scripts/contract-canary.mjs` | 39,346 | `63b2a95c8563143d0d748d36ef2bdbae656e7babdb23b986efca97bbbc9b8d83` | | `scripts/executable-resolution.mjs` | 9,154 | `31e3c412ff8c835f14522f36a59e91f4a4ba82913210ae8e3b4455217503f430` | | `scripts/owned-temp-directory.mjs` | 6,965 | `a9c55c85cf2b7d70310d278bafd2c8e7695d66f4ae38b9c3f1f12fce0b442095` | | `scripts/phase1-artifact-secret-scan.mjs` | 21,183 | `be0ec302b9c4372f232d6bd1efcba873fd3380cc5de7f756cd0b9eeeec07222a` | | `scripts/phase1-conformance-lock.mjs` | 48,544 | `2d8db4e5442fe2f585c0b005d2b059832b27d88047441e0e7dbc26dc22a00e99` | -| `scripts/phase1-conformance.mjs` | 199,227 | `fc232db10c270ec92fcd700ad44e213c04abee01492c9804f82643b4513b2199` | +| `scripts/phase1-conformance.mjs` | 199,944 | `67ba91257a71c36c7d91ef01796c5a348d106e40b4a6f1ef59fde6980a5ba584` | | `scripts/phase1-evidence-contract.mjs` | 15,088 | `24180ae03835fa6aac45559682adb3c1e626bab76466eddc55b9e2300f0a2b7f` | | `scripts/phase1-evidence-runtime.mjs` | 6,078 | `3d227c354e6d908c5912d2b8244336e3b79c3bbd4dec79b0ad219ed65b8cb159` | | `scripts/phase1-linux-secret-service.mjs` | 4,270 | `ddf834c6f57853c5116b4b1f345952a218ff0687c5d741737c68e20bc2ecda92` | | `scripts/phase1-macos-keychain.mjs` | 5,091 | `ab0c2dd08cf606d9502f5da206175707d471d99f484e8c8c79b5b08a5772b9a4` | | `scripts/phase1-process-supervisor.mjs` | 3,820 | `16b51fb1a33b4bfef98daca549aacf5dc2d2c098cfbd664753b69c940d1e6f6c` | | `scripts/phase1-schema-v2-evidence.mjs` | 51,642 | `a7cab994aa0ee97baceb4b2c475ec1ff253ae5681f39e2c3d15fb1035b2d2387` | -| `scripts/phase1-schema-v2-producer.mjs` | 165,661 | `4e938521a6436c3441781b91f0e0f52fe6e3ac6f44faedfcab0458b144ccd714` | +| `scripts/phase1-schema-v2-producer.mjs` | 168,581 | `023b65fbf2a6b29dc8a85c14e0eb002f5e10751308f5af372505ba75273a8beb` | | `scripts/process-owned-artifact-root.mjs` | 11,205 | `9ee158453044cd57b91c77c50262092a91993c6b1533b6584c61e1cbadfd794a` | | `scripts/supervised-exec.mjs` | 2,875 | `a5edfd985b934d3b46247a0da3141682c411d30bb582edf87ae7b29791dad65b` | | `scripts/supervisor-status.mjs` | 854 | `ac332ca7b6b040ecc846088bb3a6ad5e7112a0454eb3ea71d2a819d55e64254e` | diff --git a/phase1-conformance.lock.json b/phase1-conformance.lock.json index 9832d852..00e998b4 100644 --- a/phase1-conformance.lock.json +++ b/phase1-conformance.lock.json @@ -18,16 +18,16 @@ }, "harness": { "repository": "OpenCoven/chat", - "revision": "223adb33c0595df244feb4561aa0273c4afecf48" + "revision": "50ad59966d9ebdae3a97459bc21670e461bd6dd9" }, "harnessAuthority": { - "revision": "223adb33c0595df244feb4561aa0273c4afecf48", - "tree": "34b5836cb9f901466971a89afef43d8331e82517", + "revision": "50ad59966d9ebdae3a97459bc21670e461bd6dd9", + "tree": "0883076e180169216be4d6e339bb9f4bb225c422", "files": [ { "path": "scripts/phase1-conformance.mjs", - "blob": "c69fb54d0a4123b315d9fcc005c609410347ddd5", - "sha256": "fc232db10c270ec92fcd700ad44e213c04abee01492c9804f82643b4513b2199" + "blob": "2d6ee8c26ebfc78cc0f4959079af5c31fdab2f64", + "sha256": "67ba91257a71c36c7d91ef01796c5a348d106e40b4a6f1ef59fde6980a5ba584" }, { "path": "scripts/phase1-conformance-launcher.sh", @@ -81,8 +81,8 @@ }, { "path": "scripts/phase1-schema-v2-producer.mjs", - "blob": "64198513dec00d35e0dc189eb179fa92c843f724", - "sha256": "4e938521a6436c3441781b91f0e0f52fe6e3ac6f44faedfcab0458b144ccd714" + "blob": "9ecfe45795c83d1bd5a11b0053972bb912909ea5", + "sha256": "023b65fbf2a6b29dc8a85c14e0eb002f5e10751308f5af372505ba75273a8beb" }, { "path": "scripts/phase1-linux-secret-service.mjs", @@ -146,8 +146,8 @@ }, { "path": ".github/workflows/client-v1-conformance.yml", - "blob": "0061e4ad2b7abd1a3864070134c69ffea7cd28df", - "sha256": "6f1a362be64f1bb0a6bac5980ac4acb87af7fed525a33d55ace9d111b9238fe3" + "blob": "be5b78b10dc756acd370e72967f82ad79f1bf343", + "sha256": "e76c4361fb94c0b9525680f2aac176ca377174665b0323b5aefaf219fa452d02" } ], "productionDeltas": [ diff --git a/scripts/phase1-conformance.mjs b/scripts/phase1-conformance.mjs index c69fb54d..2d6ee8c2 100644 --- a/scripts/phase1-conformance.mjs +++ b/scripts/phase1-conformance.mjs @@ -309,7 +309,22 @@ const publicPhase1DiagnosticIds = new Set([ 'phase1.environment.directories.failed', 'phase1.stage.toolchain.failed', 'phase1.stage.checkouts.failed', + 'phase1.stage.checkouts.chat.failed', + 'phase1.stage.checkouts.sdk.failed', + 'phase1.stage.checkouts.cave.failed', + 'phase1.stage.checkouts.coven.failed', + 'phase1.stage.checkouts.integrity.failed', + 'phase1.stage.checkouts.validator.failed', + 'phase1.stage.checkouts.producer.failed', 'phase1.stage.evidence-authority.failed', + 'phase1.stage.evidence-authority.report.failed', + 'phase1.stage.evidence-authority.operator-state.failed', + 'phase1.stage.evidence-authority.isolation.failed', + 'phase1.stage.evidence-authority.assertions.failed', + 'phase1.stage.evidence-authority.build.failed', + 'phase1.stage.evidence-authority.serialize.failed', + 'phase1.stage.evidence-authority.scan.failed', + 'phase1.stage.evidence-authority.retain.failed', 'phase1.stage.packaging.failed', 'phase1.packaging.frozen-consumer.failed', ...FROZEN_PACKED_CONSUMER_STAGES.map( diff --git a/scripts/phase1-schema-v2-producer.mjs b/scripts/phase1-schema-v2-producer.mjs index 64198513..9ecfe457 100644 --- a/scripts/phase1-schema-v2-producer.mjs +++ b/scripts/phase1-schema-v2-producer.mjs @@ -173,7 +173,22 @@ const publicFailureDiagnosticSet = new Set([ 'phase1.stage.execution-root.failed', 'phase1.stage.environment.failed', 'phase1.stage.checkouts.failed', + 'phase1.stage.checkouts.chat.failed', + 'phase1.stage.checkouts.sdk.failed', + 'phase1.stage.checkouts.cave.failed', + 'phase1.stage.checkouts.coven.failed', + 'phase1.stage.checkouts.integrity.failed', + 'phase1.stage.checkouts.validator.failed', + 'phase1.stage.checkouts.producer.failed', 'phase1.stage.evidence-authority.failed', + 'phase1.stage.evidence-authority.report.failed', + 'phase1.stage.evidence-authority.operator-state.failed', + 'phase1.stage.evidence-authority.isolation.failed', + 'phase1.stage.evidence-authority.assertions.failed', + 'phase1.stage.evidence-authority.build.failed', + 'phase1.stage.evidence-authority.serialize.failed', + 'phase1.stage.evidence-authority.scan.failed', + 'phase1.stage.evidence-authority.retain.failed', 'phase1.stage.toolchain.failed', 'phase1.stage.packaging.failed', 'phase1.packaging.frozen-consumer.failed', @@ -2080,67 +2095,84 @@ async function createExactCheckouts(artifactRoot, options, lock, environment) { caveRoot: resolve(checkoutsRoot, 'cave'), covenRoot: resolve(checkoutsRoot, 'coven'), }; - await cloneExactCheckout({ - artifactRoot, - sourceRoot: options.chatSourceRoot, - destinationRoot: roots.chatRoot, - repository: lock.chat.repository, - revision: lock.chat.revision, - environment, - label: 'Chat', - }); - await cloneExactCheckout({ - artifactRoot, - sourceRoot: options.sdkSourceRoot, - destinationRoot: roots.sdkRoot, - repository: lock.sdk.repository, - revision: lock.sdk.revision, - environment, - label: 'SDK', - }); - await cloneExactCheckout({ - artifactRoot, - sourceRoot: options.caveSourceRoot, - destinationRoot: roots.caveRoot, - repository: lock.cave.repository, - revision: lock.cave.revision, - environment, - label: 'Cave', - }); - await cloneExactCheckout({ - artifactRoot, - sourceRoot: options.covenSourceRoot, - destinationRoot: roots.covenRoot, - repository: lock.coven.repository, - revision: lock.coven.revision, - environment, - label: 'Coven', + await runSchemaV2StageAsync('phase1.stage.checkouts.chat.failed', () => + cloneExactCheckout({ + artifactRoot, + sourceRoot: options.chatSourceRoot, + destinationRoot: roots.chatRoot, + repository: lock.chat.repository, + revision: lock.chat.revision, + environment, + label: 'Chat', + }), + ); + await runSchemaV2StageAsync('phase1.stage.checkouts.sdk.failed', () => + cloneExactCheckout({ + artifactRoot, + sourceRoot: options.sdkSourceRoot, + destinationRoot: roots.sdkRoot, + repository: lock.sdk.repository, + revision: lock.sdk.revision, + environment, + label: 'SDK', + }), + ); + await runSchemaV2StageAsync('phase1.stage.checkouts.cave.failed', () => + cloneExactCheckout({ + artifactRoot, + sourceRoot: options.caveSourceRoot, + destinationRoot: roots.caveRoot, + repository: lock.cave.repository, + revision: lock.cave.revision, + environment, + label: 'Cave', + }), + ); + await runSchemaV2StageAsync('phase1.stage.checkouts.coven.failed', () => + cloneExactCheckout({ + artifactRoot, + sourceRoot: options.covenSourceRoot, + destinationRoot: roots.covenRoot, + repository: lock.coven.repository, + revision: lock.coven.revision, + environment, + label: 'Coven', + }), + ); + runSchemaV2PreflightStage('phase1.stage.checkouts.integrity.failed', () => { + assertCleanPhase1Checkouts(roots); + assertPhase1CheckoutHeads(lock, roots); }); - assertCleanPhase1Checkouts(roots); - assertPhase1CheckoutHeads(lock, roots); if (options.platform !== undefined) { roots.validatorRoot = resolve(checkoutsRoot, 'validator'); - await cloneExactCheckout({ - artifactRoot, - sourceRoot: options.sdkValidatorSourceRoot, - destinationRoot: roots.validatorRoot, - repository: 'OpenCoven/sdk', - revision: options.validatorRevision, - environment, - label: 'SDK validator', - }); - assertCleanPhase1Checkout(roots.validatorRoot, 'SDK validator checkout'); - const validatorIdentity = readPhase1CheckoutIdentity( - roots.validatorRoot, - 'SDK validator checkout', + roots.validatorIdentity = await runSchemaV2StageAsync( + 'phase1.stage.checkouts.validator.failed', + async () => { + await cloneExactCheckout({ + artifactRoot, + sourceRoot: options.sdkValidatorSourceRoot, + destinationRoot: roots.validatorRoot, + repository: 'OpenCoven/sdk', + revision: options.validatorRevision, + environment, + label: 'SDK validator', + }); + assertCleanPhase1Checkout(roots.validatorRoot, 'SDK validator checkout'); + const validatorIdentity = readPhase1CheckoutIdentity( + roots.validatorRoot, + 'SDK validator checkout', + ); + if (validatorIdentity.revision !== options.validatorRevision) { + throw new Error('SDK validator checkout does not match the selected revision.'); + } + return validatorIdentity; + }, ); - if (validatorIdentity.revision !== options.validatorRevision) { - throw new Error('SDK validator checkout does not match the selected revision.'); - } - roots.validatorIdentity = validatorIdentity; Object.assign( roots, - await cloneProducerCheckout(artifactRoot, options.chatSourceRoot, environment), + await runSchemaV2StageAsync('phase1.stage.checkouts.producer.failed', () => + cloneProducerCheckout(artifactRoot, options.chatSourceRoot, environment), + ), ); } return roots; @@ -2953,7 +2985,7 @@ export async function withOwnedArtifactRoot(ownedRoot, action) { if (actionFailed && cleanupFailed) { throw new AggregateError( [actionFailure, cleanupFailure], - 'Owned artifact action and cleanup both failed.', + schemaV2FailureDiagnostic(actionFailure, 'Owned artifact action and cleanup both failed.'), ); } if (actionFailed) { @@ -4788,27 +4820,33 @@ export async function runSchemaV2Conformance(options, lock, harnessAuthorityVeri const report = await runSchemaV2StageAsync('phase1.stage.evidence-authority.failed', () => withOwnedArtifactRoot(reportRoot, async () => { - const completedReport = buildPhase1Report({ - assertions: [...results.values()], - revisions: { - chat: lock.chat.revision, - sdk: lock.sdk.revision, - cave: lock.cave.revision, - coven: lock.coven.revision, - }, - artifactDigests, - versions: { - harness: schemaV2 ? PHASE1_SCHEMA_V2_HARNESS_VERSION : '1.0.0', - node: process.versions.node, - ...(schemaV2 && toolchain !== undefined - ? { - rust: toolchain.rustVersion, - tauri: toolchain.tauriVersion, - } - : {}), - }, - }); - scanPhase1ArtifactText(`${JSON.stringify(completedReport)}\n`); + const completedReport = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.report.failed', + () => + buildPhase1Report({ + assertions: [...results.values()], + revisions: { + chat: lock.chat.revision, + sdk: lock.sdk.revision, + cave: lock.cave.revision, + coven: lock.coven.revision, + }, + artifactDigests, + versions: { + harness: schemaV2 ? PHASE1_SCHEMA_V2_HARNESS_VERSION : '1.0.0', + node: process.versions.node, + ...(schemaV2 && toolchain !== undefined + ? { + rust: toolchain.rustVersion, + tauri: toolchain.tauriVersion, + } + : {}), + }, + }), + ); + runSchemaV2PreflightStage('phase1.stage.evidence-authority.report.failed', () => + scanPhase1ArtifactText(`${JSON.stringify(completedReport)}\n`), + ); if (schemaV2) { if ( @@ -4832,101 +4870,124 @@ export async function runSchemaV2Conformance(options, lock, harnessAuthorityVeri completedReport, ); } - const operatorAfter = captureOperatorFilesystemState(operatorHomes); - const isolation = buildIsolationEvidence({ - operatorBefore, - operatorAfter, - nativeBeforeSha256: nativeProof.beforeSha256, - nativeAfterSha256: nativeProof.afterSha256, - opaqueIds: [ - randomBytes(16).toString('hex'), - randomBytes(16).toString('hex'), - randomBytes(16).toString('hex'), - nativeProof.opaqueId, - ], - }); - const observedAssertions = buildObservedSchemaV2Assertions({ - registry: sdkContract.registry, - platform: options.platform, - packageObservations, - primaryReport: completedReport, - caveRecord, - native: nativeProof, - coven: covenProof, - tests: observationTests, - scansPassed: true, - }); - const evidence = buildSchemaV2PlatformEvidence({ - primaryReport: completedReport, - caveRecord, - platform: options.platform, - timing: { - startedAt, - completedAt: new Date().toISOString(), - }, - sdkContract, - observedAssertions, - verified: { - validator: sdkContract.validator, - ...verifiedIdentities, - harness: { - ...producer.harness, - invocationId: randomUUID(), - }, - artifacts: evidenceArtifacts, - environment: { - os: process.platform, - arch: process.arch, - ...toolchain, - nativeCustody: { - backend: nativeProof.backend, - available: true, + const operatorAfter = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.operator-state.failed', + () => captureOperatorFilesystemState(operatorHomes), + ); + const isolation = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.isolation.failed', + () => + buildIsolationEvidence({ + operatorBefore, + operatorAfter, + nativeBeforeSha256: nativeProof.beforeSha256, + nativeAfterSha256: nativeProof.afterSha256, + opaqueIds: [ + randomBytes(16).toString('hex'), + randomBytes(16).toString('hex'), + randomBytes(16).toString('hex'), + nativeProof.opaqueId, + ], + }), + ); + const observedAssertions = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.assertions.failed', + () => + buildObservedSchemaV2Assertions({ + registry: sdkContract.registry, + platform: options.platform, + packageObservations, + primaryReport: completedReport, + caveRecord, + native: nativeProof, + coven: covenProof, + tests: observationTests, + scansPassed: true, + }), + ); + const evidence = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.build.failed', + () => + buildSchemaV2PlatformEvidence({ + primaryReport: completedReport, + caveRecord, + platform: options.platform, + timing: { + startedAt, + completedAt: new Date().toISOString(), }, - covenIdentity: { - backend: CANONICAL_PLATFORM_ENVIRONMENTS[options.platform].covenIdentity, - available: true, + sdkContract, + observedAssertions, + verified: { + validator: sdkContract.validator, + ...verifiedIdentities, + harness: { + ...producer.harness, + invocationId: randomUUID(), + }, + artifacts: evidenceArtifacts, + environment: { + os: process.platform, + arch: process.arch, + ...toolchain, + nativeCustody: { + backend: nativeProof.backend, + available: true, + }, + covenIdentity: { + backend: CANONICAL_PLATFORM_ENVIRONMENTS[options.platform].covenIdentity, + available: true, + }, + }, + isolation, }, + }), + ); + const canonical = runSchemaV2PreflightStage( + 'phase1.stage.evidence-authority.serialize.failed', + () => + serializeValidatedSchemaV2PlatformEvidence(evidence, { + contract: sdkContract.contract, + schema: sdkContract.schema, + }), + ); + runSchemaV2PreflightStage('phase1.stage.evidence-authority.scan.failed', () => + scanPhase1ArtifactText(canonical, { + validateReport(_value, contents) { + sdkContract.contract.parsePlatformEvidence( + contents, + 'Chat retained schema-v2 platform evidence', + sdkContract.schema, + ); }, - isolation, - }, - }); - const canonical = serializeValidatedSchemaV2PlatformEvidence(evidence, { - contract: sdkContract.contract, - schema: sdkContract.schema, - }); - scanPhase1ArtifactText(canonical, { - validateReport(_value, contents) { - sdkContract.contract.parsePlatformEvidence( - contents, - 'Chat retained schema-v2 platform evidence', - sdkContract.schema, - ); - }, - }); + }), + ); const reportPath = resolve(reportRoot.rootPath, 'record.json'); - writeFileSync(reportPath, canonical, { mode: 0o600 }); - await reportRoot.retainSanitizedJsonReport({ - reportPath, - destinationPath: options.outputPath, - validateReport(_value, bytes) { - sdkContract.contract.parsePlatformEvidence( - bytes.toString('utf8'), - 'Chat retained schema-v2 platform evidence', - sdkContract.schema, - ); - }, - secretScan: ({ reportPath: scannedPath }) => { - const contents = readFileSync(scannedPath, 'utf8'); - scanPhase1ArtifactText(contents, { - validateReport() { - sdkContract.contract.parsePlatformEvidence( - contents, - 'Chat retained schema-v2 platform evidence', - sdkContract.schema, - ); - }, - }); - }, + await runSchemaV2StageAsync('phase1.stage.evidence-authority.retain.failed', async () => { + writeFileSync(reportPath, canonical, { mode: 0o600 }); + await reportRoot.retainSanitizedJsonReport({ + reportPath, + destinationPath: options.outputPath, + validateReport(_value, bytes) { + sdkContract.contract.parsePlatformEvidence( + bytes.toString('utf8'), + 'Chat retained schema-v2 platform evidence', + sdkContract.schema, + ); + }, + secretScan: ({ reportPath: scannedPath }) => { + const contents = readFileSync(scannedPath, 'utf8'); + scanPhase1ArtifactText(contents, { + validateReport() { + sdkContract.contract.parsePlatformEvidence( + contents, + 'Chat retained schema-v2 platform evidence', + sdkContract.schema, + ); + }, + }); + }, + }); }); return evidence; } diff --git a/src/phase1-conformance-lock.test.ts b/src/phase1-conformance-lock.test.ts index d9f1651a..5d034df5 100644 --- a/src/phase1-conformance-lock.test.ts +++ b/src/phase1-conformance-lock.test.ts @@ -79,13 +79,13 @@ const committedHarnessAuthority = JSON.parse( readFileSync(resolve(projectRoot, 'phase1-conformance.lock.json'), 'utf8'), ).harnessAuthority; const expectedBehaviorAuthority = { - revision: '223adb33c0595df244feb4561aa0273c4afecf48', - tree: '34b5836cb9f901466971a89afef43d8331e82517', + revision: '50ad59966d9ebdae3a97459bc21670e461bd6dd9', + tree: '0883076e180169216be4d6e339bb9f4bb225c422', files: [ { path: 'scripts/phase1-conformance.mjs', - blob: 'c69fb54d0a4123b315d9fcc005c609410347ddd5', - sha256: 'fc232db10c270ec92fcd700ad44e213c04abee01492c9804f82643b4513b2199', + blob: '2d6ee8c26ebfc78cc0f4959079af5c31fdab2f64', + sha256: '67ba91257a71c36c7d91ef01796c5a348d106e40b4a6f1ef59fde6980a5ba584', }, { path: 'scripts/phase1-conformance-lock.mjs', @@ -99,8 +99,8 @@ const expectedBehaviorAuthority = { }, { path: 'scripts/phase1-schema-v2-producer.mjs', - blob: '64198513dec00d35e0dc189eb179fa92c843f724', - sha256: '4e938521a6436c3441781b91f0e0f52fe6e3ac6f44faedfcab0458b144ccd714', + blob: '9ecfe45795c83d1bd5a11b0053972bb912909ea5', + sha256: '023b65fbf2a6b29dc8a85c14e0eb002f5e10751308f5af372505ba75273a8beb', }, { path: 'scripts/unix-producer-supervisor.sh', @@ -124,8 +124,8 @@ const expectedBehaviorAuthority = { }, { path: '.github/workflows/client-v1-conformance.yml', - blob: '0061e4ad2b7abd1a3864070134c69ffea7cd28df', - sha256: '6f1a362be64f1bb0a6bac5980ac4acb87af7fed525a33d55ace9d111b9238fe3', + blob: 'be5b78b10dc756acd370e72967f82ad79f1bf343', + sha256: 'e76c4361fb94c0b9525680f2aac176ca377174665b0323b5aefaf219fa452d02', }, ], } as const; diff --git a/src/phase1-conformance.test.ts b/src/phase1-conformance.test.ts index cd1098dc..f30e4de4 100644 --- a/src/phase1-conformance.test.ts +++ b/src/phase1-conformance.test.ts @@ -1335,6 +1335,95 @@ describe('Phase 1 real-authority conformance harness', () => { }); }); + test('preserves bounded checkout and evidence-finalization substage diagnostics', async () => { + // @ts-expect-error The executable script intentionally has no declaration file. + const producer = (await import('../scripts/phase1-schema-v2-producer.mjs')) as Record< + string, + unknown + >; + const runStage = producer.runSchemaV2StageAsync; + expect(runStage).toBeTypeOf('function'); + if (typeof runStage !== 'function') { + return; + } + + const stages = [ + 'phase1.stage.checkouts.chat.failed', + 'phase1.stage.checkouts.sdk.failed', + 'phase1.stage.checkouts.cave.failed', + 'phase1.stage.checkouts.coven.failed', + 'phase1.stage.checkouts.integrity.failed', + 'phase1.stage.checkouts.validator.failed', + 'phase1.stage.checkouts.producer.failed', + 'phase1.stage.evidence-authority.report.failed', + 'phase1.stage.evidence-authority.operator-state.failed', + 'phase1.stage.evidence-authority.isolation.failed', + 'phase1.stage.evidence-authority.assertions.failed', + 'phase1.stage.evidence-authority.build.failed', + 'phase1.stage.evidence-authority.serialize.failed', + 'phase1.stage.evidence-authority.scan.failed', + 'phase1.stage.evidence-authority.retain.failed', + ]; + for (const stage of stages) { + expect(publicPhase1FailureDiagnostic(new Error(stage))).toBe(stage); + let stagedFailure: unknown; + try { + await runStage(stage, async () => { + throw new Error('private protected-run detail'); + }); + } catch (error) { + stagedFailure = error; + } + await expect( + runStage('phase1.stage.schema-v2-production.failed', async () => { + throw stagedFailure; + }), + ).rejects.toMatchObject({ message: stage }); + } + }); + + test('assigns bounded diagnostics to checkout and evidence-finalization boundaries', () => { + const source = readFileSync( + resolve(process.cwd(), 'scripts', 'phase1-schema-v2-producer.mjs'), + 'utf8', + ); + for (const stage of [ + 'phase1.stage.checkouts.chat.failed', + 'phase1.stage.checkouts.sdk.failed', + 'phase1.stage.checkouts.cave.failed', + 'phase1.stage.checkouts.coven.failed', + 'phase1.stage.checkouts.integrity.failed', + 'phase1.stage.checkouts.validator.failed', + 'phase1.stage.checkouts.producer.failed', + 'phase1.stage.evidence-authority.report.failed', + 'phase1.stage.evidence-authority.operator-state.failed', + 'phase1.stage.evidence-authority.isolation.failed', + 'phase1.stage.evidence-authority.assertions.failed', + 'phase1.stage.evidence-authority.build.failed', + 'phase1.stage.evidence-authority.serialize.failed', + 'phase1.stage.evidence-authority.scan.failed', + 'phase1.stage.evidence-authority.retain.failed', + ]) { + expect(source).toContain(stage); + } + }); + + test('places final schema-v2 record creation inside the bounded retain stage', () => { + const source = readFileSync( + resolve(process.cwd(), 'scripts', 'phase1-schema-v2-producer.mjs'), + 'utf8', + ); + const retainStage = source.indexOf( + "await runSchemaV2StageAsync('phase1.stage.evidence-authority.retain.failed'", + ); + const recordWrite = source.indexOf('writeFileSync(reportPath, canonical, { mode: 0o600 });'); + const returnEvidence = source.indexOf('return evidence;', retainStage); + + expect(retainStage).toBeGreaterThan(-1); + expect(recordWrite).toBeGreaterThan(retainStage); + expect(recordWrite).toBeLessThan(returnEvidence); + }); + test('authenticates the executing harness before schema-v2 dispatch', () => { const source = readFileSync( resolve(process.cwd(), 'scripts', 'phase1-conformance.mjs'), @@ -4512,6 +4601,37 @@ describe('Phase 1 real-authority conformance harness', () => { ); }); + test('preserves finalization diagnostics when owned-root cleanup also fails', async () => { + // @ts-expect-error The executable script intentionally has no declaration file. + const producer = await import('../scripts/phase1-schema-v2-producer.mjs'); + const diagnostic = 'phase1.stage.evidence-authority.serialize.failed'; + const cleanupFailure = new Error('private cleanup path'); + const actionFailure = new Error(diagnostic); + let failure: unknown; + try { + await producer.runSchemaV2StageAsync('phase1.stage.evidence-authority.failed', () => + producer.withOwnedArtifactRoot( + { + cleanup: async () => { + throw cleanupFailure; + }, + }, + async () => { + throw actionFailure; + }, + ), + ); + } catch (error) { + failure = error; + } + expect(publicPhase1FailureDiagnostic(failure)).toBe(diagnostic); + expect((failure as Error).cause).toBeInstanceOf(AggregateError); + expect(((failure as Error).cause as AggregateError).errors).toEqual([ + actionFailure, + cleanupFailure, + ]); + }); + test('does not swallow undefined schema-v2 action or owned-root cleanup failures', async () => { // @ts-expect-error The executable script intentionally has no declaration file. const producer = (await import('../scripts/phase1-schema-v2-producer.mjs')) as Record<