fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633) - #12643

Merged
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew
Aug 27, 2026
Merged

fix(pm): window the governed-merge sweep on landing order, not committer dates (#12633)#12643
os-litant merged 2 commits into
mainfrom
claude/issue-12633-governed-merges-since-skew

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12633

The merge queue writes a batch entry's commit when the batch is built, and main receives it when the batch lands. Those are not the same moment, so a governed landing can sit above another commit on main's first-parent chain — it landed later — while carrying an earlier committer date. git log --since=DATE cuts on committer date, so at a knife-edge boundary that landing is simply absent, with nothing in the output marking the gap; where it is the only governed landing in the window, the sweep prints ✅ clean window and exits 0 = "swept COMPLETELY", the one reading #4690 and #9902 say must never be producible.

Implements the route ruled on the card — B for --since-ref, A for --since. C (detect and refuse) and D (document) stay declined. The audit's report-only posture is unchanged, no judgment is weakened, and every pre-existing --self-test assertion is kept verbatim.

What changed — one file, scripts/pm/check-governed-merges.mjs

  1. --since-ref is topological. The window is the first-parent range from the ref to origin/main; committer dates are not consulted at all, so no skew of any size can move the boundary. Multi-repo: a bare --since-ref is tried in every governed repo and used wherever it resolves, and --since-ref repoId=REF pins one repo (repeatable). A repo no ref resolves in falls back to the date window and its report line says so — one repo's ref silently dating four repos' windows is the same class of bug as the one being fixed. Recording the previous round's tip is the caller's obligation (this script keeps no state), so the PM assumption on the card is discharged by printing the line to use next round on every sweep: next round, exactly: --since-ref objectstack=SHA --since-ref objectui=SHA …. Bonus: for a topological window the Three seat-run tools ask windowed history questions with no shallow guard, so each answers plausibly and wrongly in an agent container #9902 horizon question answers itself — the ref being present in a checkout is necessary and sufficient for the range to be complete.
  2. A bare --since is backed off by a declared budget, SKEW_BUDGET_SECONDS = 3600, and the report line states both boundaries and the back-off out loud, so a re-listed boundary entry reads as re-recognition rather than noise.
  3. The date window is closed topologically, and refuses to read clean when it cannot prove it. The emitted set is every first-parent commit at or above the deepest commit dated inside the budgeted window — a chain prefix, so nothing is ever dropped for being dated below something that landed before it, whatever the budget is. The proof obligation is the other half: the walk must actually see a commit dated below the boundary, or that deepest commit cannot be shown to be the deepest one. When it cannot, the repo is WINDOW EDGE, the green tick is suppressed and the sweep exits 2.

Part 3 is an addition to the ruled route A, not a substitute for it, and it is why the card's invariant now holds mechanically rather than up to a constant: a governed entry at a skew boundary is either listed, or the sweep is INCOMPLETE — never clean-and-absent.

Why 3600 s, and why not 874 s

readingmeasurementsource
largest build-to-land skew1,939 s (PR #12443: committed 2026-08-26T05:00:49Z, merged 05:33:08Z)card, two governed PRs of one batch
second of the same batch1,495 s (PR #12440)card
largest committer-date inversion on this mainline874 s, 10 inversions in 3,613 first-parent pairs, median 539 sre-measured on this tree 2026-08-27, git log --first-parent origin/main

The re-measurement reproduces the card exactly (10 / max 874 s / median 539 s; one extra pair because main advanced), and two of the ten inverted commits touch a governed surface. 3600 s is 1.86× the largest directly measured skew and 4.1× the largest inversion. It is deliberately not set to the measured maximum: a bound written exactly at today's worst case invalidates itself the first time a slower batch lands — the same trap as an upper bound pinned at the version that fixes it. The cost is re-listing whatever landed in the hour before the boundary; on the documented default (--since 24h) that widens the window by 4.2%, and consecutive default rounds already overlap by nearly a full day.

Before / after

Real history, the card's own probe (enumeration only — the sweep minus its attribution round-trips, which are one GET per entry and have nothing to do with the window):

BEFORE (origin/main)
--since 2026-08-14T05:55:02Z scanned=1720 governed_entries=190 01a7337fc0 listed? false
--since 2026-08-14T05:44:52Z scanned=1722 governed_entries=191 01a7337fc0 listed? true
AFTER (this branch)
--since 2026-08-14T05:55:02Z scanned=1726 governed_entries=193 01a7337fc0 listed? true
-> 01a7337fc0 PR #8620 surfaces: docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md
--since 2026-08-14T05:44:52Z scanned=1726 governed_entries=193 01a7337fc0 listed? true

The two boundaries that used to disagree by one governed ADR now return the identical list. The 190 → 193 growth is the hour of back-off plus the topological close, i.e. the re-listings named in the report line.

End to end, real exit codes, on a constructed QS-7 repo (a queue chain whose governed entry landed above the round tip while dated 874 s — the measured maximum — before it; subjects carry no PR number on purpose, so the run costs zero API lookups and the exit code under test is the window's). The BEFORE column is the pristine origin/main copy of the script run against the same repo:

BEFORE --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 0 governed merge(s) …
✓ audited objectstack-ai/objectstack — … 0 mainline commit(s) in window; history complete clone
✅ clean window — no governed surface was merged in any governed repo.
AFTER --since 2026-08-14T05:55:02Z exit 0
governed-merges sweep: 1 governed merge(s) …
window: DATE boundary 2026-08-14T05:55:02.000Z, backed off by the 3600 s build-to-land
skew budget to 2026-08-14T04:55:02.000Z, then closed topologically down to the deepest commit
inside it (#12633). An entry you recognised last round may be RE-LISTED at the boundary —
that is RE-RECOGNITION, not noise; a dropped entry is never seen again.
• objectstack-ai/objectstack … docs(adr): kernel object ownership
surfaces: docs/adr/** ×1
- docs/adr/0029-kernel-object-ownership.md
AFTER --since-ref ROUND_TIP (route B) exit 0
window: TOPOLOGICAL — the first-parent range from the ref to origin/main, per repo (…).
Committer dates are not consulted, so no build-to-land skew of any size can move this boundary.
✓ audited … 1 mainline commit(s) in window; window topological from d865aeeef
• objectstack-ai/objectstack … docs(adr): kernel object ownership

The multi-repo half of route B, a ref that resolves in objectstack but not in the swept sibling — it falls back, names why, and still lists the governed entry:

 ✓ audited objectstack-ai/objectui — … window date (fell back — '98eec7e24…' does not resolve
in this checkout); history complete clone

Verification

Union re-run after the final commit, on fdff4bad1, one && chain under scripts/pm/os-verify-lock.sh so the verdict certifies all of it:

os-verify-lock: VERDICT command-exit 0 · held the lock 146s (2m26s) · waited 0s

covering check:pm-governed-merges, check:pm-governed-prose, check:pm-dispatch-gates, bare-root-worklist --self-test, check-governed-queue-guard --self-test, ci-failure --self-test, check:nul-bytes, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:pnpm-filter-targets, check-ci-filter-parity, check-skills-token-ratchet, and whole-repo pnpm lint (no narrowing — eslint . --no-inline-config, 65 s). The gate family was derived from the diff by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, plus the two convention-triggered obligations it names for a gate-script edit, plus the three sibling scripts that import this module (check-governed-queue-guard, ci-failure, check-skills-token-ratchet) — an import is not a path literal, so the derivation cannot name them.

✓ check-governed-merges --self-test: 193 assertions

Baseline on this tree was 159, not the 157 the card recorded — main moved between the measurement and the dispatch; no pre-existing assertion was removed or weakened, and 34 were added. The new ones pin the QS-7 shape in both directions (the old bare cut drops the entry as a control; the budgeted window lists it), the topological close carrying an entry skewed past the budget, the unproven-boundary EDGE, the listed-or-INCOMPLETE invariant as a property over every fixture, the escalating floors (one walk in the ordinary case), per-repo --since-ref resolution with its named fallback, and the window words an operator actually reads.

Notes


Generated by Claude Code

…ter dates (#12633)
The merge queue writes a batch entry's commit when the batch is BUILT and main
receives it when the batch LANDS, so a governed landing can sit above another
commit on the first-parent chain while carrying an earlier committer date. A
knife-edge --since boundary then drops it with nothing marking the gap, and the
sweep prints a clean window at exit 0 — the one reading #4690 and #9902 forbid.
--since-ref is now TOPOLOGICAL (REF..origin/main, per repo, repeatable as
<repoId>=<ref>); a bare --since is backed off by a declared 3600 s skew budget
and the report line says so; and the date window is closed topologically down
to the deepest commit inside it, refusing to read clean when the walk never
reached below the boundary.
@os-litantos-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 03:03
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit fb5a669Aug 27, 2026
34 checks passed
@os-litant
os-litant deleted the claude/issue-12633-governed-merges-since-skew branch August 27, 2026 03:22
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/lskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant

@os-litant