Skip to content

fix(ratchet): exempt a ruled ceiling from opportunistic tightening - #1612

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-1607-ruled-ceiling-exempt-from-tightening
Sep 5, 2026
Merged

fix(ratchet): exempt a ruled ceiling from opportunistic tightening#1612
os-steve merged 1 commit into
mainfrom
claude/issue-1607-ruled-ceiling-exempt-from-tightening

Conversation

@os-steve

@os-steve os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1607

The opportunistic-tightening advisory offers to re-derive a ceiling from the current reading. That only means something for an anchored ceiling — one derived as anchor(reading) in the first place. A ruled ceiling is a maintainer grant no reading derives, so on business semantics the advisory was printing, on every run, an instruction to hand back the 15,421 tokens of headroom the ruling had just been made to create.

The finding, first — the distinction was not in the code

⚠️ PR #1606 introduced the ruled/anchored concept, but it landed only in the header's prose and in the test suite's RULED_ROW parsing of that prose. At runtime CEILINGS was a bare Map<label, number>; nothing the gate executes could tell the two kinds apart. So this card could not simply "key the exemption on the existing distinction" — the distinction had to be lifted into the code first, which is the bulk of this diff.

COMMITTED now declares each ceiling's number and its kind, and CEILINGS / CEILING_KINDS both derive from that one table, so a ceiling cannot carry its number in one place and its kind in another that disagrees. The advisory asks isAnchored(label) at the single place it fires. A ceiling declaring an unrecognised kind is a hard error rather than a default, because neither default is safe: one silently drops the advisory for a layer that owes it (a weakened ratchet), the other silently restores this hazard on the next grant.

Evidence — three runs of the gate, not three greens

1 — Before (origin/main @ 57ce7204, exit 0). Reproduces the card's reading exactly:

  ✓ business semantics ~84,579 tokens (ceiling ~100,000; headroom ~15,421).
      ℹ️  headroom is 15,421 tokens, over twice the 5% buffer — re-anchor this ceiling to ~89,000 in your PR; shrink-only ratchets tighten opportunistically.

2 — After (this branch, exit 0). The nag is gone; the ceiling and the headroom are still reported, so the row is exempt, not hidden:

  ✓ business semantics ~84,579 tokens (ceiling ~100,000; headroom ~15,421).
      ℹ️  ruled ceiling — a maintainer grant, not `anchor()` of a reading, so this gate does not offer to re-anchor it; the ~15,421 tokens of headroom are the ruling's. Lowering it needs a ruling quoted in the lowering PR, exactly as raising it does.
  ✓ interaction layer ~37,447 tokens (ceiling ~40,000; headroom ~2,553).
  ✓ authored total ~136,366 tokens (ceiling ~140,000; headroom ~3,634).

✓ source token ratchet clean

3 — Control: an anchored layer still gets the advisory when it qualifies. Neither anchored layer qualifies naturally today (headroom 2,553 and 3,634), so the condition was constructed: interaction layer ceiling temporarily 40,000 → 50,000. Mutation proved on disk before the run ('ceiling: 40000' occurrences 1 → 0, 'ceiling: 50000' now 1), gate exit 0:

  ✓ business semantics ~84,579 tokens (ceiling ~100,000; headroom ~15,421).
      ℹ️  ruled ceiling — a maintainer grant, not `anchor()` of a reading, so this gate does not offer to re-anchor it; …
  ✓ interaction layer ~37,447 tokens (ceiling ~50,000; headroom ~12,553).
      ℹ️  headroom is 12,553 tokens, over twice the 5% buffer — re-anchor this ceiling to ~40,000 in your PR; shrink-only ratchets tighten opportunistically.

3b — Control: the key is the KIND, not the label. Same label, same 100,000 ceiling, kind flipped RULEDANCHORED. The original advisory returns verbatim, ~89,000 included — which is what rules out a label hard-code:

  ✓ business semantics ~84,579 tokens (ceiling ~100,000; headroom ~15,421).
      ℹ️  headroom is 15,421 tokens, over twice the 5% buffer — re-anchor this ceiling to ~89,000 in your PR; shrink-only ratchets tighten opportunistically.

Both mutations ran under a trap … EXIT INT TERM, restored with git checkout HEAD -- <path>, and each restore is proved by blob hash — restored b5a5fdb981218cd28f8c473a8ef69a6c0299a143 on both legs, identical to HEAD:scripts/check-source-token-ratchet.mjs. git status is clean.

What the test suite establishes

test/source-token-ratchet.test.ts gains two cases (22 → 24, all green). They are what judges this change; hygiene:tokens green says only that the gate still runs.

  • exempts a RULED ceiling from that nag, and exempts only the ruled kind — spawns the real gate in the sandbox against fixtures tiny enough that every committed ceiling is past the advisory's trigger (asserted first, so "no nag" cannot be a quiet run). Which rows are expected to nag is derived from CEILING_KINDS, never listed: a case naming business semantics would pass for the wrong reason. The anchored branch asserts the advisory is unchanged, down to the anchor() figure it names — that branch is the control that stops this card being satisfied by silencing the advisory generally.
  • declares in code the same kinds the header states in prose — the header's ruled/anchored rows must match CEILING_KINDS. Both ways of disagreeing are silent: a row rewritten as ruled while the constant stays anchored documents an exemption that never fires; the reverse drops the advisory for a layer that owes it.

Scope and the guards left standing

  • ⛔ The raise guard is untouched. The header keeps "Lower them whenever the tree shrinks — that is free and encouraged. Raising one requires a maintainer ruling quoted in the raising PR's body", now qualified as being about the anchored kind, plus the symmetric half: a ruled ceiling is not a function of the tree, so lowering one requires a ruling quoted in the lowering PR too. That is the half no automated suggestion can supply.
  • feat(ratchet): rule the business-semantics ceiling to 100,000 and decouple the README banner #1606's interim prose is updated, not deleted — it still says a ruled ceiling is not tightened on an advisory's word alone, and now also describes the mechanism that enforces it.
  • Nothing under src/. Two files plus the changeset; test/** touched only in test/source-token-ratchet.test.ts, additively, no deletions.
  • Changeset: the empty-frontmatter "releases nothing" form, matching .changeset/ratchet-footer-names-the-stripper-importer.md already on main. This PR is repository tooling — nothing under src/ changed and nothing ships to HotCRM users. No links in it, so link-check has nothing site-absolute to resolve.

Gates

pnpm verify (validate · typecheck · lint · lint:i18n-gate · hygiene · hygiene:tokens · build · test) — exit 0, 160 test files, 3394 passed / 1 skipped. Re-run after the final commit: the three suites that import from this gate, 67 passed, exit 0.

⛔ Draft on purpose — not marked ready, not enqueued, no auto-merge; the seat lands it.

🤖 Generated with Claude Code

https://claude.ai/code/session_018xtjdpZFjgWh4Ad9Wcx68J


Generated by Claude Code

The gate's opportunistic-tightening advisory offers to re-derive a ceiling
from the current reading, which only means something for an ANCHORED
ceiling — one derived as `anchor(reading)` in the first place. A RULED
ceiling is a maintainer grant no reading derives, so on `business
semantics` the advisory printed, on every run, an instruction to hand back
the 15,421 tokens of headroom the ruling had just been made to create. An
agent following it in good faith would have undone a ruling and no check
would have objected, because the resulting ceiling would be a perfectly
valid anchored one.

The ruled/anchored distinction existed only in the header's prose, where
the code could not act on it. Lift it into the code beside each committed
ceiling: `COMMITTED` declares the number and the kind, `CEILINGS` and
`CEILING_KINDS` derive from that one table, and the advisory asks
`isAnchored(label)` at the single place it fires. A ceiling declaring an
unrecognised kind is a hard error rather than a default, because neither
default is safe — one drops the advisory for a layer that owes it, the
other restores this hazard on the next grant.

The advisory is unchanged for anchored ceilings. The ruled row prints what
it is instead of a nag, so the exemption is visible where a reader meets
it. The header's interim prose is updated to describe the mechanism rather
than to stand in for it, and the raise guard gains its symmetric half:
lowering a ruled ceiling needs a ruling too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018xtjdpZFjgWh4Ad9Wcx68J
@vercel

vercel Bot commented Sep 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Sep 5, 2026 11:52pm UTC

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline

Projects

None yet

2 participants