wip(rm-02): round-4 remediation held at RM-60 boundary

This commit is contained in:
2026-08-01 14:39:36 -05:00
parent fbb6191298
commit 9b7005d59b
23 changed files with 851 additions and 1442 deletions
+191 -156
View File
@@ -33,21 +33,18 @@
"checkout-preflight/criterion-misbinding",
"checkout-preflight/missing-meaning-provenance",
"checkout-preflight/prose-claim-misbinding",
"checkout-preflight/history-seam-head",
"checkout-preflight/history-seam-parent",
"checkout-preflight/history-seam-introduction",
"checkout-preflight/provider-cross-commit-duplicate",
"checkout-preflight/misspelled-outcome-field",
"checkout-preflight/wrong-outcome-field-type",
"checkout-preflight/empty-outcome-pattern",
"checkout-preflight/delayed-registry-introduction",
"checkout-preflight/empty-registry-populations",
"checkout-preflight/all-gates-evidence-subject-bound",
"checkout-preflight/all-gates-type-strict",
"ci-queue-wait/no-status-required",
"ci-queue-wait/unknown-option",
"hook-pre-commit/lint-staged-failure",
"hook-pre-push/typecheck-failure"
"hook-pre-push/typecheck-failure",
"checkout-preflight/history-provenance-exclusion",
"checkout-preflight/inventory-source-and-manifest-shrink"
]
},
{
@@ -113,18 +110,26 @@
},
{
"id": "RM02-CURRENT-TREE-BOUNDARY",
"originalText": "assert that every merged commit passed every required gate, evaluated AGAINST THAT COMMIT'S OWN TREE \u2014 not against current main.",
"currentText": "PR CI performs unprivileged, fail-closed current-tree verification only; isolated per-commit replay is deferred to RM-60's protected post-merge/main authority as detection with quarantine/revert, not pre-merge prevention.",
"originalText": "assert that every merged commit passed every required gate, evaluated AGAINST THAT COMMIT'S OWN TREE not against current main.",
"currentText": "PR CI performs unprivileged, fail-closed current-tree verification only and makes no history-provenance assertion; RM-60 owns that external protected property.",
"claimType": "security",
"source": "docs/PRD.md#rm02-req-10-meaning-change-provenance",
"meaningChanges": [
{
"originalText": "assert that every merged commit passed every required gate, evaluated AGAINST THAT COMMIT'S OWN TREE \u2014 not against current main.",
"originalText": "assert that every merged commit passed every required gate, evaluated AGAINST THAT COMMIT'S OWN TREE not against current main.",
"restatement": "PR CI performs unprivileged, fail-closed current-tree verification only; isolated per-commit replay is deferred to a protected post-merge/main authority as detection with quarantine/revert, not pre-merge prevention.",
"reason": "PR-controlled code would otherwise receive and could directly use the namespace capability intended to contain it; the pre-execution trust boundary is absent at the repository layer.",
"finding": "D-25",
"task": "RM-60/RM-59",
"date": "2026-08-01"
},
{
"originalText": "PR CI performs unprivileged, fail-closed current-tree verification only; isolated per-commit replay is deferred to RM-60's protected post-merge/main authority as detection with quarantine/revert, not pre-merge prevention.",
"restatement": "PR CI performs unprivileged, fail-closed current-tree verification only and makes no history-provenance assertion; RM-60 owns that external protected property.",
"reason": "D-48 proved PR lifecycle code can rewrite every local git anchor before gate execution, so the repository history claim is removed rather than annotated as unverifiable.",
"finding": "D-48",
"task": "RM-60",
"date": "2026-08-01"
}
],
"caseRefs": ["checkout-preflight/privileged-pr-gate"]
@@ -237,30 +242,31 @@
"caseRefs": ["ci-queue-wait/terminal-success", "ci-queue-wait/unknown-option"]
},
{
"id": "RM02-HISTORY-BOUNDARY",
"id": "RM02-HISTORY-PROVENANCE-EXCLUDED",
"originalText": "The audited branch range begins at the provider target merge-base, sound against a branch author who cannot rewrite main but not against main compromise; Builds 1-2 own the residual.",
"currentText": "The audited branch range begins at the provider target merge-base, sound against a branch author who cannot rewrite main but not against main compromise; Builds 1-2 own the residual.",
"currentText": "This repository verifier is structurally incapable of asserting history provenance; RM-60 owns the provider-controlled protected pre-execution boundary required to establish it.",
"claimType": "integrity",
"source": "docs/remediation/TASKS.md#d-17",
"meaningChanges": [],
"caseRefs": [
"checkout-preflight/history-seam-head",
"checkout-preflight/history-seam-parent",
"checkout-preflight/history-seam-introduction",
"checkout-preflight/delayed-registry-introduction"
]
"source": "docs/remediation/MISSION.md#first-class-principle-the-anchor-must-live-outside-the-audited-partys-authority",
"meaningChanges": [
{
"originalText": "The audited branch range begins at the provider target merge-base, sound against a branch author who cannot rewrite main but not against main compromise; Builds 1-2 own the residual.",
"restatement": "This repository verifier is structurally incapable of asserting history provenance; RM-60 owns the provider-controlled protected pre-execution boundary required to establish it.",
"reason": "PR-controlled lifecycle code executes before gate verification, so no local ref, config, remote URL, constant, or author-positioned path is trustworthy enough to anchor history provenance.",
"finding": "D-48",
"task": "RM-60",
"date": "2026-08-01"
}
],
"caseRefs": ["checkout-preflight/history-provenance-exclusion"]
},
{
"id": "RM02-EVIDENCE-SUBJECT-BINDING",
"originalText": "For every registered gate, evidence is bound to that gate subject under review; no evidence identity can certify a different or second subject.",
"currentText": "For every registered gate, evidence is bound to that gate subject under review; no evidence identity can certify a different or second subject.",
"originalText": "For every registered gate, consumed evidence carries an independently declared evidence-side subject that must match the gate definition.",
"currentText": "For every registered gate, consumed evidence carries an independently declared evidence-side subject that must match the gate definition.",
"claimType": "integrity",
"source": "docs/remediation/TASKS.md#d-38",
"meaningChanges": [],
"caseRefs": [
"checkout-preflight/provider-cross-commit-duplicate",
"checkout-preflight/all-gates-evidence-subject-bound"
],
"caseRefs": ["checkout-preflight/all-gates-evidence-subject-bound"],
"gateRefs": [
"quality-typecheck",
"quality-lint",
@@ -301,7 +307,10 @@
"claimType": "integrity",
"source": "docs/remediation/TASKS.md#d-46",
"meaningChanges": [],
"caseRefs": ["checkout-preflight/empty-registry-populations"],
"caseRefs": [
"checkout-preflight/empty-registry-populations",
"checkout-preflight/inventory-source-and-manifest-shrink"
],
"gateRefs": [
"quality-typecheck",
"quality-lint",
@@ -391,11 +400,10 @@
}
],
"mergeAssertions": {
"mode": "unprivileged-current-tree-pr-verification",
"mode": "unprivileged-current-tree-verification-with-history-provenance-excluded",
"deferredReplayOwner": "RM-60",
"trustDependencies": ["RM-25", "RM-59", "RM-60", "Builds 1-2 main-integrity bootstrap"],
"providerEvidence": "assert retained current-tree terminal-success records for prior commits; report absent, expired, or current-running evidence without inference",
"postMergeResponse": "protected isolated replay is detection, not prevention; quarantine and revert on failure"
"trustDependencies": ["RM-60"],
"postMergeResponse": "RM-60 defines provider-owned protected execution, quarantine, and revert behavior"
},
"gates": [
{
@@ -427,7 +435,10 @@
"actual": {
"exitCode": 0
},
"reasonPattern": ""
"reasonPattern": "",
"evidence": {
"subject": "quality-typecheck"
}
},
{
"id": "type-error",
@@ -452,10 +463,12 @@
"content": "export const gateTypeError: string = 42;\n"
}
]
},
"evidence": {
"subject": "quality-typecheck"
}
}
],
"evidenceSubject": "quality-typecheck"
]
},
{
"id": "quality-lint",
@@ -486,7 +499,10 @@
"actual": {
"exitCode": 0
},
"reasonPattern": ""
"reasonPattern": "",
"evidence": {
"subject": "quality-lint"
}
},
{
"id": "invalid-syntax",
@@ -511,10 +527,12 @@
"content": "export const = ;\n"
}
]
},
"evidence": {
"subject": "quality-lint"
}
}
],
"evidenceSubject": "quality-lint"
]
},
{
"id": "quality-format",
@@ -545,7 +563,10 @@
"actual": {
"exitCode": 0
},
"reasonPattern": ""
"reasonPattern": "",
"evidence": {
"subject": "quality-format"
}
},
{
"id": "unformatted-json",
@@ -567,10 +588,12 @@
"content": "{\"bad\":true,\"spacing\":[1,2,3]}\n"
}
]
},
"evidence": {
"subject": "quality-format"
}
}
],
"evidenceSubject": "quality-format"
]
},
{
"id": "checkout-preflight",
@@ -603,7 +626,10 @@
"exitCode": 0,
"outputPattern": "checkout preflight passed"
},
"reasonPattern": ""
"reasonPattern": "",
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "stale-build-lock",
@@ -625,6 +651,9 @@
"content": "negative control\n"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -650,6 +679,9 @@
"replace": " gate-verify:\n image: *node_image\n privileged: true\n"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -675,11 +707,7 @@
},
"reasonPattern": "RM02-SET-COVERS: declared exercising case checkout-preflight/criterion-misbinding is not bound",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -692,6 +720,9 @@
"replace": "\"criterionIds\": [\"RM02-CHECK-RIGHT\"],"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -717,11 +748,7 @@
},
"reasonPattern": "RM02-MEANING-PROVENANCE: missing meaning-change provenance",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -729,6 +756,9 @@
"replace": "\"currentText\": \"A restated criterion changed without provenance\","
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -754,11 +784,7 @@
},
"reasonPattern": "GATE-CLAIM:PROSE-IS-A-CLAIM exercising case quality-typecheck/type-error does not exercise criterion RM02-PROSE-CONTROL",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -766,68 +792,11 @@
"replace": "\"caseRef\": \"quality-typecheck/type-error\""
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "history-seam-head",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-HISTORY-BOUNDARY"],
"mustFail": true,
"invocation": ["node", "scripts/gate-history-boundary-control.mjs", "head"],
"required": {
"exitCode": 1,
"outputPattern": "history boundary candidate head rejected"
},
"actual": {
"exitCode": 1,
"outputPattern": "history boundary candidate head rejected"
},
"reasonPattern": "derived activation is provider target merge-base"
},
{
"id": "history-seam-parent",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-HISTORY-BOUNDARY"],
"mustFail": true,
"invocation": ["node", "scripts/gate-history-boundary-control.mjs", "parent"],
"required": {
"exitCode": 1,
"outputPattern": "history boundary candidate parent rejected"
},
"actual": {
"exitCode": 1,
"outputPattern": "history boundary candidate parent rejected"
},
"reasonPattern": "derived activation is provider target merge-base"
},
{
"id": "history-seam-introduction",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-HISTORY-BOUNDARY"],
"mustFail": true,
"invocation": ["node", "scripts/gate-history-boundary-control.mjs", "introduction"],
"required": {
"exitCode": 1,
"outputPattern": "history boundary candidate introduction rejected"
},
"actual": {
"exitCode": 1,
"outputPattern": "history boundary candidate introduction rejected"
},
"reasonPattern": "derived activation is provider target merge-base"
},
{
"id": "provider-cross-commit-duplicate",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-EVIDENCE-SUBJECT-BINDING"],
"mustFail": true,
"invocation": ["node", "scripts/gate-provider-binding-control.mjs"],
"required": {
"exitCode": 1,
"outputPattern": "duplicate pipeline identity across commits"
},
"actual": {
"exitCode": 1,
"outputPattern": "duplicate pipeline identity across commits"
},
"reasonPattern": "duplicate pipeline identity across commits"
},
{
"id": "misspelled-outcome-field",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-TYPE-STRICT-SCHEMA"],
@@ -851,11 +820,7 @@
},
"reasonPattern": "required: unknown field outputPatern",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -863,6 +828,9 @@
"replace": "\"required\": {\n \"exitCode\": 0,\n \"outputPatern\": \"checkout preflight passed\"\n },\n \"actual\":"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -888,11 +856,7 @@
},
"reasonPattern": "required.exitCode: expected an integer",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -900,6 +864,9 @@
"replace": "\"required\": {\n \"exitCode\": \"0\",\n \"outputPattern\": \"checkout preflight passed\"\n },\n \"actual\":"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
@@ -925,11 +892,7 @@
},
"reasonPattern": "required.outputPattern: expected a non-empty pattern",
"fixture": {
"copyPaths": [
"gates/gates.manifest.json",
"scripts/gate-verify.mjs",
"scripts/gate-history.mjs"
],
"copyPaths": ["gates/gates.manifest.json", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "gates/gates.manifest.json",
@@ -937,23 +900,11 @@
"replace": "\"required\": {\n \"exitCode\": 0,\n \"outputPattern\": \" \"\n },\n \"actual\":"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "delayed-registry-introduction",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-HISTORY-BOUNDARY"],
"mustFail": true,
"invocation": ["node", "scripts/gate-delayed-introduction-control.mjs"],
"required": {
"exitCode": 1,
"outputPattern": "delayed registry introduction rejected"
},
"actual": {
"exitCode": 1,
"outputPattern": "delayed registry introduction rejected"
},
"reasonPattern": "own-tree registry cannot be read"
},
{
"id": "empty-registry-populations",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-NONEMPTY-ANCHORED-QUANTIFICATION"],
@@ -967,7 +918,10 @@
"exitCode": 1,
"outputPattern": "empty universally quantified registry populations rejected"
},
"reasonPattern": "empty universally quantified registry populations rejected"
"reasonPattern": "empty universally quantified registry populations rejected",
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "all-gates-evidence-subject-bound",
@@ -982,7 +936,10 @@
"exitCode": 1,
"outputPattern": "evidence-subject population control rejected every registered gate"
},
"reasonPattern": "evidence-subject population control rejected every registered gate"
"reasonPattern": "evidence-subject population control rejected every registered gate",
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "all-gates-type-strict",
@@ -997,10 +954,58 @@
"exitCode": 1,
"outputPattern": "type-strict population control rejected every registered gate"
},
"reasonPattern": "type-strict population control rejected every registered gate"
"reasonPattern": "type-strict population control rejected every registered gate",
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "history-provenance-exclusion",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-HISTORY-PROVENANCE-EXCLUDED"],
"mustFail": true,
"invocation": ["node", "scripts/gate-history-exclusion-control.mjs"],
"required": {
"exitCode": 79,
"outputPattern": "HISTORY_PROVENANCE_FORBIDDEN"
},
"actual": {
"exitCode": 79,
"outputPattern": "HISTORY_PROVENANCE_FORBIDDEN"
},
"reasonPattern": "HISTORY_PROVENANCE_FORBIDDEN",
"fixture": {
"copyPaths": ["scripts/gate-history-exclusion-control.mjs", "scripts/gate-verify.mjs"],
"replaceFiles": [
{
"path": "scripts/gate-verify.mjs",
"find": "const CURRENT_TREE_OBSERVATION_PATTERNS = [\n /^META-NEGATIVE-CONTROL /,",
"replace": "const CURRENT_TREE_OBSERVATION_PATTERNS = [\n /^COMMIT ANCESTRY VERIFIED /,\n /^META-NEGATIVE-CONTROL /,"
}
]
},
"evidence": {
"subject": "checkout-preflight"
}
},
{
"id": "inventory-source-and-manifest-shrink",
"criterionIds": ["RM02-CHECK-RIGHT", "RM02-NONEMPTY-ANCHORED-QUANTIFICATION"],
"mustFail": true,
"invocation": ["node", "scripts/gate-inventory-shrink-control.mjs"],
"required": {
"exitCode": 83,
"outputPattern": "INVENTORY_SHRINK_REJECTED"
},
"actual": {
"exitCode": 83,
"outputPattern": "INVENTORY_SHRINK_REJECTED"
},
"reasonPattern": "INVENTORY_SHRINK_REJECTED",
"evidence": {
"subject": "checkout-preflight"
}
}
],
"evidenceSubject": "checkout-preflight"
]
},
{
"id": "ci-queue-wait",
@@ -1083,6 +1088,9 @@
"defect": {
"owner": "RM-03",
"reason": "The status classifier consumes its Python program from stdin, so piped provider JSON is not read and even terminal success becomes unknown."
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1145,6 +1153,9 @@
"defect": {
"owner": "RM-03",
"reason": "The status classifier does not read the provider payload, so --require-status never reaches no-status."
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1194,6 +1205,9 @@
"content": "#!/bin/sh\ncase \"$*\" in\n *'/branches/'*) printf '{\"commit\":{\"id\":\"gate-sha\"}}\\n200' ;;\n *'/commits/'*) printf '%s' \"$GATE_STATUS_JSON\" ;;\nesac\n"
}
]
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1243,6 +1257,9 @@
"content": "#!/bin/sh\ncase \"$*\" in\n *'/branches/'*) printf '{\"commit\":{\"id\":\"gate-sha\"}}\\n200' ;;\n *'/commits/'*) printf '%s' \"$GATE_STATUS_JSON\" ;;\nesac\n"
}
]
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1292,6 +1309,9 @@
"content": "#!/bin/sh\ncase \"$*\" in\n *'/branches/'*) printf '{\"commit\":{\"id\":\"gate-sha\"}}\\n200' ;;\n *'/commits/'*) printf '%s' \"$GATE_STATUS_JSON\" ;;\nesac\n"
}
]
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1351,6 +1371,9 @@
"content": "#!/bin/sh\ncase \"$*\" in\n *'/branches/'*) printf '{\"commit\":{\"id\":\"gate-sha\"}}\\n200' ;;\n *'/commits/'*) printf '%s' \"$GATE_STATUS_JSON\" ;;\nesac\n"
}
]
},
"evidence": {
"subject": "ci-queue-wait"
}
},
{
@@ -1374,10 +1397,12 @@
"fixture": {
"copyPaths": ["packages/mosaic/framework/tools/git"],
"writeFiles": []
},
"evidence": {
"subject": "ci-queue-wait"
}
}
],
"evidenceSubject": "ci-queue-wait"
]
},
{
"id": "hook-pre-commit",
@@ -1423,6 +1448,9 @@
"content": "#!/bin/sh\necho FAKE_NPX_EXIT=$FAKE_EXIT >&2\nexit \"$FAKE_EXIT\"\n"
}
]
},
"evidence": {
"subject": "hook-pre-commit"
}
},
{
@@ -1451,10 +1479,12 @@
"content": "#!/bin/sh\necho FAKE_NPX_EXIT=$FAKE_EXIT >&2\nexit \"$FAKE_EXIT\"\n"
}
]
},
"evidence": {
"subject": "hook-pre-commit"
}
}
],
"evidenceSubject": "hook-pre-commit"
]
},
{
"id": "hook-pre-push",
@@ -1500,6 +1530,9 @@
"content": "#!/bin/sh\nif [ \"$1\" = \"$FAIL_PNPM_COMMAND\" ]; then echo FAKE_PNPM_FAILURE=$1 >&2; exit 19; fi\nexit 0\n"
}
]
},
"evidence": {
"subject": "hook-pre-push"
}
},
{
@@ -1528,10 +1561,12 @@
"content": "#!/bin/sh\nif [ \"$1\" = \"$FAIL_PNPM_COMMAND\" ]; then echo FAKE_PNPM_FAILURE=$1 >&2; exit 19; fi\nexit 0\n"
}
]
},
"evidence": {
"subject": "hook-pre-push"
}
}
],
"evidenceSubject": "hook-pre-push"
]
}
]
}
+16
View File
@@ -0,0 +1,16 @@
{
"schemaVersion": 1,
"purpose": "Independent required-gate population baseline; manifest and verifier inventory must both match.",
"gates": [
{ "id": "quality-typecheck", "source": "package.json" },
{ "id": "quality-lint", "source": "package.json" },
{ "id": "quality-format", "source": "package.json" },
{ "id": "checkout-preflight", "source": "scripts/preflight.mjs" },
{
"id": "ci-queue-wait",
"source": "packages/mosaic/framework/tools/git/ci-queue-wait.sh"
},
{ "id": "hook-pre-commit", "source": ".husky/pre-commit" },
{ "id": "hook-pre-push", "source": ".husky/pre-push" }
]
}