Skip to content

Commit 209dac9

Browse files
committed
fix(p037): carve out the Rocq consolidation from the a2d treatment-path gate
CI run 36400084949 (job "tests (py3.13)", 108855609862) is red on this head: FAIL[only-treatment-paths-tests-record-and-adjudicated-docs-move] naming the 17 files under formal/p037-rocq/ plus docs/notes/p037-rocq-consolidation.md. Not a formal/semantic problem -- the same job's "formal kernel" leg is green, and this test runs no theorem prover; it asks git which paths moved between T_D and HEAD and checks them against a closed allowlist. Neither the consolidated Rocq package nor its research note existed before this branch cherry-picked them (e4c73f4/06e3d78 from claude/p037-rocq-consolidation), so nothing caught the gap locally -- the same false-green mechanism this file's own comments already document for b234599 and ca84cb1 (a dirty working tree hides a path from `git diff T_D HEAD` that a clean CI checkout sees). Adds two narrowly-scoped, explicitly named entries -- not a `formal/` or `docs/` prefix -- mirroring the existing formal/p037-kernel/ precedent: ROCQ_CONSOLIDATION_PREFIXES = ("formal/p037-rocq/",) and ROCQ_CONSOLIDATION_NOTE_PATH, spliced into the same allowed_prefixes/ governance tuples the check already used. docs/notes/p037-formal-kernel.md needed no new entry: it is already FORMAL_NOTE_PATH and was never in the FAIL list. Factors the check's own logic into classify_outside_paths() so hostile controls can probe it on synthetic input: the carve-out admits exactly its own two paths; frontend/roslyn/OwnSharp.Extractor/Program.cs, rust/crates/own-bridge/src/lower.rs, ownlang/ outside its one named door file, and an arbitrary unrelated doc all still fail the same check. formal/p037-kernel/ is deliberately NOT re-asserted as forbidden -- it is already an allowed PHASE_B_PREFIXES entry, predating and untouched by this change; asserting it forbidden would assert a regression against Phase B's own already-accepted policy, not a property of this fix. A fourth hostile check instead pins that it stays exactly as allowed as it already was. Verified: tests/test_p037_a2d_epoch.py green (including the 3 new hostile checks); ruff check . clean; mypy clean; zero diff under rust/, frontend/, ownlang/, formal/p037-kernel/ against 06e3d78. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AN6xHbpovxrmZ4AMjS7WQA
1 parent 06e3d78 commit 209dac9

1 file changed

Lines changed: 76 additions & 7 deletions

File tree

‎tests/test_p037_a2d_epoch.py‎

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,30 @@
164164
# commit reasoned about.
165165
PHASE_B_PREFIXES = ("formal/p037-kernel/", "docs/evidence/p037-b-")
166166

167+
# Rocq consolidation integration (e4c73f4/06e3d78, cherry-picked onto this
168+
# branch from claude/p037-rocq-consolidation): the same false-green mechanism
169+
# b234599 and ca84cb1 already hit above -- this allowlist keys on which paths
170+
# moved between T_D and HEAD, and neither the consolidated Rocq package nor
171+
# its research note existed before this branch cherry-picked them, so nothing
172+
# caught the gap until CI ran on a clean checkout (run 36400084949, job
173+
# "tests (py3.13)", FAIL[only-treatment-paths-tests-record-and-adjudicated-
174+
# docs-move] naming exactly the 17 files under formal/p037-rocq/ plus
175+
# docs/notes/p037-rocq-consolidation.md). `formal/p037-rocq/` gets a full
176+
# prefix exception for the same reason `formal/p037-kernel/` already has one:
177+
# it is a self-contained, non-production verification tree (its own README:
178+
# a disposable-mutation-tested, zero-MathComp plain-Rocq proof package that
179+
# "must share no source with the extractor, never writes OwnIR") holding no
180+
# ownlang/rust/own-ir/spec/frontend byte -- confirmed by this same test's own
181+
# zero-drift check at the consolidation's own commit, not re-derived here.
182+
# `docs/notes/p037-rocq-consolidation.md` is a single named research note,
183+
# not a prefix, matching how FORMAL_NOTE_PATH is one named file rather than
184+
# all of `docs/notes/`: only this one path is exempted, every other doc stays
185+
# governed exactly as before. `docs/notes/p037-formal-kernel.md`'s own append
186+
# (the consolidation's "pointer" paragraph) needed no new entry -- it is
187+
# already FORMAL_NOTE_PATH and was never in the FAIL list above.
188+
ROCQ_CONSOLIDATION_NOTE_PATH = "docs/notes/p037-rocq-consolidation.md"
189+
ROCQ_CONSOLIDATION_PREFIXES = ("formal/p037-rocq/",)
190+
167191
# 10.6.14b: order step 6 (D after) lands its evidence as exactly these six
168192
# files under docs/evidence/, and nothing about them is inferred or
169193
# regenerated -- each is pinned to the exact sha256 the accepted external
@@ -189,6 +213,24 @@
189213
"18912d32707f66b704c78eabdd02e26cdbef9e046a3240ab48c4af9b42e13e7b",
190214
}
191215

216+
def classify_outside_paths(changed: list[str], t_paths: list[str],
217+
r_d_files: set[str] = frozenset(),
218+
d_after_ok: set[str] = frozenset()) -> list[str]:
219+
"""The exact logic `only-treatment-paths-tests-record-and-adjudicated-
220+
docs-move` checks: paths outside every allowlist this test recognises.
221+
Factored out so the hostile controls below can probe it with synthetic
222+
`changed` lists instead of needing a real git commit per probe."""
223+
allowed_prefixes = (*tuple(t_paths), "tests/", *PHASE_B_PREFIXES,
224+
*ROCQ_CONSOLIDATION_PREFIXES)
225+
governance = (EPOCH_RECORD_PATH, FORMAL_NOTE_PATH, *PHASE_B_GOVERNANCE_FILES,
226+
ROCQ_CONSOLIDATION_NOTE_PATH)
227+
return [f for f in changed if f not in governance
228+
and not f.startswith(allowed_prefixes)
229+
and f not in DOCS_GENERATED_ADJUDICATED
230+
and f not in r_d_files
231+
and f not in d_after_ok]
232+
233+
192234
_failures: list[str] = []
193235

194236

@@ -422,8 +464,6 @@ def run() -> int:
422464
check("gate-holds-this-head-within-the-allowlist-of-T-D", rc == 0, line)
423465

424466
changed = [f for f in git("diff", "--name-only", t_d, "HEAD")[1].splitlines() if f]
425-
allowed_prefixes = (*tuple(t_paths), "tests/", *PHASE_B_PREFIXES)
426-
governance = (EPOCH_RECORD_PATH, FORMAL_NOTE_PATH, *PHASE_B_GOVERNANCE_FILES)
427467
# R_D (order step 4) sits between T_D and the D treatment on this
428468
# branch and is a separately governed, already-accepted
429469
# evidence-only commit; "only the treatment paths and tests move"
@@ -455,14 +495,43 @@ def run() -> int:
455495
not d_after_mismatched, f"{d_after_mismatched}")
456496
d_after_ok = d_after_changed - set(d_after_mismatched)
457497

458-
outside = [f for f in changed if f not in governance
459-
and not f.startswith(allowed_prefixes)
460-
and f not in DOCS_GENERATED_ADJUDICATED
461-
and f not in r_d_files
462-
and f not in d_after_ok]
498+
outside = classify_outside_paths(changed, t_paths, r_d_files, d_after_ok)
463499
check("only-treatment-paths-tests-record-and-adjudicated-docs-move",
464500
not outside, f"{outside}")
465501

502+
# Hostile controls for the Rocq consolidation carve-out: prove it
503+
# admits exactly its own two paths and nothing wider, on synthetic
504+
# `changed` lists rather than a real commit (classify_outside_paths
505+
# is the exact function the check above calls, so this probes the
506+
# same logic, not a re-implementation of it).
507+
admits_probe = classify_outside_paths(
508+
["formal/p037-rocq/theories/P037.v", "formal/p037-rocq/check.sh",
509+
ROCQ_CONSOLIDATION_NOTE_PATH],
510+
t_paths, r_d_files, d_after_ok)
511+
check("rocq-carveout-admits-exactly-its-own-two-paths",
512+
not admits_probe, f"{admits_probe}")
513+
still_forbidden = [
514+
"frontend/roslyn/OwnSharp.Extractor/Program.cs", # instrument, frozen in a2d
515+
"rust/crates/own-bridge/src/lower.rs", # Phase-B-measured, not epoch-allowed
516+
"ownlang/analysis.py", # ownlang production; only ownlang/ownir.py is a named door
517+
"docs/notes/some-unrelated-research-note.md", # arbitrary doc, not the carve-out
518+
]
519+
forbidden_probe = classify_outside_paths(
520+
still_forbidden, t_paths, r_d_files, d_after_ok)
521+
check("rocq-carveout-does-not-broaden-unrelated-forbidden-paths",
522+
sorted(forbidden_probe) == sorted(still_forbidden), f"{forbidden_probe}")
523+
# formal/p037-kernel/ is deliberately NOT probed as forbidden here:
524+
# it is already an allowed PHASE_B_PREFIXES entry (Phase B's own
525+
# verification-tree exception, landed before this carve-out and
526+
# untouched by it) -- asserting it forbidden would assert a
527+
# regression against Phase B's own already-accepted policy, not a
528+
# property of this fix. What this carve-out owes is that entry
529+
# staying exactly as allowed as it already was:
530+
unaffected_probe = classify_outside_paths(
531+
["formal/p037-kernel/src/lib.rs"], t_paths, r_d_files, d_after_ok)
532+
check("phase-b-formal-kernel-prefix-unaffected-by-rocq-carveout",
533+
not unaffected_probe, f"{unaffected_probe}")
534+
466535
d_after_evidence = later.get("D_after_evidence")
467536
if d_after_evidence is not None:
468537
check("D-after-evidence-named-correctly",

0 commit comments

Comments
 (0)