6Fold-landing gate for review-hardened plans (built for plan 151).
10What this is — and, honestly, what it is NOT (2026-07-15, reviews 151/R17+R18).
11This is a **region-scoped exact-substring checker**. For each folded finding it
14 * NEW — the new mechanism's literal appears INSIDE the finding's executing
15 region (a bounded span between two anchor strings — a step, a Gate,
16 an AC row), **not merely somewhere in the document**. This is the
17 capability whose absence let the v1 gate certify step-landings that
18 were only in prose (Opus R18 O18-P0-1: the `/save` check passed while
19 the T8 step had no `/save`).
20 * GONE — the retired literal and its listed paraphrases appear nowhere outside
21 the sanctioned historical narrative.
23It is **NOT** semantic paraphrase detection. The ``gone`` lists are a hand-curated
24exact-substring denylist, case-sensitive; an unforeseen rewording is not caught.
25The v1 tool over-claimed "concept-aware"; that claim is RETRACTED. A deterministic
26checker cannot prove a concept is gone — so a MANDATORY HUMAN CONCEPT AUDIT remains
27part of the fold procedure (plan §7(iii)); this gate is the mechanical floor under
28it, not a replacement for it.
30It is also NOT a completeness proof. ``CHECKS`` is reconciled against ``MANIFEST``
31(the review-finding IDs it must cover) so the denominator cannot silently shrink by
32deleting a check — but a finding nobody added to the manifest is still uncovered.
34V30 (Sol R25 SOL25-03): the R24 lifecycle literals are the smallest complete OPERATIVE
35contracts (the T8 custody phrase with its ledger-hash equality; the freeze-marker
36baseline comparison) instead of bare tokens — Sol executed two single-leg mutations
37that deleted the safety action while keeping the token, and the V29 checks stayed
38green; both are now pinned regression tests. The three T8 blocked-path surfaces
39(step / Gate / AC 22) are checked per-surface, and the receipt enumerates every
40audited source. Still a phrase floor, not a lifecycle proof.
42V31 (operator re-scope directive 2026-07-16 + Fable/Sol R26): the plan's evidence-layer
43dispatch gates were retired by operator directive (threat-matched for a sole-operator,
44local, reversible migration), so SOL25-01/SOL25-01-probe/SOL25-01-vars (the
45authenticated-ledger dispatch gate), TERRA22-04 (the SOL20-04 pre-dispatch commit at
46AC 22), and S23-P1-3 (the retired section-1.0 commit variable) are RETIRED from
47CHECKS+MANIFEST — their anchor text no longer exists in the plan. SOL25-04 is
48RETARGETED to the simple one-commit receipt form of section 7 clause v, and the
49SOL25-02 blocked-path window is WIDENED over the two new close items. New checks:
50F26-01 (the T2 PRESERVE equality oracle), F26-02-step/-gate/-ac22 (the terminal
51artifact manifest blocked-path item, per surface), F26-03 (the rollback-copy and
52DACL-save blocked-path items), R25-01-root (the durable-root declaration — Sol R26
53mutation C, executed false-green at V30, now red), and V31-T8-RECONCILE (the kept T8
54terminal-transition contract at AC 22). The V30 claim that each new check carried a
55single-leg adversarial test was FALSE for five of the nine (Sol R26 SOL26-05); the
56test suite now carries a META-TEST mapping every manifest fid to a named test or the
57documented untested-phrase-floor list, failing on drift.
61 python tools/plan_fold_gate.py # gate the committed HEAD blob (authoritative)
62 python tools/plan_fold_gate.py --worktree # gate the working tree (iterating a fold)
66- :class:`Region` — a bounded span of the plan, located between two anchor strings.
67- :class:`Check` — one finding: its ``new`` literal + the ``region`` it must land in,
68 plus whole-document ``gone`` literals.
69- :data:`CHECKS` / :data:`MANIFEST` — the fold set and the review IDs it must cover.
70- :func:`evaluate` — THE single production predicate: returns the problems for one
71 check against the plan text (the tests call this — they do not re-implement it).
72- :func:`read_plan` / :func:`run` / :func:`main`.
76- 0 — every check passed and the manifest is covered.
77- 1 — a finding did not land at its region, a retired literal survived, or the
78 manifest/checks disagree.
79- 2 — the plan file could not be read.
85 L2 — lifecycle events (the pass/fail tally)
91- The committed blob (``git show HEAD:<plan>``) is authoritative; ``--worktree`` is
92 only for iterating a fold before committing.
93- Historical-scope decision (Opus R17 O17-P1-4): ``gone`` targets a retired concept's
94 OPERATIVE phrasing; a dated statement of fact ("renamed from X", "branch Y is merged
95 and deleted") is allowed, which is why ``gone`` lists operative phrasings not bare
100- oc_diagnostics (structured debug logging via _dbg)
102from __future__
import annotations
107from dataclasses
import dataclass, field
108from pathlib
import Path
111from oc_diagnostics
import _dbg
113_REPO = Path(__file__).resolve().parent.parent
114PLAN =
"oc_chat/plans/completed/151-monorepo-migration.md"
115DEFERRED =
"tools/151_deferred_sol20_tooling.md"
119_SOURCES = {
"plan": PLAN,
"deferred": DEFERRED}
123@dataclass(frozen=True)
125 """A bounded span of the plan, from the line containing ``start`` up to (but not
126 including) the next line containing ``end``. ``end=None`` runs to end-of-document.
127 ``label`` names the surface (step / Gate / AC) for the receipt."""
131 end: str |
None =
None
133 def slice(self, text: str) -> str |
None:
134 i = text.find(self.start)
139 j = text.find(self.
end, i + len(self.start))
140 return text[i:]
if j < 0
else text[i:j]
145 """One folded finding. ``new`` must appear INSIDE ``region``; ``gone`` literals
146 must be ABSENT from the whole document."""
150 new: str |
None =
None
151 region: Region |
None =
None
152 gone: list[str] = field(default_factory=list)
159_T8_CLOSE =
Region(
"T8 close order",
"close order (ONE canonical list",
"Pin the mechanism as")
160_T1_STEP3 =
Region(
"T1 step 3 (fetch)",
"OC_MIGRATION_BRANCH=<pinned>",
"**⚠️")
161_T2_D4 =
Region(
"T2 D4 step",
"D4 — distribution-SUPPLY fix",
"D5 — ONE")
162_T0_LEDGER =
Region(
"§2.1 ledger schema",
"ledger_schema_version, tranche",
"**")
163_S24_ROLLBACK =
Region(
"§2.4 rollback",
"rollback of the structural move",
"###")
164_T1_REHEARSAL =
Region(
"T1 rehearsal Gate",
"the rehearsal runs on a MERGED",
"**")
167_T0_GATE =
Region(
"T0 Gate",
"each anchor tag (`pre-oc-chat-merge`",
"free-space PER-VOLUME BUDGET receipt")
168_T8_MIRROR =
Region(
"T8 terminal transition (canonical close step 6)",
169 "LIFT the freeze (a marker removal, not a failure-capable gate)",
"NEVER the artifact root")
170_AC22_ATOMIC =
Region(
"AC row 22 (T8 close)",
"| 22 | **T8 (close):**",
"| T8 report;")
173_S10_VARS =
Region(
"§1.0 canonical vars",
"ACTIVE_FREEZE_PATH = <dispatch-pinned",
"```")
174_T2_GATE =
Region(
"T2 Gate (workspaces row)",
"the scm `root`-DEPTH re-derivation recorded",
"report-T2.")
178_T8_FAILPATH =
Region(
"T8 step failure path (blocked-path set)",
179 "Failure path: if ANY close gate fails",
"write a NON-terminal")
180_T8_GATE_BLOCKED =
Region(
"T8 Gate (blocked-path set)",
181 "non-terminal BLOCKED path taken on any failed close gate",
182 "never `Completed` before the final ledger entry lands")
183_S7_V =
Region(
"§7(v) fold-evidence protocol",
"(v) THE MECHANICAL FOLD-LANDING GATE",
"| # | Check |")
195_BLOCKED_WINDOW = (
"`tag_receipt_sha256` re-check**, "
196 +
"**independent rollback-copy verified**, "
197 +
"**archive+parent DACL `/save` verified**, "
198 +
"lock, smoke, intact-check")
201_MANIFEST_WINDOW = (
"final report-hash, **`terminal_artifact_manifest` compute + read-back**"
202 ", final ledger-append")
206_AC11 =
Region(
"AC row 11 (runtime-state boundary)",
"| 11 | **Runtime-state boundary",
"| 12 |")
207_AC18 =
Region(
"AC row 18 (T2 D5 + settings)",
"| 18 | **T2 D5 + settings",
"| 19 |")
211 "O16-P1-1",
"O16-P1-3",
"V17-1",
"V17-3",
"V17-4",
"V17-6",
212 "13b",
"SOL16-01",
"O16-P2-1",
"O16-P2-2",
"O17-P1-4",
"O17-P2-2",
213 "SOL17-01",
"SOL17-03",
215 "SOL14-07-rollback-tags",
"SOL16-03-parent-acl",
"D4-gate-ac",
216 "O19-P1-1",
"SOL14-04",
221 "TERRA23-01",
"S23-P1-2",
"OPUS22",
224 "R24-01",
"R24-02",
"SOL24-01",
"SOL24-03",
"SOL24-03-status",
"OPUS22-AC11",
"OPUS22-AC18",
231 "R24-02-schema",
"R25-01",
232 "SOL25-02-step",
"SOL25-02-gate",
"SOL25-02-ac22",
"SOL25-04",
237 "F26-01",
"F26-02-step",
"F26-02-gate",
"F26-02-ac22",
"F26-03",
238 "R25-01-root",
"V31-T8-RECONCILE",
241CHECKS: list[Check] = [
242 Check(
"O16-P1-1",
"fetch pins the migration branch",
243 new=
"OC_MIGRATION_BRANCH", region=_T1_STEP3, gone=[
"main:occ-import"]),
244 Check(
"SOL17-01",
"T1 asserts the POST-filter path + exact tip",
245 new=
"oc_chat/oc_chat/scripts/py_link_check.py", region=_T1_STEP3,
246 gone=[
"occ-import:oc_chat/scripts/py_link_check.py"]),
247 Check(
"O16-P1-3",
"session-log against real symbols", new=
None,
248 gone=[
"update_changelog",
"open(CHANGELOG_PATH",
"core/changelog.py:"]),
249 Check(
"V17-1",
"rehearsal on a MERGED copy of both repos", new=
"MERGED throwaway copy of BOTH repos",
250 region=_T1_REHEARSAL, gone=[
"calibrated RED-then-GREEN on the rehearsal clone"]),
251 Check(
"V17-3",
"freeze-lift order fixed at the STEP", new=
None,
252 gone=[
"no evidence write, no failure-capable gate",
253 "LIFT the freeze + write the SEPARATE"]),
254 Check(
"V17-4",
"ledger schema carries terminal fields",
255 new=
"expected_terminal_transition", region=_T0_LEDGER),
256 Check(
"V17-6",
"DACL /save AT THE T8 STEP", new=
"/save", region=_T8_CLOSE,
258 Check(
"SOL16-03-parent-acl",
"archive parent-ACL + independent copy AT THE T8 STEP",
259 new=
"rollback copy of the archive medium", region=_T8_CLOSE),
260 Check(
"SOL14-07-rollback-tags",
"rollback deletes imported tag refs AT §2.4",
261 new=
"oc_chat-v*", region=_S24_ROLLBACK),
262 Check(
"13b",
"143-family is SIX, 143h merged", new=
None,
263 gone=[
"the five members",
"the 5 members",
"all five members"]),
264 Check(
"SOL16-01",
"D4 is a distribution-supply defect at the STEP",
265 new=
"prove it in a `--no-index` venv", region=_T2_D4,
266 gone=[
"oc-diagnostics>=2.0.0` (D4)",
"D4 — dist-name fix",
"dist-name mismatch"]),
267 Check(
"D4-gate-ac",
"D4 Gate/AC no longer gate on the cosmetic spelling grep", new=
None,
268 gone=[
"D4 verified (`pip check`",
"hyphenated-form grep-zero",
269 "post-reinstall `python -m pip check` exits 0 AND a grep-zero"]),
270 Check(
"O16-P2-1",
"false dev-count receipt deleted", new=
None, gone=[
"0.8.0.dev894"]),
271 Check(
"O16-P2-2",
"hardcoded tag counts gone", new=
None,
272 gone=[
"EXACTLY the 11",
"the 11 renamed",
"option_c's own 5",
"option_c's own **5**"]),
273 Check(
"O17-P1-4",
"no garbled mechanical-replace corruption", new=
None,
274 gone=[
"<path> the bare-`main`",
"unless the confirmed mechanism supersedes static fields"]),
275 Check(
"O17-P2-2",
"pyproject dep-cite re-derived", new=
None, gone=[
"pyproject.toml:41-42"]),
276 Check(
"O19-P1-1",
"T0 Gate verifies peeled target, not existence-only", new=
"PEELED target", region=_T0_GATE),
277 Check(
"SOL14-04",
"the real terminal command is present at the canonical close step so that replacing it with prose fails the check",
278 new=
"plan_status set --status Completed --path", region=_T8_MIRROR),
279 Check(
"SOL17-03",
"no active ref to the removed writer", new=
None,
280 gone=[
"changelog.py:6",
"CHANGELOG is updated automatically"]),
283 Check(
"TERRA23-01",
"the T0 tag receipt is external + carried by the ledger schema, not a report-T0 self-reference",
284 new=
"tag_receipt_sha256", region=_T0_LEDGER,
285 gone=[
"preexisting:false}` is written into report-T0"]),
286 Check(
"S23-P1-2",
"the T8 Gate does not name validate_migration.py as a T0-dispatch check", new=
None,
287 gone=[
"`validate_migration.py` preflights the required-registry mode"]),
290 Check(
"OPUS22",
"the T2 Gate asserts positive workspaces-row equality, not the retired negative check",
291 new=
"its `workspaces` identity row asserted to equal the pinned", region=_T2_GATE,
292 gone=[
"NO `Option_C` literal in the workspaces row"]),
299 Check(
"R24-01",
"lifecycle: the t8 close order performs the tag receipt custody action — the operative contract, not the filename token",
300 new=
"exists + hash unchanged (== ledger entry 0's `tag_receipt_sha256`",
302 Check(
"R24-02",
"lifecycle: the t8 freeze marker re check names its ledger baseline — the operative comparison, not the field token",
303 new=
"== ledger entry 0's `freeze_marker_sha256`", region=_T8_CLOSE),
304 Check(
"R24-02-schema",
"lifecycle: the ledger schema carries the freeze marker hash field",
305 new=
"freeze_marker_sha256", region=_T0_LEDGER),
306 Check(
"SOL24-01",
"the append only chain integrity claim is downgraded to the honest mutable ledger model", new=
None,
307 gone=[
"binds forward via the append-only"]),
308 Check(
"SOL24-03",
"cross file: the retired report t0 receipt model is absent from the deferred tooling doc", new=
None,
309 gone=[
"hash-chained into report-T0"], source=
"deferred"),
310 Check(
"SOL24-03-status",
"the retired report t0 tag mapping receipt phrasing is gone from the plan status and gate note", new=
None,
311 gone=[
"report-T0 tag mapping receipt",
"report-T0 mapping receipt"]),
312 Check(
"OPUS22-AC11",
"ac row 11 asserts the positive workspaces equality not the retired negative",
313 new=
"ASSERTED to EQUAL the pinned", region=_AC11),
314 Check(
"OPUS22-AC18",
"ac row 18 asserts the positive workspaces equality via the sol22 producer",
315 new=
"REWRITTEN and ASSERTED == pinned", region=_AC18),
317 Check(
"R25-01",
"the tag receipt is pinned under the durable artifact root, not at an arbitrary out of worktree path",
318 new=
"T0_TAG_RECEIPT_PATH = <MIGRATION_ARTIFACT_ROOT>", region=_S10_VARS,
319 gone=[
"T0_TAG_RECEIPT_PATH = <dispatch-pinned"]),
323 Check(
"SOL25-02-step",
"the t8 step blocked path set carries the tag receipt re check and the new close items",
324 new=_BLOCKED_WINDOW, region=_T8_FAILPATH),
325 Check(
"SOL25-02-gate",
"the t8 gate blocked path set carries the tag receipt re check and the new close items",
326 new=_BLOCKED_WINDOW, region=_T8_GATE_BLOCKED),
327 Check(
"SOL25-02-ac22",
"the ac row 22 blocked path set carries the tag receipt re check and the new close items",
328 new=_BLOCKED_WINDOW, region=_AC22_ATOMIC),
329 Check(
"SOL25-04",
"section 7 clause v is the simple one commit receipt form run against the committed head",
330 new=
"run `python tools/plan_fold_gate.py` "
331 +
"in committed-HEAD mode and confirm the SAME green result", region=_S7_V,
332 gone=[
"records `C`'s SHA, every audited source's blob hash"]),
334 Check(
"F26-01",
"the t2 preserve equality oracle is the stripped payload content hash, never the re-export file sha",
335 new=
"the `exported_at`/`signature`-stripped payload "
336 "content hash MATCH the T0 receipt", region=_T2_GATE,
337 gone=[
"re-export SHA-256 against T0's receipt",
338 "re-export SHA-256 MATCH the T0 receipt",
339 "re-export SHA matched"]),
340 Check(
"F26-02-step",
"the t8 step blocked path set carries the terminal artifact manifest item in position",
341 new=_MANIFEST_WINDOW, region=_T8_FAILPATH),
342 Check(
"F26-02-gate",
"the t8 gate blocked path set carries the terminal artifact manifest item in position",
343 new=_MANIFEST_WINDOW, region=_T8_GATE_BLOCKED),
344 Check(
"F26-02-ac22",
"the ac row 22 blocked path set carries the terminal artifact manifest item in position",
345 new=_MANIFEST_WINDOW, region=_AC22_ATOMIC),
346 Check(
"F26-03",
"the t8 step blocked path set carries the rollback copy and dacl save items",
347 new=
"**independent rollback-copy verified**, "
348 "**archive+parent DACL `/save` verified**", region=_T8_FAILPATH),
349 Check(
"R25-01-root",
"the migration artifact root declaration keeps its durable comment (sol r26 mutation c)",
350 new=
"# the DURABLE terminal-evidence root", region=_S10_VARS),
351 Check(
"V31-T8-RECONCILE",
"ac row 22 carries the kept t8 contract, monorepo cwd both surfaces and manual reconcile",
352 new=
"documented MANUAL reconcile path on divergence", region=_AC22_ATOMIC),
357 """THE production predicate. Return the problems for ``check`` against ``text``
358 (empty list == pass). Tests call THIS — they do not re-implement it (SOL18-01)."""
359 problems: list[str] = []
360 if check.new
is not None:
361 if check.region
is None:
362 problems.append(f
"NEW {check.new!r} has no region (a whole-doc NEW is not a landing)")
364 span = check.region.slice(text)
367 problems.append(f
"region {r.label!r} not found (start anchor moved)")
368 elif text.count(r.start) != 1:
373 problems.append(f
"region {r.label!r} start anchor {r.start!r} is AMBIGUOUS "
374 f
"(appears {text.count(r.start)}x, must be exactly 1) — "
375 "cross-site prose could substitute for the executing action")
376 elif r.end
is not None and r.end
not in text[text.find(r.start):]:
379 problems.append(f
"region {r.label!r} end anchor {r.end!r} DEAD "
380 f
"(span ran to EOF, {len(span)} chars) — region-scoping defeated")
381 elif len(span) > _REGION_MAX:
382 problems.append(f
"region {r.label!r} span {len(span)} > {_REGION_MAX} "
383 "(anchor too loose to be an executing site)")
384 elif check.new
not in span:
385 problems.append(f
"NEW {check.new!r} ABSENT from {r.label}")
388 problems.append(f
"RETIRED {g!r} SURVIVES")
393 """Return problems if CHECKS and MANIFEST have drifted (a required finding uncovered, or a check not in the manifest)."""
394 fids = {c.fid
for c
in CHECKS}
396 for missing
in sorted(MANIFEST - fids):
397 problems.append(f
"manifest ID {missing!r} has NO check (a required finding is uncovered)")
398 for extra
in sorted(fids - MANIFEST):
399 problems.append(f
"check {extra!r} is NOT in the manifest (denominator drift)")
404 """Return a source file's text: the committed HEAD blob (authoritative) or the worktree.
405 Generalizes ``read_plan`` so a CROSS-FILE check can gate a second file (V29 SOL24-03)."""
407 _dbg(
"OC_CHAT.MAIN", func, f
"{rel_path} worktree={worktree}", 4)
410 return p.read_text(encoding=
"utf-8")
if p.is_file()
else None
411 proc = subprocess.run(
412 [
"git",
"show", f
"HEAD:{rel_path}"], cwd=str(_REPO),
413 text=
True, capture_output=
True, encoding=
"utf-8",
415 return proc.stdout
if proc.returncode == 0
else None
419 """Return the plan text (back-compat shim over :func:`read_source`)."""
423def run(worktree: bool) -> int:
424 """Evaluate every check, print the labelled receipt, return the process exit code."""
426 texts: dict[str, str] = {}
427 for name, rel
in _SOURCES.items():
430 print(f
"!! could not read {rel}", file=sys.stderr)
433 src =
"WORKTREE" if worktree
else "HEAD"
434 print(f
"fold landing gate, region scoped and exact substring, at {src}")
437 for name
in sorted(_SOURCES):
438 print(f
"audited source {name}: {_SOURCES[name]} at {src}")
442 problems =
evaluate(texts[c.source], c)
443 print(f
"[{'PASS' if not problems else 'FAIL'}] {c.fid:24} {c.name}")
450 print(f
"[FAIL] MANIFEST {p}")
451 total = len(CHECKS) + (1
if mprobs
else 0)
452 fails += 1
if mprobs
else 0
454 print(f
"{total - fails} of {total} checks pass and {fails} failed. the new text is region scoped and the retired text is gone; the human concept audit is still required.")
455 _dbg(
"OC_CHAT.MAIN", func, f
"{total - fails}/{total} pass ({src})", 2)
456 return 1
if fails
else 0
459def main(argv: list[str] |
None =
None) -> int:
460 """CLI entry point."""
466 oc_diagnostics.init(intercept_streams=
False, intercept_exceptions=
False)
467 _dbg(
"OC_CHAT.MAIN", func,
"parsing args", 4)
468 ap = argparse.ArgumentParser(prog=
"plan_fold_gate.py", description=
"Fold-landing gate for plan 151.")
469 ap.add_argument(
"--worktree", action=
"store_true",
470 help=
"gate the working tree instead of the committed HEAD blob")
471 args = ap.parse_args(argv)
472 return run(args.worktree)
475if __name__ ==
"__main__":
476 raise SystemExit(
main())
str|None slice(self, str text)
list[str] evaluate(str text, Check check)
list[str] _manifest_problems()
str|None read_plan(bool worktree)
str|None read_source(str rel_path, bool worktree)
int main(list[str]|None argv=None)