Skip to content

docs(backlog): consolidate eight ledger filings into one PR (BACKLOG #1436, #1441, #1444, #1450, #1457, #1458, #1459, #1460, #1461) - #940

Merged
wshallwshall merged 24 commits into
mainfrom
claude/lander-ledger-batch-2
Sep 6, 2026
Merged

docs(backlog): consolidate eight ledger filings into one PR (BACKLOG #1436, #1441, #1444, #1450, #1457, #1458, #1459, #1460, #1461)#940
wshallwshall merged 24 commits into
mainfrom
claude/lander-ledger-batch-2

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Consolidates eight ledger-only pull requests into one, so nine filings cost one merge cycle instead of eight.

Supersedes and closes: #834 (#1436), #838 (#1444), #850 (#1441), #886 (#1450), #903 (#1457), #925 (#1459), #926 (#1458), #936 (#1460, #1461).

Why one PR and not eight

Every merge invalidates every other open pull request, because branch protection is strict. Eight ledger filings that each append to docs/BACKLOG.md are therefore eight serial cycles, and each one re-dirties the other seven. Consolidating removes seven of those cycles. Nothing about the rows themselves changes.

How it was built, and the trap it avoids

Each branch was merged, not cherry-picked, so every number arrives carried by a real merge parent -- which is what the exemption in ledger_check.py grandfathers. Cherry-picking would strip that parentage and the gate would refuse each number as a fresh allocation by a worktree that does not own it.

Each merge re-applies only that branch's own ## N. sections onto the accumulated file. It never takes a branch's whole ledger. That matters: measured before building, all eight branches are stale enough that taking any one wholesale would have silently reverted #1426, #1440, #1454, #1455 and #1456. All five are asserted present below.

This is also the first real exercise of #905. Merge two refused before that landed, with BLOCKED: BACKLOG item #1436 was not allocated to this worktree, because #1436 had arrived from PR 834 onto HEAD and the gate read only MERGE_HEAD. It passes now.

Verification

Run locally before pushing, with all commit hooks active. No --no-verify was used at any point.

Check Result
Files changed docs/BACKLOG.md only
Diff 678 additions, 0 deletions
## N. headings removed 0
Final row count 443 = main's 434 + 9, the target computed before building
Duplicate item numbers none, asserted after every one of the eight merges
#1426, #1440, #1454, #1455, #1456 all present
scripts/docs/backlog_status_check.py OK, 680 items, each declaring exactly one status
scripts/hooks/ledger_check.py --ci exit 0

The one advisory warning is pre-existing: #1426 is open and carries no value or difficulty score. That is advisory by owner ruling (BACKLOG #1455) and never fails the gate.

What a reviewer should check

That the nine rows are the ones the eight superseded pull requests each filed, and nothing else moved. git diff origin/main... on this branch shows additions only.

🤖 Generated with Claude Code

wshallwshall and others added 23 commits September 4, 2026 16:19
…t (BACKLOG #1436)

A Builder reported the leak gate flags any bare six-digit number as a site
code. Measured at 46ea10a: it does not. _ESTATE_ID_SHAPE needs an
underscore-joined identifier and matches 0 of 2,038 tracked files;
_SITE_CODE_FILE fires only when the leading digits match a loaded
[site_prefix], of which two load. The gate as configured flags 0 lines of
the tracked tree.

Four narrowings were tested against 12 realistic site codes built on the
shipped synthetic prefix. All four miss at least one; the underscore anchor
misses 8 and only re-derives a detector that already ships.

Verdict: change no detector. Scope left open is one paragraph in
CONTRIBUTING.md correcting the mental model.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…(BACKLOG #1444)

A scoring pass is a SNAPSHOT. Nothing in CI requires a value or difficulty
at filing time, so the gap re-opens as fast as items are filed.

Measured 2026-09-04 against main at 685d4f5: 278 open items, 5 with no
score -- #1424, #1427, #1429, #1430, #1439 -- every one filed 2026-09-03.
PR 754 closed this to zero on 2026-09-03, so the gap went 0 to 5 in about
a day. Re-measured here with parse_items rather than a hand-rolled scan,
against the reporting seat's figures; both the count and the exact five
item numbers agreed.

Filed as a DECISION rather than a defect. The items are correct: #1427's
own banner states that value and difficulty belong to a scoring pass. So
moving the gate to filing time needs a ruling before it needs code, and
would red on the five existing items on day one -- unshippable without a
grandfather baseline, the same shape as #1435. Re-running the pass keeps
the convention but is unbounded work with no set cadence.

Scoring the current five would not settle it. That is another snapshot,
and it decays the same way.

The item carries its own score, so it is not an instance of itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e CLI subcommands

logging.lastResort carries filters=[] and formatter=None. Two of the CLI's 32
subcommands install a root handler (serve, supervise); the other 30 run with an
empty root handler list, so their WARNING+ records reach stderr through
lastResort and bypass the three filters _install_phi_filters puts on every
configured handler.

Measured with paired controls: a real `messagefoundry backup` run holds
root.handlers == [] throughout and loads 18 WARNING+ traceback sites; the same
record with configure_logging first comes out PID|[redacted].

Measured at 46ea10a and re-verified at a2eef0f, because main moved 58
commits in between and both measured files changed. The counts are unchanged.
#1199's fix landed as 99887f5 (PR 820) in that window; it is per-logger, never
appears in __main__.py, and does not close this gap.

Files the item only. No fix: the item weighs both candidate remedies and records
that remedy (1) empties caplog for the 6 test files that use it, of 40 asserting
on captured CLI output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rom the file it guards (BACKLOG #1450)

The detector exists. scripts/ci/check_required_contexts_drift.py reads the
public branches endpoint and set-compares it to the checked-in file, as the
job `the required-contexts file matches the server`. Neither
.github/required-contexts.txt nor tests/test_required_contexts.py names it,
so two readers in one night read those files and concluded the drift was
undetectable. One of them briefed this item as a structural impossibility.

Measured 2026-09-04, each reading with a positive control: server 13
contexts on both endpoints, file 14, pin 14. The drift job carries no
continue-on-error, is not a required context, and is paths-filtered on
pull_request, so a server-side change reaches only its 07:00 UTC cron on
main, which notifies nobody.

Recommends AGAINST a live-API arm in the pytest suite: that suite sits
inside a required leg and runs offline and on fork PRs, so a fail-closed
network call there would red every PR on an API blip. The gap is routing,
not detection.

The reconciliation itself is PR 884; this Builder stood down on it after the
collision registry flagged the overlap. No file in that diff is touched
here. The one thing 884 leaves stale is named in the item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…main stale (BACKLOG #1450)

The item said the guard's paths-filtered pull_request trigger means it
does not run on an ordinary PR, so a server-side change is invisible to
every merge path. The first half is right and the conclusion is wrong.

A PR that touches those paths DOES fire it. Measured on PR 884: run
created 2026-09-04T23:55:21Z, event=pull_request.

What actually stops it reporting the drift is the checkout. The job runs
actions/checkout with no ref:, so on a pull_request event it reads the
file as that PR has it and compares against the live server. 884 compares
13 against 13 and passes. The run validates a fix; it cannot report that
main is stale.

"No pull request triggers it" is falsifiable and false. "No pull-request
run can see the drift on main" is true and stronger.

Caught by the Lander on review of the ledger entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolved by the Lander. One hunk, and it is the ledger tail serialising:
this branch appends #1436, main appended #1434. Different items, so both
sides stand. Main's block keeps the position it holds on main and #1436
follows it, which leaves the next merge of this file less to reconcile.

Set-difference control over item numbers: nothing lost, nothing invented,
430 = main's 429 plus #1436. #1069 is absent because main archived it at
7f97202. Three items whose status differs from this branch (#1389,
#1392, #1439) follow main; this branch's own diff touches none of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolved by the Lander. The ledger tail serialising: this branch appends
its item, main appended another. Different items, so both sides stand,
with main's block in the position it holds on main.

Set-difference control over item numbers: nothing lost, nothing invented,
no duplicate headings. #1069 is absent because main archived it at
7f97202, not because this merge dropped it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolved by the Lander. The ledger tail serialising: this branch appends
its item, main appended another. Different items, so both sides stand,
with main's block in the position it holds on main.

Set-difference control over item numbers: nothing lost, nothing invented,
no duplicate headings. #1069 is absent because main archived it at
7f97202, not because this merge dropped it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolved by the Lander. The ledger tail serialising: this branch appends
its item, main appended another. Different items, so both sides stand,
with main's block in the position it holds on main.

Set-difference control over item numbers: nothing lost, nothing invented,
no duplicate headings. #1069 is absent because main archived it at
7f97202, not because this merge dropped it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…G #1457)

Dependabot #891 bumped zizmor 1.29.0 to 1.30.0. That release added the
`self-repository` audit, which fires one LOW on cla.yml:102 and exits 12.

The gate ran on the bump PR and was merged past. Run 33945900593 reported
`1 low, 0 medium, 0 high` and exit code 12 at 04:57:02Z; #891 merged at
21:02:26Z. Not a bypass: zizmor is not among the thirteen required
contexts, auto-merge was null, and nobody was obliged to stop.

Measured on main's own inputs rather than on main: PR 901's zizmor run
executed main's pinned 1.30.0 against main's cla.yml blob, which is
byte-identical across both, and reported the same finding. Main's last
zizmor run predates the bump, so its next scheduled run is the reading
that closes the loop.

The item deliberately does not name a fix. zizmor's suggested `$/` syntax
was not verified against GitHub's documentation, and cla.yml carries a
required context on a pull_request_target workflow that the PR changing it
cannot test -- the deadlock PR 621 already paid for once.

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

Value 4, difficulty 3, fill-in, P3, verdict build. Scored at filing.

scripts/hooks/usage-headroom-inject.ps1:224 reads latest.json out of the
state directory, and that file exists on NONE of the six config roots on
this machine, so the injection resolves to "UNKNOWN -- no data" on every
spawn it fires for. Observed six times in one session, on every Workflow
launch.

MEASURED WITH A POSITIVE CONTROL, because an absence needs one. A find
for latest.json across every root returns zero; the same sweep for
status.json returns three. So the search works and the absence is real
rather than a broken pattern. The hook's own header at :10 says the
collector IS a statusLine that writes that file, so it appears only where
that statusLine runs, and on this machine that is nowhere.

VALUE 4 AND NOT 6, which is the judgment in this row. The band-6 shape
here is an instrument whose silence looks like success. This one is the
opposite and says so in its own output: "UNKNOWN is not zero headroom and
it is not full headroom. It is no measurement." An instrument that
announces its own blindness is degraded, not deceptive. The row argues
that down explicitly and invites the counter-argument rather than
asserting the band.

IT IS ONE HALF OF A PAIR. #1406 records that the hook never fires on the
path that spends most -- a Console spawns a Builder through a
Bash(claude:*) grant, which no tool-name matcher can select, and
test_claude_settings_contract.py asserts no matcher wiring this hook may
select it. So #1406 is "does not fire where it matters most" and this row
is "where it does fire, it has nothing to read". Fixing either alone
leaves the instrument useless, and neither should be closed on the
strength of the other. Both statements are in the row.

Number allocated with scripts/coord/alloc.ps1 from this worktree, never
picked by reading the file. Appended at the tail, so it conflicts with
other ledger work only as an append.

Verified: backlog_status_check green (671 items, one status each), the
row parses open with all three banner fields and no duplicate, and the
status, citation and ledger test legs pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lity contradicts ADR 0052 AC-2

At [sandbox].mode=subprocess the engine holds one persistent worker tree per
traffic-carrying inbound: spawned lazily, never evicted, with no pool and no
cap. Per connection that is a process tree, two daemon threads, three pipe fds
and a Windows job-object handle -- the resource class AC-2 names, needing no
multiplication to see.

It also records why the 74 GiB total is retracted: the multiplier counts
connections rather than inbounds, linearity was never measured (all five result
JSONs record one worker tree), and resident set is bounded by installed RAM.
The per-worker figures stand; the scaled framing did not.

Scored 6/10 value, 7/10 difficulty, big bet, P2, verdict research -- two
candidate shapes, and the row deliberately chooses neither.

#1278's block is left untouched: PR 879 is rewriting it.

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

Two constants carry stale seat assignments, and neither is fixed here.
CLOSING_SEAT at scripts/docs/backlog_status_check.py:122 names the ASVS
Tracker, the Liaison and the Dispatcher. GATED_VERDICTS at
scripts/coord/dispatch_gate.py:160 independently names two of them, so
correcting one constant leaves the other emitting. Measured over 670
ledger rows, 132 get a dispatch reason naming a retired seat.

A fourth value is a wrong assignment rather than a dangling name:
CLOSING_SEAT["code"] tells a Builder the Lander flips the banner, while
backlog-hygiene.yml demands the ledger edit of that Builder's own PR.

#1461 is the vault half. Three role playbooks hold the same old
assignment, including BUILDER.md:216 forbidding the Builder the edit
CLAUDE.md:286 assigns it. That is a write outside this repository, so
the Lander performs it and needs no owner approval.

Filed, not fixed. The 97-row scorecard-rescore value needs PR 929 on
main first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1436)

Merge of PR 834 into the Lander batch. Rows are re-applied onto main's
current file rather than taking the branch's whole ledger, which is
eight commits stale and would silently revert #1426, #1440, #1454,
#1455 and #1456.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1444)

Merge of PR 838. #1436 now sits on HEAD from the previous merge, which is
the case PR 905 added to the ledger gate: a merge commit has two parents
and the gate read only MERGE_HEAD.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1441)

Merge of PR 850. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1450)

Merge of PR 886. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1457)

Merge of PR 903. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1459)

Merge of PR 925. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1458)

Merge of PR 926. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…#1460)

Merge of PR 936. Rows re-applied onto the accumulated file, never the
branch's whole ledger.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@wshallwshall
wshallwshall added this pull request to the merge queue Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

@wshallwshall

This pull request is green and nobody has marked it read.

Every check that has reported is passing and the reviewed label is absent, so
a reviewer has read this is the only thing between it and a merge. Nothing else reports that, which is
why this comment exists (BACKLOG #1413).

To clear it, IN THIS ORDER:

  1. If the branch is behind main, update it FIRST: gh pr update-branch --repo MEFORORG/MessageFoundry 940.
    That push fires synchronize, and synchronize REMOVES the reviewed label. Labelling
    before updating throws the label away and costs a round trip.
  2. Read the diff.
  3. gh pr edit 940 --repo MEFORORG/MessageFoundry --add-label reviewed

DO NOT TRIAGE THIS FROM mergeStateStatus. It returns one value with precedence, so BEHIND,
DIRTY and UNSTABLE each mask the missing check -- the requirement is invisible until you act on
something else. This check never reads that field; see scripts/ci/check_unread_prs.py.

A seat can find every pull request in this state in one call: gh pr list --label unread.
The label is withdrawn automatically once this pull request leaves the state.

The reviewed label is a PROCESS gate. It records that a step happened. It does not
establish that an independent party looked, and nothing here should be read as saying it does.

@github-actions github-actions Bot added the unread Green and mergeable, but not marked read. Read it, then add: reviewed label Sep 6, 2026
Merged via the queue into main with commit 89b2574 Sep 6, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

unread Green and mergeable, but not marked read. Read it, then add: reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant