Skip to content

feat(ratchet): verify first contact and the guard's own routing table - #2494

Merged
POWERFULMOVES merged 1 commit into
mainfrom
feat/anchor-orientation-and-roads
Aug 8, 2026
Merged

feat(ratchet): verify first contact and the guard's own routing table#2494
POWERFULMOVES merged 1 commit into
mainfrom
feat/anchor-orientation-and-roads

Conversation

@POWERFULMOVES

Copy link
Copy Markdown
Owner

What

The anchor ratchet checked docs, skills and runbooks. It did not check the two surfaces that decide whether an agent entering this repo succeeds or breaks something.

1. First contact

.claude/CLAUDE.md, BOOTSTRAP.md, PATTERNS.md, CATALOG.md, root CLAUDE.md and AGENTS.md are always loaded. An agent reads them before anything else — so a dead reference there is the most expensive kind there is. The agent is misdirected at step one, improvises, breaks something, and the model gets blamed for the field's error.

Four real ghosts, immediately:

File Ghost target
.claude/CLAUDE.md worktree-sitrep-strict — described in-file as "Authoritative worktree sitrep. Prefer this to per-worktree spot checks."
.claude/PATTERNS.md worktree-sitrep, worktree-sitrep-strict
.claude/BOOTSTRAP.md health-quick

Also now scanned: .claude/context, .claude/commands, .claude/agents. .claude/learnings/ is excluded alongside archive/ — a learnings file records what was true in a past session. It's a log, not a promise.

2. The guard's own routing table

patterns.yaml is the best thing in this repo. 121 entries, each carrying why this is wrong, the correct path, the valid parameter set, and how to verify afterwards — with ask: true rather than a hard no. It routes a blocked agent to safety instead of just refusing it.

Nothing checked where it routes to. New GHOST_ROAD class points the same GHOST_TARGET question one layer inward — at the thing that answers that question for everyone else. Two of its 13 offered targets don't exist:

mini-cli stop/down/reset  ->  "use make -C pmoves targets"           GHOST
schema changes            ->  "apply with make -C pmoves db-migrate"  GHOST

A well-behaved agent that follows the offered road lands in a wall at the moment it is least able to recover. That's the failure being described when models "get dropped in and break things" — it was never the model.

Two discriminators, so the gate doesn't punish the docs doing it right

.claude/PATTERNS.md:38 and AGENTS.md:28 both carry a | Raw command (blocked) | Known Road | table mapping docker volume rmmake -C pmoves volume-reset SERVICE=.... They name the dangerous operation in order to route away from it. Flagging those would punish the cure.

A line is treated as documentation rather than instruction when it either names its Known Road on the same line, or frames the command as blocked / dangerous / anti-pattern. Semantic, deliberately not a file whitelist — a whitelist would also hide a real instruction hiding in the same file.

Two bugs fixed along the way: the first cut tested the inline span rather than the line it sits on, so a road sitting next to the command in a table row was invisible and both correct docs got flagged. And up-<service> placeholders render as up- after extraction — the trailing hyphen is the tell.

One bug worth recording

Writing a literal \b into a discriminator through a heredoc escape-interprets it to 0x08, silently replacing the word boundary with a backspace:

DESCRIBES_BLOCK_RE = re.compile(r"^HBlocks?:|^Hblocked^H|...")     # ^H = 0x08

The regex then matched nothing, so the exemption looked broken rather than absent. Same class as the corruption that turned feat/ into eat/ in the claim register (#2476) — second time today. Regexes are now built rather than typed, and a test asserts no control characters survive in any of them.

Verification

$ make -C pmoves validate-command-anchors
Anchor findings: 436 total, 436 baselined, 0 new
PASS — no findings outside the baseline, no stale entries.

$ python -m pytest pmoves/tools/tests/test_validate_command_anchors.py -q
32 passed

Baseline 409 → 418.

Not approved, just baselined

The four orientation ghosts and two dead roads are recorded, not accepted. They're the first things that should be fixed — and now they can't silently multiply.

Follow-ups from the same thread, in leverage order:

  1. Retire the duplicate deny-list. .claude/hooks/pre-tool.sh carries a flat 11-entry list. make -C pmoves appears nowhere in it; "Known Road" appears nowhere in it. 5 of its 11 entries are already in patterns.yaml — duplicated, minus the affordance. Same "layer re-types instead of naming" defect as the four cleanup copies. Its flat rm -rf / also matches rm -rf /var/lib/apt/lists/*, a standard Dockerfile line.
  2. Fix the six findings above — add the targets, or correct the docs.
  3. Repoint the wall-teaching docs at their roads — three Neo4j guides teach docker volume rm pmoves_neo4jdata when volume-reset SERVICE=neo4j exists.

🤖 Generated with Claude Code

The anchor ratchet checked docs, skills and runbooks — but not the two surfaces
that decide whether an agent entering this repo succeeds or breaks something.

FIRST CONTACT. .claude/CLAUDE.md, BOOTSTRAP.md, PATTERNS.md, CATALOG.md, the root
CLAUDE.md and AGENTS.md are ALWAYS LOADED. An agent reads them before it reads
anything else, so a dead reference there is the most expensive kind: the agent is
misdirected at step one, improvises, breaks something, and the model gets blamed
for the field's error. They were not scanned. Now they are, along with
.claude/context, .claude/commands and .claude/agents.

Four real ghosts surfaced immediately, all in always-loaded files:

  .claude/CLAUDE.md    `make -C pmoves worktree-sitrep-strict`
                       — described in-file as "Authoritative worktree sitrep.
                         Prefer this to per-worktree spot checks." No such target.
  .claude/PATTERNS.md  `worktree-sitrep`, `worktree-sitrep-strict`
  .claude/BOOTSTRAP.md `health-quick`

.claude/learnings/ is excluded alongside archive/: a learnings file records what
was true in a past session. It is a log, not a promise.

THE GUARD'S OWN ROUTING TABLE. .claude/hooks/damage-control/patterns.yaml is the
best thing in this repo — 121 entries, each carrying why-this-is-wrong, the
correct path, the valid parameter set, and how to verify afterwards, with
ask:true rather than a hard no. It routes a blocked agent to safety. But nothing
checked where it routes TO. New GHOST_ROAD class points the same GHOST_TARGET
question one layer inward, at the thing that answers that question for everyone
else. Two of its 13 offered targets do not exist:

  mini-cli stop/down/reset  -> "use make -C pmoves targets"          GHOST
  schema changes            -> "apply with make -C pmoves db-migrate" GHOST

A well-behaved agent that follows the offered road lands in a wall at the moment
it is least able to recover.

TWO DISCRIMINATORS, so the gate does not punish the docs doing this right.
.claude/PATTERNS.md:38 and AGENTS.md:28 both carry a
"| Raw command (blocked) | Known Road |" table mapping `docker volume rm` ->
`make -C pmoves volume-reset SERVICE=...`. They name the dangerous operation in
order to route away from it. A line that names its Known Road on the same line,
or that frames the command as blocked/dangerous/anti-pattern, is documentation
rather than instruction. Semantic, deliberately not a file whitelist — a
whitelist would also hide a real instruction hiding in the same file.

Also fixed: the first cut tested the inline SPAN rather than the LINE it sits on,
so the road sitting next to the command in a table row was invisible and both
correct docs were flagged. And `up-<service>` placeholders render as `up-` after
extraction; the trailing hyphen is the tell.

One bug worth recording because it has now bitten twice in one day: writing a
literal backslash-b into the discriminator through a heredoc escape-interprets it
to 0x08, silently replacing the word boundary with a backspace. The regex then
matched nothing and the exemption looked broken rather than absent. Same class as
the corruption that turned `feat/` into `eat/` in the claim register (#2476).
Regexes are now built rather than typed, and a test asserts no control characters
survive in any of them.

Baseline 409 -> 418. 32 tests.

The four orientation ghosts and two dead roads are baselined, not approved. They
are the first things that should be fixed, and now they cannot silently multiply.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@POWERFULMOVES, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e550c46e-14d0-46e0-88af-bb671084d29e

📥 Commits

Reviewing files that changed from the base of the PR and between 21f7fb5 and 950176d.

📒 Files selected for processing (4)
  • .github/workflows/validate-command-anchors-ratchet.yml
  • pmoves/configs/command_anchors/_known_gaps.yaml
  • pmoves/tools/tests/test_validate_command_anchors.py
  • pmoves/tools/validate_command_anchors.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added workflows GitHub Actions workflows config pmoves/config(s)/ changes labels Aug 8, 2026
@POWERFULMOVES
POWERFULMOVES merged commit 304a8c7 into main Aug 8, 2026
25 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the feat/anchor-orientation-and-roads branch August 8, 2026 18:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 950176d162

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +313 to +314
if ROAD_IN_LINE_RE.search(line) or DESCRIBES_BLOCK_RE.search(line):
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Evaluate exemptions per command candidate

This skips the entire line before extracting command candidates, so a live instruction such as “If deployment is blocked, run docker system prune -a” is ignored merely because it contains the word blocked; likewise, an unrelated make -C pmoves ... anywhere on the line suppresses every blocked command on that line. A newly documented destructive command can therefore pass the ratchet silently. Apply the exemption to the relevant candidate or require explicit anti-pattern/Known-Road framing rather than broad substring matches on the whole line.

Useful? React with 👍 / 👎.

rel = GUARD_PATTERNS.relative_to(REPO_ROOT).as_posix()
text = GUARD_PATTERNS.read_text(encoding="utf-8", errors="replace")
findings: List[dict] = []
for t in sorted({m.group(1) for m in GUARD_ROAD_RE.finditer(text)}):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude YAML comments from guard-road discovery

The regex scans the complete YAML text, including comments and pattern values, although only corrective routing messages actually offer roads. For example, the current file already contains a historical comment mentioning make up-z890; if a similar comment mentions a removed make -C pmoves old-target, this workflow reports a new GHOST_ROAD and blocks the PR even though the guard never presents that target to an agent. Restrict discovery to non-comment routing fields such as reason.

Useful? React with 👍 / 👎.

POWERFULMOVES added a commit that referenced this pull request Aug 8, 2026
…PARK (#2495)

Today's ratchets made every NAMED thing in this repo checkable. They made
nothing WORKED checkable. validate-command-anchors (#2488, #2494) proves a
skill's targets, path citations, ssh hosts and the guard's own routing table all
resolve. It cannot prove the skill does what it claims. A skill can be perfectly
anchored and completely wrong.

The ladder, named so the rungs stop being confused for each other:

  T1 anchored   does everything it names exist?      validate-command-anchors  SHIPPED
  T2 exercised  does it do what it claims, on a      Danger Room               THIS HANDOFF
                real node?
  T3 receipted  can another node verify that         CHIT + NATS               designed, follows T2
                without re-running it?

T1 without T2 is a spell-checked lie. T2 without T3 is a result only the node
that ran it can trust.

SPARK on capability, not availability. GB10 / 128 GB unified means a skill
claiming "route through TensorZero to a local model" can actually be exercised;
on a CPU node that run is a mock, and a mock receipt is worse than none. Its claw
scope already carries sign_trail: true + damage_control_hooks: true, so T3 needs
no new trust wiring. And a sandbox resets free — skills get run against their
worst fixture rather than their friendliest.

The stage requested is five pieces, each grounded in something that bit this
node today:

  1. a pmoves-skill-check template beside templates/base, WITH SUBMODULES
     POPULATED — SUBMODULE_BUILD_AND_MOUNT_GAP.md applies directly here and an
     empty-submodule sandbox produces confident false negatives.
  2. an ADDITIVE skill frontmatter contract (scope / nodes / danger_room), where
     scope reuses the classifier vocabulary validate_command_anchors already
     has rather than inventing a second one. Declared scope disagreeing with
     actual command scope is itself a finding.
  3. fixtures that PLANT A FALSIFIABLE FAILURE, versioned beside the skill. A
     fixture that plants nothing verifies nothing.
  4. artifacts that are deterministic, self-describing (carrying the skill
     CONTENT HASH, or the verdict cannot be tied to what it judged),
     signed-or-explicitly-labelled-unsigned, and addressable. A verdict on one
     node's local disk is a rumour everywhere else.
  5. CHIT reflection: one skill.verified.v1 receipt per run, closed schema
     registered BEFORE first publish. archon.crawl.* is the cautionary tale of a
     subject registered against an operation nobody built.

Acceptance is written to be observable from artifacts alone, so the lane does
not require me present for a run. The load-bearing criterion is that a
DELIBERATELY BROKEN SKILL PRODUCES A RED ARTIFACT — every gate shipped on this
node today was weaker than advertised until something proved it could say no.

Why it matters past hygiene: a 1B-param agent cannot judge whether a skill will
work, but it can read a receipt. The heavy model pays discovery cost once in the
sandbox and leaves pre-digested context; the small model selects on it instead of
reasoning about it. Same principle patterns.yaml already proves — the guard hands
over the correct path, valid parameters, and how to verify, so the model need not
know PMOVES. Capability in the field rather than the model, extended from "what
to do when blocked" to "what actually works."

Not claimed by 4090 — SPARK is named owner and the row is left open for SPARK to
CLAIM. Out of scope and flagged: deploying e2b-mcp-server (Agent Zero registers
e2b.* against :7073, which is not a compose service, is not running, and for
surf has no route in the fork at all — separate lane, must not block this one);
retrofitting all 31 skills; building T3 before T2 emits something worth signing.

Gitlink for PMOVES-E2B-Danger-Room is currently drifted (+) — noted in the doc,
sync before building the template.

Verified: make -C pmoves validate-command-anchors passes on both new files.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Aug 9, 2026
…reign RELEASE lines (#2498)

* docs(agnote): WS2 RELEASE + lane sweep — evidence for owners, no foreign RELEASE lines

Two entries.

RELEASE — WS2 (z890's coordination plan) is complete inside its 72h TTL. Eight
PRs merged: #2482 claim+handoff+corrections, #2483 ci-expedition skill, #2484
claude-pmoves delegation, #2485 submodule gap runbook, #2486 up-* inventory,
#2488 validate-command-anchors, #2494 first-contact + guard routing table, #2495
Danger Room handoff to SPARK. pmoves/mk/infra.mk untouched throughout — z890's
#2480, no collision.

The entry records what the audit found BEYOND its enumerated items, because that
is the reusable part: a gate can advertise coverage it does not have (three
separate instances, each caught by review rather than by me); the always-loaded
orientation file misdirects first contact; the guard's own routing table has two
dead roads; and patterns.yaml is the pattern worth generalizing while
pre-tool.sh duplicates 5 of its entries minus the affordance.

It also records four corrections to my own prior work — the wrong 13-of-15
figure, the retracted hf-mcp-server entry, the dangerous first up-* retire list,
and the yt-cookies pair that was never a duplicate. A closeout that only lists
wins is not a closeout.

NOTE — lane sweep. 115 CLAIM against 119 RELEASE. Four Mavis lanes verified
shipped and missing only a RELEASE (harness v0 #2437/#2443/#2450, multi-fork
follow-ups #2477, OpenRoom slice 2, creative-pipeline v0). Four older lanes
still open with no PR cited and nothing found merged, now 8-10 days. Mine that
are correctly still open: #2446 draft, #2468 held for review, and the SPARK
handoff awaiting its CLAIM.

ZERO RELEASE lines written on another agent's behalf — verified in the diff.
Those lanes are Mavis's to close under Village Rule; this records evidence so
they can close from it rather than from memory. Kept distinct from the
KIMI-SPARK / CRUSH stale claims, which need a release OR re-claim — different
category, and conflating them would make the ping inaccurate.

Verified: make -C pmoves validate-command-anchors passes.

Note for follow-up: dogfooding this entry surfaced a real false-positive
generator in MAKE_CITE_RE — `-C \S+` swallows a closing backtick, so prose that
backticks "make -C pmoves" alone captures the following word as a target. Fixed
separately, not folded in here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(agnote): state the counting method, and stop treating merge as acceptance

Three review findings, all correct, all mine.

1. THE TOTALS WERE NOT REPRODUCIBLE. I published "115 CLAIM against 119 RELEASE"
   with no method attached. Recounting three ways on the same file:

     anchored bullet rows      115 / 119   <- what I published
     token anywhere in text    284 / 221   (prose mentions)
     timestamped, no anchor    116 / 119

   and the 2026-08-07 sweep reported 121 / 115 on a fourth. None of these is
   wrong; a bare number with no pattern is. The entry now states the exact regex,
   lists what the other methods give, and says to treat the ratio as a rough
   signal rather than a metric — the per-lane table is the checkable part.

2. MERGE IS NOT RUNTIME ACCEPTANCE. I listed OpenRoom slice 2 under "verified
   shipped, missing only a RELEASE" on the strength of #2437 merging. That lane
   was claimed against six handoff priorities with room-level acceptance, and
   #2437 is scaffold plus iframe wiring. Merging it does not demonstrate the
   rooms render.

3. Same for line 1723: it covers three deliverables including fork-side
   consumers, and #2477 merging in PMOVES.AI says nothing about whether the fork
   consumers landed.

Both are now "merged, acceptance unverified" rather than ready-to-release, with
the reasoning stated so the owner closes from runtime evidence instead of from
my table.

This is precisely the error the register exists to prevent, made by the sweep
that exists to catch it — which is worth leaving visible rather than quietly
correcting. Every gate I shipped this week was weaker than advertised until
something proved it could say no; this one was a bookkeeping claim that had not
been asked to reproduce itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config pmoves/config(s)/ changes workflows GitHub Actions workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant