From 826c3188cec8d8a4c50bd3bb56e10d0fce0b2957 Mon Sep 17 00:00:00 2001 From: Jonathan Borduas Date: Sun, 23 Aug 2026 15:06:02 +0100 Subject: [PATCH 1/2] tools: completedAt cannot say WHICH CODE RAN -- the counter-case to the entry directly above it The check-freshness.py entry names three quantities that all sound like "is this PR current" -- head commit date, merge-base distance, and the check's completedAt -- and concludes "only the third mattered." That is true of the question it asks. It is false of a question that sounds identical at the call site, and the entry currently points a reader at completedAt with nothing saying where it stops. Measured by TEAMLEAD on #570, in their own merge guard, and re-verified here at origin/main before landing: gate changed 2fa1a3b 2026-08-22T01:30:03Z check finished 2026-08-22T01:33:26Z 3m23s later, so the clock says PASS git merge-base --is-ancestor 2fa1a3b FALSE The check finished three minutes after the new gate landed and ran the old gate anyway. Class C in a guard: the proposition needed was "did it execute this code", the proposition measured was "did it finish after this code was committed." Both are about the gate and about time, and only one is answerable by a timestamp. A second trap sits on top of the first. git log --format=%cI prints LOCAL time (02:30:03+01:00 on this machine) and the GitHub API prints UTC (01:33:26Z). Comparing them unnormalised is a one-hour error in whichever direction the operator happens to sit, so the wrong question also gets a wrong answer. The remedy is TEAMLEAD's and involves no clock: merge-tree --write-tree, commit-tree, worktree add --detach, run the CURRENT gate against the actual merge result -- with a control that the new leg is present in that tree, because running a new gate against a tree that lacks it prints a clean pass, and a clean pass is what you are looking for. Why it never looked wrong: the gate rarely changes and the queue is usually drained between changes, so timestamp and ancestry agree almost always. A guard that is right by coincidence of scheduling is indistinguishable from one that is right by construction, until the two propositions come apart once. Both asserted facts re-verified at origin/main today, not carried from the measurement two days ago. Gates: check-orientation 0, check-goal-conformance 0, check-tools-index 0, gate-selftests 0. Filed by ARCHITECT, session c83ecf77. Measurement and remedy are TEAMLEAD's. Refs #570. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01RTX4A8KkC9cRRrt17yzjWQ --- tools/README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tools/README.md b/tools/README.md index 86c8737..00fef54 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1136,6 +1136,38 @@ which is #345's *noun with no shared definition* one layer down, and the mismatc **`check-freshness.py`** — ⛔ **a red check is evidence about the MOMENT IT RAN, not about now.** Measured 2026-08-20 on 56 open PRs: **65 failing required checks, 54 of them completed BEFORE the resource they depend on recovered** — **83% of the board's red was a measurement taken under conditions that no longer held**, and the fleet spent hours treating it as 49 defects. ★ **Base freshness does not detect this**: PRs zero commits behind main failed required checks at **88%**, stale ones at **86%** — indistinguishable. A PR can sit exactly on main's tip while its checks are four hours old. ⇒ Three quantities that all sound like *"is this PR current"* — the **head commit date**, the **merge-base distance**, and the **check's `completedAt`** — and only the third mattered. ⚠ `--since` is **required and never defaulted**: only the caller knows when the condition changed, and a default would manufacture a verdict from an arbitrary clock. ⛔ A `STALE` verdict does **not** mean the PR passes — it means the evidence predates the change and cannot speak to now; **re-running produces evidence, reading does not.** ⚠ And `UNDATED` is **not** old: a check with no completion time has not been dated, and bucketing it as stale would quietly enlarge the safe-to-ignore pile. +⛔ **AND THE COUNTER-CASE, BECAUSE THE ENTRY ABOVE POINTS A READER AT `completedAt` AND THERE IS A +QUESTION IT CANNOT ANSWER.** ★ *"Only the third mattered"* is true of **is this evidence current**. It +is false of **did this check EXECUTE the current gate** — and the two sound identical at the call +site. ⚠ **Measured 2026-08-22 on `#570`, by TEAMLEAD, in their own merge guard:** + +``` +gate changed 2fa1a3b 2026-08-22T01:30:03Z +check finished 2026-08-22T01:33:26Z ⇒ 3m23s LATER, so the clock says PASS +git merge-base --is-ancestor 2fa1a3b ⇒ FALSE + ⇒ the gate change was NOT in the tested tree +``` + +⇒ ⛔ **The check finished three minutes after the new gate landed and ran the OLD gate anyway.** +★ **Class C in a guard: the proposition needed was *did it execute this code*, the proposition +measured was *did it finish after this code was committed*. Both are about the gate and about time, +and only one is answerable by a timestamp.** + +⚠⚠ **A SECOND TRAP SITS ON TOP OF THE FIRST, and it is why the wrong question also gets a wrong +answer:** `git log --format=%cI` prints **LOCAL** time (`02:30:03+01:00` here) and the GitHub API +prints **UTC** (`01:33:26Z`). ⇒ **Comparing them unnormalised is a one-hour error in whichever +direction the operator happens to sit.** + +★ **The remedy is TEAMLEAD's and it does not involve a clock:** `git merge-tree --write-tree` → +`commit-tree` → `worktree add --detach` → **run the CURRENT gate against the actual merge result** — +with a control that the new leg is *present* in that tree (`grep -c` ⇒ 2), **because running a new +gate against a tree that lacks it prints a clean pass, and a clean pass is what you are looking for.** + +⛔ **Why it never looked wrong: the gate rarely changes and the queue is usually drained between +changes, so the timestamp and the ancestry AGREE almost always.** ★ **A guard that is right by +coincidence of scheduling is indistinguishable from one that is right by construction — until the two +propositions come apart once.** *(#570; the same instrument refuted the two-dot guard 5 the same day.)* + ⛔ **AND EVERY `first:N` WINDOW IS A SILENT TRUNCATION UNTIL COMPARED TO `totalCount`.** Both windows in its query were unchecked. Measured 2026-08-21 on Blazing-Back: `branchProtectionRules` **totalCount 1** (window 5) and `contexts` **totalCount 56–57** (window 100). ⇒ Neither bound, so nothing was wrong — **but 57 of 100 is not margin**, and nothing would have said so when it did. `totalCount` sits in the *same response* as the `nodes` window, which makes not reading it inexcusable rather than merely unlucky. ★★ **The two truncations are not the same severity and are handled differently on purpose:** a dropped **protection rule** decides *which contexts are required*, so it does not shrink the answer — **it redefines the question**, and the output looks identical ⇒ **fatal, exit 2**. A dropped **context** loses rows from one PR ⇒ named, and every count becomes a **lower bound**. ⚠ Pinned behaviourally by exit code, not by source text — the first version of those checks asserted strings in the file and **would have passed against a comment**. **`established.py`** — ⛔ **four instruments needed this in one day**, each rediscovering it and each shipping without it first: **0 API calls** read as restraint (the meter was *exhausted*), **0 current red checks** read as a clean board (*nothing had re-run*), **0 untouched issues** read as full coverage (*the query failed*), **0 conflicts** read as no collisions (*the heads were never fetched*). ★ **The shape, once instead of four times: an observation is `OUTCOME ∧ EXECUTION`**, and when the execution did not happen the outcome is not a reading — **the number looks identical in both cases.** ⚠ **And every one fails toward reassurance**, which is why it has to be structural rather than remembered: nobody double-checks a clean result, and that is exactly when it fires. ⇒ A refusal is **falsy but not `None` and not `== 0`**, so `if result:` skips it and `is None` / `== 0` do not silently absorb it. ⚠ **A stated limit, pinned in the suite rather than discovered later:** `or 0` still defeats it — falsiness is exactly what makes `if` safe and `or` unsafe, and no value is both. Use `isinstance(x, NotEstablished)`. ⛔ And the witness must be about the **execution**, never the value: `established(0, count == 0, …)` is always-true nonsense, kept as a known-bad control because it cannot be detected at runtime. From c84da3eaf94db91e86ebab1425baf32d0ad9bc00 Mon Sep 17 00:00:00 2001 From: Jonathan Borduas Date: Sun, 23 Aug 2026 15:15:09 +0100 Subject: [PATCH 2/2] fix: %cI is immune to TZ -- the skew belongs to the COMMIT, not the reader Two corrections from TEAMLEAD's review, both verified here by running them rather than by reading the review. The entry said comparing %cI against the API's Z was "a one-hour error in whichever direction the operator happens to sit." False. %cI prints the offset STORED IN THE COMMIT -- the committer's zone at commit time -- and does not follow the reader: TZ=UTC %cI 2026-08-22T02:30:03+01:00 TZ=Asia/Tokyo %cI 2026-08-22T02:30:03+01:00 unchanged TZ=America/Los_Angeles %cI 2026-08-22T02:30:03+01:00 unchanged TZ=Asia/Tokyo %cd --date=local Sat Aug 22 10:30:03 2026 this moves A Tokyo-authored commit carries +09:00 and a reader in UTC mis-compares by nine hours without leaving UTC. The skew belongs to the commit. That is this entry's own thesis one level down. Nine panes on one machine means committer-zone and operator-zone are always equal here, so the wrong explanation produced right answers every time. Right by coincidence of topology. Found by TEAMLEAD by varying TZ -- the control the first version did not run. The normalising form is now given with the reason it works: format-local DOES honour TZ, the opposite property from %cI. And a warning I am adding on top: its trailing Z is a literal, not a computed zone, so dropping the TZ=UTC prefix under Asia/Tokyo prints 2026-08-22T10:30:03Z -- well-formed, confidently wrong, and it compares cleanly against anything. The TZ=UTC is load-bearing. Second: the published control used `grep -c => 2`, reading stdout. grep -c has three outcomes and only two are distinguishable that way: match stdout="1" rc=0, no match stdout="0" rc=1, unreadable stdout="" rc=2. A presence control reading stdout cannot tell ABSENT from UNREADABLE, and a missing file is exactly the state a freshly-constructed worktree can be in. Now says read the exit code and treat rc=2 as VOID. TEAMLEAD raised this against their own published control. Also added, for anyone re-running the measurement: merge-base no longer denotes what it did when this was measured. Before #570 merged it was e66aeb4, a fork point; now it is 894869b, which IS the head, because once a PR lands its head is an ancestor of main and merge-base collapses onto it. The verdict is FALSE either way, so the command still agrees -- and agreement from a command now answering a different question is not confirmation. MD040 declined again, on controls re-run today rather than carried from #568: no markdownlint or MD040 config anywhere at origin/main, and tools/README.md has 28 bare fences to 0 tagged, so tagging one makes it uniquely inconsistent. Gates: check-orientation 0, check-goal-conformance 0, check-tools-index 0, gate-selftests 0. Filed by ARCHITECT, session c83ecf77. Both corrections TEAMLEAD's. Refs #574, #570. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01RTX4A8KkC9cRRrt17yzjWQ --- tools/README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/tools/README.md b/tools/README.md index 00fef54..205ac7a 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1154,14 +1154,64 @@ measured was *did it finish after this code was committed*. Both are about the g and only one is answerable by a timestamp.** ⚠⚠ **A SECOND TRAP SITS ON TOP OF THE FIRST, and it is why the wrong question also gets a wrong -answer:** `git log --format=%cI` prints **LOCAL** time (`02:30:03+01:00` here) and the GitHub API -prints **UTC** (`01:33:26Z`). ⇒ **Comparing them unnormalised is a one-hour error in whichever -direction the operator happens to sit.** +answer:** `git log --format=%cI` prints `02:30:03+01:00` and the GitHub API prints `01:33:26Z`. +⛔ **Comparing them unnormalised is a one-hour error HERE, and an arbitrary one elsewhere.** + +⛔ **AND NOT FOR THE REASON THIS ENTRY FIRST GAVE.** ★ **`%cI` is IMMUNE to `TZ`. It prints the +offset STORED IN THE COMMIT — the committer's zone at commit time — so it does not follow the +reader at all:** + +``` +TZ=UTC %cI ⇒ 2026-08-22T02:30:03+01:00 +TZ=Asia/Tokyo %cI ⇒ 2026-08-22T02:30:03+01:00 UNCHANGED +TZ=America/Los_Angeles %cI ⇒ 2026-08-22T02:30:03+01:00 UNCHANGED +TZ=Asia/Tokyo %cd --date=local ⇒ Sat Aug 22 10:30:03 2026 THIS one moves +``` + +⇒ ⛔ **So "an error in whichever direction the OPERATOR sits" is false — the operator does not enter +into it.** ★ **A Tokyo-authored commit carries `+09:00`, and a reader sitting in UTC mis-compares by +nine hours WITHOUT LEAVING UTC.** ⚠ **The skew belongs to the COMMIT, not to the reader.** + +★★ **This entry's own thesis, one level down: nine panes on one machine means committer-zone and +operator-zone are always equal here, so the wrong explanation produced right answers every time.** +⛔ **Right by coincidence of TOPOLOGY.** *(Found by TEAMLEAD on this entry, 2026-08-23, by varying +`TZ` — the control the first version did not run.)* + +**The normalising form, and why it works:** + +``` +TZ=UTC git log -1 --format=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ 2fa1a3b + ⇒ 2026-08-22T01:30:03Z +``` + +⚠ **`format-local` DOES honour `TZ` — the opposite property from `%cI`, which is the whole reason it +works.** ⛔ **And the trailing `Z` is a LITERAL, not a computed zone: drop the `TZ=UTC` prefix under +`Asia/Tokyo` and it prints `2026-08-22T10:30:03Z`** — well-formed, confidently wrong, and it will +compare cleanly against anything. ★ **The `TZ=UTC` is load-bearing, not decoration.** ★ **The remedy is TEAMLEAD's and it does not involve a clock:** `git merge-tree --write-tree` → `commit-tree` → `worktree add --detach` → **run the CURRENT gate against the actual merge result** — -with a control that the new leg is *present* in that tree (`grep -c` ⇒ 2), **because running a new -gate against a tree that lacks it prints a clean pass, and a clean pass is what you are looking for.** +with a control that the new leg is *present* in that tree, **because running a new gate against a +tree that lacks it prints a clean pass, and a clean pass is what you are looking for.** + +⚠ **Read that control's EXIT CODE, not its stdout.** ⛔ **`grep -c` has THREE outcomes and only two +are distinguishable on stdout:** + +``` +match stdout="1" rc=0 +no match stdout="0" rc=1 +unreadable stdout="" rc=2 ⇐ and "" is not 0, but `n=$(grep -c …)` swallows it either way +``` + +⇒ ★ **A presence control reading only stdout cannot tell ABSENT from UNREADABLE**, and a missing +file is exactly the state a freshly-constructed worktree can be in. **Use `grep -c … ; rc=$?` and +treat `rc=2` as VOID.** *(TEAMLEAD, against their own published control.)* + +⚠ **REPRODUCING THE MEASUREMENT ABOVE AFTER #570 MERGED: `merge-base` no longer denotes what it did.** +Before the merge it was `e66aeb4`, a fork point; now it is `894869b`, **which IS the head** — once a +PR lands, its head is an ancestor of `main` and the merge-base collapses onto it. ⛔ **The verdict is +`FALSE` either way, so the command still agrees** — ★ **and agreement from a command that is now +answering a different question is not confirmation.** ⛔ **Why it never looked wrong: the gate rarely changes and the queue is usually drained between changes, so the timestamp and the ancestry AGREE almost always.** ★ **A guard that is right by