Skip to content

arch-ratchet: independent receipt, owner and expiry per exception; app_lines ratchets; blocking escapes need a review record - #28195

Merged
lawrencecchen merged 1 commit into
feat-cmux-nextfrom
cp/feat-ratchet-review-rule
Oct 31, 2026
Merged

lawrencecchen merged 1 commit into
feat-cmux-nextfrom
cp/feat-ratchet-review-rule

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Reward-hacking audit (cmux-ad, 2026-10-30). On perf/chrome-parity, blocking_allow_escapes went 0 -> 19 through ratchet exceptions that the tasks that needed them wrote, and app_lines went 143,610 -> 164,014 while it was report only. This PR ports the checker rule to feat-cmux-next first (lead decision), before the 6 tip rises are decided under it.

  • An arch-ratchet.json exception allows nothing unless it has author, owner, an independent receipt (Review (<reviewer>): SHIP at <40-hex sha>, reviewer not the author) and an expiry.
  • --update never records a blocking-escape rise as upstream debt.
  • New escape_reviews record: a push that adds or edits a blocking escape site needs a reviewed entry for that site. --audit lists unreviewed, expired and stale entries.
  • app_lines (CmuxNextApp physical lines) is a ratcheted row: a push may not raise it.

The checker and its tests only. No CI job, step or gate is added (the ratchet runs in the pre-push hook only). No arch-ratchet.json change.

Effect on this tip: the 9 pending exceptions on feat have no receipt, owner or expiry, so they now allow nothing. --update already refused at 84bca8e (6 rows over the record) and still refuses. app_lines is 158,210 here against the recorded 143,610, so it becomes a 7th row for the tip follow-up. A feature push that grows CmuxNextApp is now refused at pre-push. It must move the code to its own target or pay with removed App lines.

Testing

Python, on the VM (these are not CI jobs):

  • scripts/cmux-next/tests/test_arch_ratchet.py OK. The 5 new tests fail on the old checker (4 FAIL, 1 ERROR).
  • scripts/cmux-next/tests/test_layer_gate.py OK.
  • scripts/cmux-next/tests/test_perf_cron_arch_report.py OK.
  • tests/test_cmux_next_codebase_health.py OK.
  • tests/test_cmux_next_guardrails.py 128 OK.

Observed / Not run

  • Observed: the five suites above, and arch-ratchet.py --audit at this head (it lists the 3 unreviewed escapes and 7 rows over the record).
  • Not run: no Swift build (Python only). A compile-check of the head is submitted for the risk:high evidence.

Changelog

none

Risk evidence (risk:high, gate enforcer)

… an expiry; app_lines ratchets; blocking escapes need a review record

Reward-hacking audit (cmux-ad 2026-10-30, findings 2 and 6; lead decision: port the rule to feat
first, as its own PR, then decide the tip rises under it). Same change as d173b9a on
perf/chrome-parity, the checker and its tests only (no arch-ratchet.json change).

- An exception allows nothing unless it has `author`, `owner`, a `receipt`
  `Review (<reviewer>): SHIP at <40-hex sha>` whose reviewer is not the author, and an `expiry` not
  before its date. The refusal text prints the full form. Applied entries stay verbatim.
- `--update` never records a blocking_allow_escapes rise as upstream debt (no generated entry).
- `escape_reviews` in arch-ratchet.json: a push that adds or edits a blocking escape site needs a
  reviewed entry for it, whatever exception covers the count. `--audit` lists sites with no entry,
  unreviewed and expired entries, and stale entries. `--update` keeps the list.
- app_lines is a ratcheted row: a push may not raise CmuxNextApp's physical lines, and its recorded
  total may not rise by hand.

Effect on this tip: the 9 pending exceptions on feat have no receipt, owner or expiry, so they now
allow nothing; `--update` already refused at 84bca8e (6 rows over the record) and still does.
app_lines is 158,210 here against the recorded 143,610: that is a 7th row for the tip follow-up
(handoff/followups.md "arch-ratchet tip rises (no exceptions)").

Tests (python, local; not CI): scripts/cmux-next/tests/test_arch_ratchet.py OK (5 new tests, red on
the old checker), test_layer_gate.py OK, test_perf_cron_arch_report.py OK,
tests/test_cmux_next_codebase_health.py OK, tests/test_cmux_next_guardrails.py 128 OK.
@lawrencecchen lawrencecchen added the risk:high Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 28 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp1rfe6xjs/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmp7k7lz0ih/summary-missing.json (live):/summary-missing.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='', primary='failure')/
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='', primary='failure')
View Logs
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='', primary='success')/
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='', primary='success')
View Logs
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='blacksmith-16vcpu-ubuntu-2404', primary='failure')/
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='blacksmith-16vcpu-ubuntu-2404', primary='failure')
View Logs
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='blacksmith-16vcpu-ubuntu-2404', primary='success')/
test_every_linux_nightly_job_takes_a_runner_set_member (main.NightlyTrustedRouting.
test_every_linux_nightly_job_takes_a_runner_set_member) (job='attest-nightly-remote-dae
mon', runner='blacksmith-16vcpu-ubuntu-2404', primary='success')
View Logs

...and 18 more test failures. View all on Blacksmith

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 59dc602: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr28195 -f ref=cp/feat-ratchet-review-rule -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: 3 commit(s) change the sidebar's drawing code without a Sidebar-Look: trailer or an entry in plans/cmux-next/sidebar-owner.md is not red on the base e863077; do not merge until green; see lane-rules

Shipped in:

@github-actions github-actions Bot added risk:normal Risk tier (docs/ci/risk-tiers.md) and removed risk:high Risk tier (docs/ci/risk-tiers.md) labels Oct 30, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (independent review subagent, risk:high ratchet): SHIP at 59dc602
perf claim: none
compile: da4983f0e80f2b29fda923e8 passed

What I checked (read-only, no Swift or Rust run):

  • Holes for a ratcheted rise: a push gets allowance only from non-generated entries that pass review_problems (added_exceptions filters generated entries). A hand-written raised_by entry gives only what generated_allowance re-derives from upstream commits, and that function now skips blocking_allow_escapes. update() does not record an escape rise as upstream debt. Layer-gate entries go through the same valid_exception. A layer-map exceptions or relayered entry without review does not cover the count row. An edit of an applied entry is refused (verbatim compare). A site that moves to another file, or an edit of its text, makes a new (path, text) key and is refused without a reviewed escape_reviews entry (fail closed). A missing or broken head json gives no reviews (fail closed).
  • Normal pushes: escape_rule reads the json only when a push adds a site. record() has one caller and the new parameter is optional.
  • Tests: test_arch_ratchet 109 OK, test_layer_gate 55 OK, test_cmux_next_guardrails 128 OK, test_cmux_next_codebase_health 10 OK. --audit runs and lists 3 escape sites with no entry and 7 rows over the record.
  • No .github change, no CI job, step or gate added. arch-ratchet.json and app-size-baseline.txt are not changed. No total is lowered and no limit is raised. app_lines changes from report only to ratcheted (stricter).

Notes (no block):

  • The rule cannot prove identity. The self-review check is a casefold compare of the names only, and the receipt sha is not checked as a real commit or as the head. Any other name passes. The landing record must carry the receipt.
  • expiry is not compared with today at push time. A new exception or escape review can be already expired. --audit lists expired escape_reviews entries only, not expired exceptions.
  • Stale text: arch_rules/layer_gate.py escape() (and its docstring) and the arch_rules/__init__.py docstring still show the old form {"date", "row", "allow", "why"}. An agent that follows the layer-gate refusal text writes an entry that now allows nothing (fail closed; the ratchet note says what it lacks). Fix in a follow-up.
  • The PR label is risk:normal. The change is to a gate enforcer, so it is risk:high.

@lawrencecchen lawrencecchen added risk:high Risk tier (docs/ci/risk-tiers.md) ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds and removed risk:normal Risk tier (docs/ci/risk-tiers.md) labels Oct 30, 2026
@github-actions github-actions Bot added risk:normal Risk tier (docs/ci/risk-tiers.md) and removed risk:high Risk tier (docs/ci/risk-tiers.md) labels Oct 30, 2026
lawrencecchen added a commit that referenced this pull request Oct 30, 2026
Follow-up of #28195, same review as the --audit change before it (lead, 2026-10-30): a push could add an
exception whose expiry was already past, and it allowed its rise. added_exceptions now drops an entry
the push adds (one the base does not have) whose expiry is before today, with a note; an entry the
base had keeps its standing, and --audit reports it once it expires. The test fixtures' review expiry
is now 2999-12-31, so the suite does not turn red on 2026-11-06.

Test: scripts/cmux-next/tests/test_arch_ratchet.py OK (new
test_an_exception_added_after_its_expiry_allows_nothing, red without the change), test_layer_gate.py OK.
@lawrencecchen
lawrencecchen merged commit 2063c20 into feat-cmux-next Oct 31, 2026
180 of 202 checks passed
@lawrencecchen
lawrencecchen deleted the cp/feat-ratchet-review-rule branch October 31, 2026 00:32
lawrencecchen added a commit that referenced this pull request Oct 31, 2026
… capture backdrop is DEBUG/bench only (#28263)

* fix(design): the capture backdrop panel is DEBUG and bench only, as its only callers are

An independent exception review (reward-hacking audit, arch-ratchet tip rises) found that
CaptureBackdropPattern.swift (8fb4805, #27514) ships its CaptureBackdropPanel, its willClose
observer and NSWindow.setCaptureBackdrop in Release, although its only callers
(DebugWindowSnapshot.captureBackdrop, the debug.capture_backdrop route in AppControl+Input) are
`#if DEBUG || CMUX_BENCH_HOOKS`, and its exception said "DEBUG-only". The panel, its view and the
two NSWindow members that make or read it now sit in the same `#if`; Release keeps the two read
helpers that NSWindow+Snapshot uses, as constants (no backdrop: none to skip, nothing behind).
The pattern enum stays (a value type, no observer). Release behavior: unchanged, since nothing
could make a backdrop there.

* arch-ratchet.json: 12 reviewed exceptions for the tip rises an independent reviewer judged needed; 9 unreviewed pending entries removed

Reward-hacking audit (handoff/followups.md "arch-ratchet tip rises (no exceptions)"). An independent
exception reviewer (it wrote none of the code and none of the old reasons) judged 14 candidates at
2391c5e: 12 EXCEPTION-OK, 2 FIX (AppDelegate.swift:514's quit flush, on fix/arch-rise-quit-flush;
the capture backdrop, gated in 2391c5e and then accepted). The reviewer wrote each entry's
receipt itself; each has author, owner and expiry 2026-11-30, one site per entry (allow 1):
global_mutable_statics PaletteScope lock (#28036), CrashWatcher descriptor (#22844);
stateful_singletons KillSwitches.shared (#24212), BlockingViolationTable.shared (f668c89);
observer_sites DesktopWallpaperWatch :144 :147 :148 :149 (#25308), IPhoneHostService wake (#27297),
DebugWindowRecord willClose (#23680), CaptureBackdropPattern willClose (#27514);
blocking_allow_escapes SingleInstanceGuard (#25918), plus its escape_reviews entry (read by the rule
of #28195).

Removed: the 9 PENDING entries with no review that these replace or that cover no site any more
(CrashWatcher, BlockingViolationTable, DesktopWallpaperWatch +7, SingleInstanceGuard, HomeReduceMotion
(a FIX), kill switches +2, PaletteScope +4 (statics gone) and +1, CaptureBackdropPanel). No applied
entry, total or measured_sha changes; no ratchet number is raised. --update still refuses until the
fix PRs land; it is run after them.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 59dc602c Deployed Oct 30, 2026 by lawrencecchen via cmux-tui tree preflight #81907
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant