From 78d9addd14a0c446137622e624180e466ecc69e3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 13:28:36 +0000 Subject: [PATCH 1/3] Acknowledge completed PR #40 promotion in the repository front door Removes the stale pre-merge wording that said merge remained pending Gate G and owner authorization, and records the completed promotion as scoped evidence. Independent Gate G validation passed for exact candidate a2b5053771ce510fb35ce09f3e99f545c21ac20e (tree b8e31ec4786a2fd1aca976a6ff047deeee63ef15). Pull request 40 merged that exact tree into main as merge commit c4a325c551ce8904dfcc5b9fe81b05109726a334, first parent 9ad37fc80d8f34318c6212ed702de5eab3551cf5, second parent a2b5053771ce510fb35ce09f3e99f545c21ac20e, approved by inventor1975 and merged at 2026-09-06T08:14:03Z. Gate F evidence remains scoped to c0108a7a80585d6f5732407d4904ba815073ecd2 and its recorded tree, and is not rewritten as validation of any later commit. Each numeric result stays bound to the exact commit and tree that produced it. Ceilings are unchanged: the production semantic gate remains BLOCKED, NVIDIA remains NOT_QUALIFIED, Canada redistribution remains UNRESOLVED, Ontology 007R1 remains unexecuted and execution-unauthorized, the negative-stability live outcome remains DEFERRED, and institutional-IR closure, production compilation and runtime authorization remain UNESTABLISHED. All twelve exclusions are retained verbatim in both front doors and in the capability matrix. The inherited SOURCE_MANIFEST.csv is unchanged and remains entry-scoped. The capability matrix gains a machine-readable gate_g_promotion_evidence object recording the PR number, base, candidate, validated tree, merge commit, parent order, approval identity, merge time, Gate G verdict, test count, declared skip, coverage and demo digest. The code-start gate refuses a forged, mutated or removed promotion record, and the claims-discipline contract fails closed if a required post-merge fact is dropped, a stale pre-merge assertion is reintroduced, an anchor drifts, or a ceiling is weakened. Closes GG001-M01: README numeric claims are now bound by test to the matrix anchors that produced them, without creating an unscoped current-head claim. No semantic runtime, demo-output, packaging, provider, rights or corpus change. The deterministic offline demo digest is unchanged. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_012ZnoGkqEBXouAq1FpLeU62 --- README.md | 17 ++- STATUS.md | 22 +++- docs/capabilities/CAPABILITY_MATRIX.json | 43 +++++++ scripts/verify_code_start_gate.py | 61 ++++++++++ tests/contract/test_claims_discipline.py | 132 +++++++++++++++++++++- tests/contract/test_semantic_promotion.py | 59 ++++++++++ 6 files changed, 326 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 744f24c..f615e75 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Open Institutional Compiler -- **Status:** BOUNDED_REFERENCE_IMPLEMENTATION — scoped independent Gate F repository validation passed; merge pending Gate G and owner authorization +- **Status:** BOUNDED_REFERENCE_IMPLEMENTATION — scoped independent Gate G validation passed for candidate `a2b5053771ce510fb35ce09f3e99f545c21ac20e` and merged to `main` as `c4a325c551ce8904dfcc5b9fe81b05109726a334` - **Bootstrap date:** 2026-07-29 - **Governing design:** TDD-OIC-001 v1.1 @@ -44,8 +44,19 @@ that exact candidate only. It does not establish semantic correctness, model accuracy, institutional validity, legal effect, provider qualification, rights resolution, ontology execution, production compilation, runtime authorization, institutional-IR closure, enterprise readiness, or benchmark superiority. It -also does not establish legal validity or production readiness. Merge remains -pending Gate G and owner authorization. +also does not establish legal validity or production readiness. It is not +validation of any later commit. +Independent Gate G validation passed for candidate +`a2b5053771ce510fb35ce09f3e99f545c21ac20e` (tree +`b8e31ec4786a2fd1aca976a6ff047deeee63ef15`): canonical Linux execution reported +1720 passed, 0 failed, 0 errors, 1 declared skip, 93.5% coverage, and the same +byte-identical offline demo digest. Pull request 40 merged that exact tree into +`main` as merge commit `c4a325c551ce8904dfcc5b9fe81b05109726a334` (first parent +`9ad37fc80d8f34318c6212ed702de5eab3551cf5`, second parent +`a2b5053771ce510fb35ce09f3e99f545c21ac20e`), approved by `inventor1975` and +merged at 2026-09-06T08:14:03Z. That result carries the same twelve exclusions +and the same ceilings, is scoped to that exact candidate and tree, and is not +validation of any later commit. See [`CAPABILITY_MATRIX.json`](docs/capabilities/CAPABILITY_MATRIX.json) for exact provenance and ceilings. NVIDIA is NOT_QUALIFIED; Canada redistribution is UNRESOLVED; Ontology 007R1 is unexecuted and execution-unauthorized. No model accuracy or legal validity is claimed. diff --git a/STATUS.md b/STATUS.md index 7fe1e4a..227172b 100644 --- a/STATUS.md +++ b/STATUS.md @@ -2,12 +2,13 @@ ## Current status -**BOUNDED_REFERENCE_IMPLEMENTATION — SCOPED INDEPENDENT GATE F REPOSITORY VALIDATION PASSED** +**BOUNDED_REFERENCE_IMPLEMENTATION — SCOPED INDEPENDENT GATE G VALIDATION PASSED AND MERGED TO MAIN** OIC-SEMANTIC-PROMOTION-001 admits only the 58-path maximum recorded in `docs/capabilities/CAPABILITY_MATRIX.json`, from main `9ad37fc80d8f34318c6212ed702de5eab3551cf5`. It implements an offline synthetic reference path, not production compilation, runtime authorization, or canonical meaning. + Independent Gate F repository validation passed for exact candidate `c0108a7a80585d6f5732407d4904ba815073ecd2`, tree `1d12b17aad7977c939090909171183be166cfd50`. Canonical Linux execution reported @@ -15,8 +16,23 @@ Independent Gate F repository validation passed for exact candidate byte-identical offline demo runs with SHA-256 `0f9d01bb0dfc488505e027ac7bd8aecf869578e379b5a977cd9d642f2101a39a`. The result establishes reproducibility, boundary integrity, the specified fail-closed -properties, packaging, and named adversarial checks for that candidate only. -Merge remains pending Gate G and owner authorization; no merge is authorized. +properties, packaging, and named adversarial checks for that candidate only. It +is not validation of any later commit. + +Independent Gate G validation passed for exact candidate +`a2b5053771ce510fb35ce09f3e99f545c21ac20e`, tree +`b8e31ec4786a2fd1aca976a6ff047deeee63ef15`. Canonical Linux execution reported +1720 passed, 0 failed, 0 errors, 1 declared skip +(`tests/contract/test_canada_acquisition_preflight.py:574`), 93.5% coverage, and +two byte-identical offline demo runs with SHA-256 +`0f9d01bb0dfc488505e027ac7bd8aecf869578e379b5a977cd9d642f2101a39a`. Pull request +40 merged that exact tree into `main` as merge commit +`c4a325c551ce8904dfcc5b9fe81b05109726a334`, first parent +`9ad37fc80d8f34318c6212ed702de5eab3551cf5`, second parent +`a2b5053771ce510fb35ce09f3e99f545c21ac20e`, approved by `inventor1975` at +2026-09-06T08:12:51Z and merged at 2026-09-06T08:14:03Z. The merged tree is +byte-identical to the validated tree. Each result above is scoped to the exact +commit and tree that produced it and to nothing later. NVIDIA: NOT_QUALIFIED and excluded from the demo. Canada redistribution: UNRESOLVED. Ontology 007R1: unexecuted and execution-unauthorized. Institutional-IR closure: diff --git a/docs/capabilities/CAPABILITY_MATRIX.json b/docs/capabilities/CAPABILITY_MATRIX.json index bd98e45..84830c0 100644 --- a/docs/capabilities/CAPABILITY_MATRIX.json +++ b/docs/capabilities/CAPABILITY_MATRIX.json @@ -305,6 +305,49 @@ "benchmark superiority" ] }, + "gate_g_promotion_evidence": { + "status": "GATE_G_PASS", + "work_order": "OIC-INDEPENDENT-GATE-G-001", + "candidate_commit": "a2b5053771ce510fb35ce09f3e99f545c21ac20e", + "candidate_tree": "b8e31ec4786a2fd1aca976a6ff047deeee63ef15", + "canonical_linux": { + "passed": 1720, + "failed": 0, + "errors": 0, + "skipped": 1, + "declared_skip": "tests/contract/test_canada_acquisition_preflight.py:574", + "coverage_percent": 93.5 + }, + "demo_sha256": "0f9d01bb0dfc488505e027ac7bd8aecf869578e379b5a977cd9d642f2101a39a", + "promotion": { + "pull_request": 40, + "pull_request_url": "https://github.com/veraxis-protocol/Institutional-Compiler/pull/40", + "base_before_merge": "9ad37fc80d8f34318c6212ed702de5eab3551cf5", + "merge_commit": "c4a325c551ce8904dfcc5b9fe81b05109726a334", + "merge_first_parent": "9ad37fc80d8f34318c6212ed702de5eab3551cf5", + "merge_second_parent": "a2b5053771ce510fb35ce09f3e99f545c21ac20e", + "merge_tree": "b8e31ec4786a2fd1aca976a6ff047deeee63ef15", + "merge_method": "merge_commit", + "approved_by": "inventor1975", + "approved_at": "2026-09-06T08:12:51Z", + "merged_at": "2026-09-06T08:14:03Z" + }, + "scope": "Scoped independent Gate G acceptance of this exact candidate: identity and boundary, claims audit, adversarial fail-closed challenges, canonical Linux execution, deterministic offline demo, packaging, and repository integrity. Pull request 40 merged this exact tree into main without modification.", + "exclusions": [ + "semantic correctness", + "model accuracy", + "institutional validity", + "legal effect", + "provider qualification", + "rights resolution", + "ontology execution", + "production compilation", + "runtime authorization", + "institutional-IR closure", + "enterprise readiness", + "benchmark superiority" + ] + }, "capabilities": [ { "name": "grounded_candidate_extraction", diff --git a/scripts/verify_code_start_gate.py b/scripts/verify_code_start_gate.py index 9683547..de64069 100644 --- a/scripts/verify_code_start_gate.py +++ b/scripts/verify_code_start_gate.py @@ -94,6 +94,65 @@ def validate_independent_validation_evidence(evidence: object) -> None: _require(evidence == INDEPENDENT_VALIDATION_EVIDENCE, "independent validation evidence forged") +GATE_G_PROMOTION_EVIDENCE = { + "status": "GATE_G_PASS", + "work_order": "OIC-INDEPENDENT-GATE-G-001", + "candidate_commit": "a2b5053771ce510fb35ce09f3e99f545c21ac20e", + "candidate_tree": "b8e31ec4786a2fd1aca976a6ff047deeee63ef15", + "canonical_linux": { + "passed": 1720, + "failed": 0, + "errors": 0, + "skipped": 1, + "declared_skip": "tests/contract/test_canada_acquisition_preflight.py:574", + "coverage_percent": 93.5, + }, + "demo_sha256": "0f9d01bb0dfc488505e027ac7bd8aecf869578e379b5a977cd9d642f2101a39a", + "promotion": { + "pull_request": 40, + "pull_request_url": "https://github.com/veraxis-protocol/Institutional-Compiler/pull/40", + "base_before_merge": "9ad37fc80d8f34318c6212ed702de5eab3551cf5", + "merge_commit": "c4a325c551ce8904dfcc5b9fe81b05109726a334", + "merge_first_parent": "9ad37fc80d8f34318c6212ed702de5eab3551cf5", + "merge_second_parent": "a2b5053771ce510fb35ce09f3e99f545c21ac20e", + "merge_tree": "b8e31ec4786a2fd1aca976a6ff047deeee63ef15", + "merge_method": "merge_commit", + "approved_by": "inventor1975", + "approved_at": "2026-09-06T08:12:51Z", + "merged_at": "2026-09-06T08:14:03Z", + }, + "scope": ( + "Scoped independent Gate G acceptance of this exact candidate: identity and " + "boundary, claims audit, adversarial fail-closed challenges, canonical Linux " + "execution, deterministic offline demo, packaging, and repository integrity. " + "Pull request 40 merged this exact tree into main without modification." + ), + "exclusions": [ + "semantic correctness", + "model accuracy", + "institutional validity", + "legal effect", + "provider qualification", + "rights resolution", + "ontology execution", + "production compilation", + "runtime authorization", + "institutional-IR closure", + "enterprise readiness", + "benchmark superiority", + ], +} + + +def validate_gate_g_promotion_evidence(evidence: object) -> None: + """Accept only the exact owner-adjudicated Gate G promotion evidence record. + + The merge second parent must be the Gate G candidate and the merge tree must be + the validated tree, so a forged, mutated or removed promotion record fails closed. + """ + _require(evidence == GATE_G_PROMOTION_EVIDENCE, "gate g promotion evidence forged") + + ADMITTED_SRC_OIC_PATHS = frozenset( { "src/oic/__init__.py", @@ -273,6 +332,7 @@ def validate_bounded_record(root: Path) -> None: "source_provenance", "ceilings", "independent_validation_evidence", + "gate_g_promotion_evidence", "capabilities", }, "capability matrix fields expanded", @@ -313,6 +373,7 @@ def validate_bounded_record(root: Path) -> None: _require(record.get("production_semantic_gate") == "BLOCKED", "production gate expanded") _require(record.get("ceilings") == CEILINGS, "evidence ceiling expanded") validate_independent_validation_evidence(record.get("independent_validation_evidence")) + validate_gate_g_promotion_evidence(record.get("gate_g_promotion_evidence")) provenance = record.get("source_provenance") _require( hashlib.sha256( diff --git a/tests/contract/test_claims_discipline.py b/tests/contract/test_claims_discipline.py index 9803022..e7e6528 100644 --- a/tests/contract/test_claims_discipline.py +++ b/tests/contract/test_claims_discipline.py @@ -230,6 +230,57 @@ def test_static_claims_documents_are_unchanged_by_this_work_order(repo_root: Pat assert observed == committed, relpath +#: Pre-merge wording that the completed PR #40 promotion makes false. A front-door +#: document that reintroduces any of these is stale and must fail closed. +STALE_PRE_MERGE_PHRASES = ( + "merge remains pending gate g and owner authorization", + "merge pending gate g and owner authorization", + "no merge is authorized", + "gate g and owner merge authorization remain pending", +) + + +def _assert_promotion_claims(normalized: str, promotion: object) -> None: + """Require the shipped text to carry the exact Gate G promotion anchors. + + Every anchor is read from the live capability matrix rather than hard-coded here, + so changing an anchor in the matrix without changing the shipped document fails + closed, and changing the document without the matrix fails closed too. + """ + assert isinstance(promotion, dict), "missing gate_g_promotion_evidence" + assert promotion.get("status") == "GATE_G_PASS" + assert promotion.get("work_order") == "OIC-INDEPENDENT-GATE-G-001" + detail = promotion.get("promotion") + assert isinstance(detail, dict), "missing promotion detail" + + for key in ("candidate_commit", "candidate_tree"): + value = promotion.get(key) + assert isinstance(value, str) and value in normalized, ( + f"missing Gate G promotion anchor: {key}" + ) + for key in ("merge_commit", "merge_first_parent", "merge_second_parent"): + value = detail.get(key) + assert isinstance(value, str) and value in normalized, ( + f"missing Gate G promotion anchor: {key}" + ) + + pull_request = detail.get("pull_request") + assert isinstance(pull_request, int) + assert f"pull request {pull_request}" in normalized, "missing pull request reference" + approver = detail.get("approved_by") + assert isinstance(approver, str) and approver.lower() in normalized + merged_at = detail.get("merged_at") + assert isinstance(merged_at, str) and merged_at.lower() in normalized + + assert "independent gate g validation passed" in normalized, ( + "missing independent Gate G validation statement" + ) + assert promotion.get("exclusions") == list(GATE_F_EXCLUSIONS) + + for phrase in STALE_PRE_MERGE_PHRASES: + assert phrase not in normalized, f"stale pre-merge assertion reintroduced: {phrase}" + + def _assert_status_claims(text: str, capability_matrix: dict[str, object]) -> None: """Require the active bounded state and ceilings; reject affirmative escalation.""" normalized = " ".join(text.lower().replace("*", "").split()) @@ -237,6 +288,7 @@ def _assert_status_claims(text: str, capability_matrix: dict[str, object]) -> No gate = capability_matrix["production_semantic_gate"] ceilings = capability_matrix["ceilings"] evidence = capability_matrix.get("independent_validation_evidence") + promotion = capability_matrix.get("gate_g_promotion_evidence") assert isinstance(state, str) and state.lower() in normalized assert isinstance(gate, str) and f"production semantic gate: {gate.lower()}" in normalized assert isinstance(ceilings, dict) @@ -265,13 +317,14 @@ def _assert_status_claims(text: str, capability_matrix: dict[str, object]) -> No "missing STATUS.md independent Gate F validation statement" ) assert "1714 passed, 0 failed, 0 errors, 1 declared skip, 93.5% coverage" in normalized - assert "merge remains pending gate g and owner authorization" in normalized assert "does not establish semantic correctness" in normalized assert evidence.get("exclusions") == list(GATE_F_EXCLUSIONS) for exclusion in GATE_F_EXCLUSIONS: assert exclusion.lower() in normalized + _assert_promotion_claims(normalized, promotion) else: assert evidence is None + assert promotion is None assert "pending independent validation" in normalized for phrase in FORBIDDEN_ABSOLUTELY: assert phrase not in normalized, f"forbidden STATUS.md claim: {phrase}" @@ -331,11 +384,36 @@ def test_status_reports_active_bounded_state_and_ceilings(repo_root: Path) -> No with pytest.raises(AssertionError, match="independently validated"): _assert_status_claims(broad_claim, matrix) + stale_claim = status + "\nMerge remains pending Gate G and owner authorization.\n" + with pytest.raises(AssertionError, match="stale pre-merge assertion reintroduced"): + _assert_status_claims(stale_claim, matrix) + + drifted_matrix = json.loads(json.dumps(matrix)) + drifted_matrix["gate_g_promotion_evidence"]["promotion"]["merge_commit"] = "0" * 40 + with pytest.raises(AssertionError, match="missing Gate G promotion anchor: merge_commit"): + _assert_status_claims(status, drifted_matrix) + + removed_promotion = json.loads(json.dumps(matrix)) + del removed_promotion["gate_g_promotion_evidence"] + with pytest.raises(AssertionError, match="missing gate_g_promotion_evidence"): + _assert_status_claims(status, removed_promotion) + + gate_g_marker = "independent gate g validation passed" + dropped_gate_g = re.sub( + re.escape(gate_g_marker), "gate g marker removed", status, flags=re.IGNORECASE + ) + assert dropped_gate_g != status + with pytest.raises( + AssertionError, match=re.escape("missing independent Gate G validation statement") + ): + _assert_status_claims(dropped_gate_g, matrix) + pending_matrix = json.loads(json.dumps(matrix)) pending_matrix["ceilings"]["independent_validation"] = False del pending_matrix["independent_validation_evidence"] + del pending_matrix["gate_g_promotion_evidence"] pending_status = status.replace( - "SCOPED INDEPENDENT GATE F REPOSITORY VALIDATION PASSED", + "SCOPED INDEPENDENT GATE G VALIDATION PASSED AND MERGED TO MAIN", "PENDING INDEPENDENT VALIDATION", ) _assert_status_claims(pending_status, pending_matrix) @@ -354,6 +432,56 @@ def test_gate_f_exclusions_are_exact_and_present_in_both_front_doors(repo_root: ) +def test_readme_numeric_claims_are_bound_to_their_source_evidence(repo_root: Path) -> None: + """Close GG001-M01: every README validation claim must name its source candidate. + + The Gate F and Gate G numeric results are only meaningful next to the exact commit + and tree that produced them. This control reads the anchors from the live matrix, + so stripping the citation from README.md while leaving the numbers in place fails + closed, and so does changing an anchor in the matrix alone. + """ + matrix = json.loads( + (repo_root / "docs/capabilities/CAPABILITY_MATRIX.json").read_text(encoding="utf-8") + ) + readme = (repo_root / "README.md").read_text(encoding="utf-8") + normalized = " ".join(readme.lower().replace("*", "").split()) + + gate_f = matrix["independent_validation_evidence"] + gate_g = matrix["gate_g_promotion_evidence"] + + required_anchors = { + "gate_f_candidate_commit": gate_f["candidate_commit"], + "gate_f_candidate_tree": gate_f["candidate_tree"], + "gate_g_candidate_commit": gate_g["candidate_commit"], + "gate_g_candidate_tree": gate_g["candidate_tree"], + "merge_commit": gate_g["promotion"]["merge_commit"], + "merge_first_parent": gate_g["promotion"]["merge_first_parent"], + "merge_second_parent": gate_g["promotion"]["merge_second_parent"], + } + for label, anchor in required_anchors.items(): + assert isinstance(anchor, str) and anchor.lower() in normalized, ( + f"README.md numeric claim is unscoped: missing {label}" + ) + + # A numeric result may not appear without the commit that produced it. + gate_f_passed = gate_f["canonical_linux"]["passed"] + gate_g_passed = gate_g["canonical_linux"]["passed"] + for passed, anchor_label in ( + (gate_f_passed, "gate_f_candidate_commit"), + (gate_g_passed, "gate_g_candidate_commit"), + ): + assert f"{passed} passed" in normalized, f"missing README result for {anchor_label}" + + stripped = readme.replace(gate_f["candidate_commit"], "REDACTED") + assert stripped != readme + stripped_normalized = " ".join(stripped.lower().replace("*", "").split()) + assert gate_f["candidate_commit"].lower() not in stripped_normalized + + # README must also refuse an unscoped current-head validation claim. + for phrase in ("this repository is validated", "main is independently validated"): + assert phrase not in normalized, f"unscoped README validation claim: {phrase}" + + @pytest.mark.parametrize("mutation", ("delete", "substitute", "reorder", "add")) def test_matrix_gate_f_exclusion_mutations_fail_closed(repo_root: Path, mutation: str) -> None: import importlib.util diff --git a/tests/contract/test_semantic_promotion.py b/tests/contract/test_semantic_promotion.py index 2058082..e2c1794 100644 --- a/tests/contract/test_semantic_promotion.py +++ b/tests/contract/test_semantic_promotion.py @@ -196,3 +196,62 @@ def test_forged_independent_validation_evidence_is_refused( path.write_text(json.dumps(matrix), encoding="utf-8") with pytest.raises(module.GateEvidenceError, match="evidence forged"): module.validate_bounded_record(gate_tree) + + +def test_gate_g_promotion_evidence_removal_is_refused(repo_root: Path, gate_tree: Path) -> None: + module = gate(repo_root) + path = gate_tree / "docs/capabilities/CAPABILITY_MATRIX.json" + matrix = json.loads(path.read_bytes()) + del matrix["gate_g_promotion_evidence"] + path.write_text(json.dumps(matrix), encoding="utf-8") + with pytest.raises(module.GateEvidenceError): + module.validate_bounded_record(gate_tree) + + +@pytest.mark.parametrize( + ("field", "value"), + [ + ("candidate_commit", "0" * 40), + ("candidate_tree", "0" * 40), + ("status", "GATE_G_FAIL"), + ("work_order", "OIC-INDEPENDENT-GATE-G-999"), + ], +) +def test_forged_gate_g_promotion_evidence_is_refused( + repo_root: Path, gate_tree: Path, field: str, value: str +) -> None: + module = gate(repo_root) + path = gate_tree / "docs/capabilities/CAPABILITY_MATRIX.json" + matrix = json.loads(path.read_bytes()) + matrix["gate_g_promotion_evidence"][field] = value + path.write_text(json.dumps(matrix), encoding="utf-8") + with pytest.raises(module.GateEvidenceError, match="gate g promotion evidence forged"): + module.validate_bounded_record(gate_tree) + + +@pytest.mark.parametrize( + "field", + ["merge_commit", "merge_first_parent", "merge_second_parent", "merge_tree", "approved_by"], +) +def test_forged_gate_g_merge_topology_is_refused( + repo_root: Path, gate_tree: Path, field: str +) -> None: + """A forged merge parent, tree, commit or approver must fail closed.""" + module = gate(repo_root) + path = gate_tree / "docs/capabilities/CAPABILITY_MATRIX.json" + matrix = json.loads(path.read_bytes()) + matrix["gate_g_promotion_evidence"]["promotion"][field] = "forged" + path.write_text(json.dumps(matrix), encoding="utf-8") + with pytest.raises(module.GateEvidenceError, match="gate g promotion evidence forged"): + module.validate_bounded_record(gate_tree) + + +def test_gate_g_promotion_evidence_matches_the_gate_g_candidate(repo_root: Path) -> None: + """The recorded merge must carry the Gate G candidate as its second parent.""" + module = gate(repo_root) + evidence = module.GATE_G_PROMOTION_EVIDENCE + promotion = evidence["promotion"] + assert promotion["merge_second_parent"] == evidence["candidate_commit"] + assert promotion["merge_tree"] == evidence["candidate_tree"] + assert promotion["merge_first_parent"] == promotion["base_before_merge"] + assert evidence["exclusions"] == module.INDEPENDENT_VALIDATION_EVIDENCE["exclusions"] From 8d5f7d9f63c5c4928fa8afeaedf9e0bce0a1cb91 Mon Sep 17 00:00:00 2001 From: Claude Executor Date: Sun, 6 Sep 2026 19:21:00 +0000 Subject: [PATCH 2/3] Scope README independent-validation claims to their exact candidates Close the state-ack findings where README.md could carry an unscoped "current repository head is independently validated" claim without the claims-discipline contract failing. Normalize README text before matching so presentation syntax (case, emphasis markers, punctuation, collapsed whitespace, line breaks) cannot smuggle an unscoped validation claim past a literal phrase check, and require every Gate F and Gate G independent-validation statement to name its exact candidate commit and tree. Genuine source-anchor checks are unchanged: the existing numeric-claim anchor binding still fails closed when a candidate SHA is removed. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01TjmAD2zReEvYvskjRvjmgm --- tests/contract/test_claims_discipline.py | 70 +++++++++++++++++++++--- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/tests/contract/test_claims_discipline.py b/tests/contract/test_claims_discipline.py index e7e6528..2c30a9c 100644 --- a/tests/contract/test_claims_discipline.py +++ b/tests/contract/test_claims_discipline.py @@ -432,6 +432,46 @@ def test_gate_f_exclusions_are_exact_and_present_in_both_front_doors(repo_root: ) +def _normalize_readme_claims(text: str) -> str: + """Remove presentation syntax while preserving the words that carry a claim.""" + return " ".join(re.sub(r"[^a-z0-9]+", " ", text.casefold()).split()) + + +def _assert_readme_independent_validation_is_scoped( + text: str, gate_f: dict[str, object], gate_g: dict[str, object] +) -> None: + normalized = _normalize_readme_claims(text) + subject = ( + r"(?:this\s+)?(?:current\s+repository(?:\s+head)?|repository\s+head|" + r"current\s+(?:head|commit|revision|release)|release|main)" + ) + validation = r"(?:independently\s+validated|independent\s+validation)" + bridge = r"(?:\s+[a-z0-9]+){0,5}\s+" + unscoped = re.search( + rf"\b(?:{subject}{bridge}{validation}|{validation}{bridge}{subject})\b", + normalized, + ) + assert unscoped is None, f"unscoped README independent-validation claim: {unscoped.group(0)!r}" + + for label, marker, evidence in ( + ( + "Gate F", + "independent gate f repository validation passed for candidate", + gate_f, + ), + ("Gate G", "independent gate g validation passed for candidate", gate_g), + ): + candidate_commit = evidence["candidate_commit"] + candidate_tree = evidence["candidate_tree"] + assert isinstance(candidate_commit, str) + assert isinstance(candidate_tree, str) + scoped_claim = f"{marker} {candidate_commit} tree {candidate_tree}".lower() + assert scoped_claim in normalized, ( + f"README.md {label} independent-validation statement is not bound " + "to its exact candidate commit and tree" + ) + + def test_readme_numeric_claims_are_bound_to_their_source_evidence(repo_root: Path) -> None: """Close GG001-M01: every README validation claim must name its source candidate. @@ -472,14 +512,30 @@ def test_readme_numeric_claims_are_bound_to_their_source_evidence(repo_root: Pat ): assert f"{passed} passed" in normalized, f"missing README result for {anchor_label}" - stripped = readme.replace(gate_f["candidate_commit"], "REDACTED") - assert stripped != readme - stripped_normalized = " ".join(stripped.lower().replace("*", "").split()) - assert gate_f["candidate_commit"].lower() not in stripped_normalized + _assert_readme_independent_validation_is_scoped(readme, gate_f, gate_g) - # README must also refuse an unscoped current-head validation claim. - for phrase in ("this repository is validated", "main is independently validated"): - assert phrase not in normalized, f"unscoped README validation claim: {phrase}" + unscoped_claims = ( + "This current repository head is independently validated.", + "**THIS CURRENT**\nrepository HEAD -- is independently validated!!!", + "The current head is independently validated.", + "This release has independent validation.", + "Main is independently validated.", + ) + for claim in unscoped_claims: + mutated = f"{readme}\n{claim}\n" + assert _normalize_readme_claims(claim) in _normalize_readme_claims(mutated) + with pytest.raises(AssertionError, match="unscoped README independent-validation claim"): + _assert_readme_independent_validation_is_scoped(mutated, gate_f, gate_g) + + scoped_claims = ( + "Independent Gate F repository validation passed for candidate " + f"{gate_f['candidate_commit']} (tree {gate_f['candidate_tree']}).", + "Independent Gate G validation passed for candidate " + f"{gate_g['candidate_commit']} (tree {gate_g['candidate_tree']}).", + ) + normalized_claims = _normalize_readme_claims(readme) + for claim in scoped_claims: + assert _normalize_readme_claims(claim) in normalized_claims @pytest.mark.parametrize("mutation", ("delete", "substitute", "reorder", "add")) From 4576fea067d33c2c0f8e8fc2d49bb506c52b2f1c Mon Sep 17 00:00:00 2001 From: Claude Executor Date: Mon, 7 Sep 2026 02:44:51 +0000 Subject: [PATCH 3/3] Refuse unscoped "implementation" independent-validation claims in README The README claims control scoped independent-validation assertions to their exact candidate commit and tree, but its subject alternation enumerated repository, head, commit, revision, release and main only. An unscoped claim whose subject is "implementation" passed every acceptance control in the repository, so the front door could have asserted blanket independent validation without failing closed. Add "implementation" to the existing subject alternation and add the corresponding case to the internal unscoped-claims regression tuple. No other subject term is introduced, and no runtime, verifier, matrix, or claim content changes. Closes SAK001C-F01, pending independent continuity re-review. Work order: OIC-POST-MERGE-STATE-ACK-CONTINUITY-REPAIR-LINUX-001 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GHphtvHoRy3j3SqY2PYYBC --- tests/contract/test_claims_discipline.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/contract/test_claims_discipline.py b/tests/contract/test_claims_discipline.py index 2c30a9c..b70ff2b 100644 --- a/tests/contract/test_claims_discipline.py +++ b/tests/contract/test_claims_discipline.py @@ -443,7 +443,7 @@ def _assert_readme_independent_validation_is_scoped( normalized = _normalize_readme_claims(text) subject = ( r"(?:this\s+)?(?:current\s+repository(?:\s+head)?|repository\s+head|" - r"current\s+(?:head|commit|revision|release)|release|main)" + r"current\s+(?:head|commit|revision|release)|release|main|implementation)" ) validation = r"(?:independently\s+validated|independent\s+validation)" bridge = r"(?:\s+[a-z0-9]+){0,5}\s+" @@ -519,6 +519,7 @@ def test_readme_numeric_claims_are_bound_to_their_source_evidence(repo_root: Pat "**THIS CURRENT**\nrepository HEAD -- is independently validated!!!", "The current head is independently validated.", "This release has independent validation.", + "*This Implementation* is independently validated.", "Main is independently validated.", ) for claim in unscoped_claims: