fix(hooks): now-gate matched a bold NOW stamp nothing writes; correct the symlink comment; drop 835 lines of base64 - #2300
Merged
Conversation
Three uncontested defects, each verified against origin/master at 7e8de87 before being touched. 1. `tri hooks now-gate` matched `^\*\*Last updated:\*\*` (bold), but the producer `cli/tri/src/nownote.rs` writes the plain form, and master's `docs/NOW.md` has 0 bold stamps against 136 plain. The gate always took its `None` branch and bailed on the only document it exists to check. The pattern now accepts either form. Both existing tests wrote their own bold fixture and asserted the regex read it back, so the producer/consumer split was invisible to them. Added one test pinning the plain shape `nownote.rs` emits, and one running the gate against the real `docs/NOW.md` with the expected date re-derived by the live gate's own rule -- an agreement check, not a freshness check. Note: nothing invokes `tri hooks now-gate` or `tri hooks pre-commit` today. The gate that runs is `scripts/tri check-now` -> `t27c check-now` in `bootstrap/src/suite.rs`, which uses `contains("Last updated:")` and accepts plain. So this is dead code, not a live block -- but `MIGRATION_AUDIT.md` advertises `tri hooks` as the replacement port, and it would reject every commit the moment it is wired up. 2. `.gitattributes` said root `NOW.md` "is a symlink". `git ls-tree` reports mode 100644 -- a regular file (a symlink is 120000). It is a divergent document stamped 2026-08-09. A second claim was backwards: the pattern `NOW.md` has no slash, so git matches it by basename at any depth and it already covers `docs/NOW.md`. Comments corrected; the `merge=union` rules are unchanged and `git check-attr merge` returns `union` for the same paths before and after. Whether root `NOW.md` should be a symlink, be deleted, or keep its content is left open -- see #2253. 3. `docs/NOW.md.master` was 835 lines of committed base64 from d063152. It decodes to 35,328 bytes of an obsolete NOW snapshot stamped 2026-04-08, and `git grep "NOW\.md\.master"` finds zero references tree-wide. Unreadable in review, ungreppable, undiffable. Removed. The 137 figure in the brief did not survive checking: master has 136 `Last updated:` stamps across 74 `^# NOW --` headers. The NOW entry is a pure prepend -- `git diff --numstat` reports 86 added, 0 deleted. Not verified: this crate was not compiled. Building it needs cargo, which was out of scope for this change, so the Rust edits are reviewed by reading only. Closes #2299
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
gHashTag
enabled auto-merge (squash)
August 20, 2026 05:43
gHashTag
pushed a commit
that referenced
this pull request
Aug 20, 2026
Entries were prepended to the single file docs/NOW.md, so every PR rewrote its first line and all 18 open PRs are marked CONFLICTING by GitHub. Entries are now one file per unit of work, docs/now/<YYYY-MM-DD>-<slug>.md: two PRs write two different paths, so the shared line is gone rather than papered over. merge=union is retired for both NOW.md and docs/NOW.md. Measured, not assumed: git merge-tree from a worktree checked out at origin/master reports docs/NOW.md clean for PRs GitHub simultaneously calls CONFLICTING, so the driver never ran where the conflicts were reported. Where it did run its failure mode is silent duplication: docs/NOW.md should hold one `Last updated:` line per entry heading and holds it for every entry but one, `Wave Loop 421 close-out / Wave Loop 422 setup (2026-07-06)`, which carries no date line. The gate asserts strictly more than before: presence (the diff must ADD an entry, --diff-filter=A), freshness (filename date in the same [yesterday .. tomorrow] UTC window), plus a new content assertion of one heading and one bullet, which closes the vacuous-touch hole a whitespace edit used to walk through. Freshness reads the filename, so there is no first-Last-updated coupling and no line for two branches to duplicate. Two dead consumers fixed in passing: tri hooks now-gate matched a bold **Last updated:** label that occurs 0 times in docs/NOW.md -- every stamp there is plain -- and so could never pass; suite.rs check_now_sync demanded today's LOCAL date where CI allowed a UTC window, blocking work locally that CI would accept. docs/NOW.md is frozen as a historical archive with a pointer header. The existing entries are NOT migrated and the orphaned entry is NOT repaired. Rebased onto master after #2300 landed. Three notes on that resolution: - #2300 added two now_gate tests that pass a FILE. This change makes now_gate take a directory, so read_dir gives ENOTDIR and neither can survive. One of them, now_gate_agrees_with_the_live_gate_on_the_real_document, was the only test in the module that touched the real repository; dropping it for five temp-fixture tests would have been a net loss of liveness coverage. It is replaced by the directory analogue, now_gate_agrees_with_the_ci_gate_on_the_real_entries_directory, which runs the gate against the real docs/now/ and cross-checks the entry against the independent pattern and content rules in scripts/ci/now-sync-gate-diff.sh. It derives its expected date from the newest entry present rather than from Utc::now(), so it asserts agreement without asserting freshness and cannot go red merely because nobody wrote an entry today. Its one honest limit is recorded in the test: docs/now/ is created by this PR, so today it asserts against the directory this PR itself adds. - The FROZEN ARCHIVE banner is placed at line 1 explicitly. Under union it landed below master's newest entry, which read as though entry #1 were exempt from "do not add entries here". - Absolute counts in the prose (137 headings / 136 date lines) went stale within one wave -- master is at 138/137 now. They are restated as the invariant they were evidence for, in .gitattributes, in the banner, and in the now_gate doc comment. Closes #2297
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2299. Three small, independent defects found while analysing the
docs/NOW.mdbottleneck.Everything below was verified against
origin/masterat7e8de87b10bf2754c27500e107345b289f26d700, not against a working branch. That mattered: the local checkout is 2,400 commits behind and its.gitattributesstill saysmerge=theirs, which would have produced a false finding for defect 2.1.
tri hooks now-gaterequired a format nothing producescli/tri/src/hooks.rsmatched the bold stamp:The producer disagrees —
cli/tri/src/nownote.rswrites the plain form:On
master:Zero bold against 136 plain, so the gate always fell to its
Nonebranch and bailed with "no line found". Fixed on the consumer side — changing 136 stamps to satisfy a regex would be backwards.**stays optional so archived snapshots and rootNOW.md, which still carry the old bold style, keep matching.The tests were self-matching
Both existing
now_gatetests write their own fixture in the bold form, then assert the regex reads it back. The fixture matched because the same commit authored both sides; neither test ever sawnownote.rs's output or the real document. Two added:now_gate_accepts_the_plain_form_nownote_writes— pins the shapenownote.rsactually emits. Fails against the pre-fix pattern.now_gate_agrees_with_the_live_gate_on_the_real_document— runs the gate against the realdocs/NOW.md, deriving the expected date with the live gate's own rule (bootstrap/src/suite.rstakes the first line containingLast updated:). It asserts the two implementations agree. It deliberately does not assert freshness, so it cannot go red merely because the file is a day old, and it no-ops rather than failing outside a checkout.This is dead code, and saying so changes the severity
Nothing invokes
tri hooks now-gateortri hooks pre-commit. The gate that actually runs at commit time is a separate implementation:.githooks/pre-commit→scripts/tri check-now→t27c check-now(bootstrap/src/suite.rs), which matches oncontains("Last updated:")and therefore accepts plain. Outsidehooks.rsitself, the only mentions are two table rows inMIGRATION_AUDIT.md.So no commit is blocked today. It is still worth fixing:
MIGRATION_AUDIT.mdpresentstri hooksas the Rust port that replaces the shell gates, and it would reject every commit the moment anything wires it up.2.
.gitattributesdescribed a symlink that does not existThe comment read "The root file is a symlink, so git merges the link target, not the text".
100644is a regular file; a symlink would be120000. RootNOW.mdis its own divergent document stampedLast updated: 2026-08-09whiledocs/NOW.mdis stamped today.A second claim was backwards: "the rule above names the SYMLINK, not the file that actually conflicts". The pattern
NOW.mdhas no slash, so git matches it by basename at any depth — it already coversdocs/NOW.md. Verified:Comments only — no rule changed.
git check-attr mergereturnsunionfor the same three paths before and after this commit.Whether root
NOW.mdshould become a real symlink, be deleted, or keep its own content is deliberately not decided here. #2253 raised that and stays open for it; this PR fixes only the comment-accuracy half.3.
docs/NOW.md.master— 835 lines of committed base64Landed in
d063152ad, evidently a.masterconflict side-file that was base64'd and committed. Verified junk before removing:**Last updated:** 2026-04-08— note the bold form, which is the format defect 1's regex was written against.git grep -n "NOW\.md\.master" origin/masterreturns zero hits tree-wide. No script, workflow, test or doc reads the path.Being base64, it was unreadable in review, ungreppable and undiffable — inert bytes. Removed.
A number in the brief did not survive checking
The task I worked from said "137 entries". Measured on
masterit is 136Last updated:stamps across 74^# NOW --headers. Corrected in the issue, the commit message and the NOW entry rather than repeated. The load-bearing figure for the defect is the zero, not the 136.Verification
docs/NOW.md: 0 removed lines — existing entries untouched.2026-08-20); the old bold-only pattern still finds nothing there, which is the defect reproducing on the live document.Compilation — not done locally, since confirmed by CI
I did not run
cargolocally (out of scope for this change), so when this was opened the Rust edits were reviewed by reading only. CI has since compiled and run them. Thecli-trijob reports 155 passed / 1 failed, and all fivenow_gatetests are green, including both new ones:The liveness test passing is the meaningful one: it ran the gate against the real
docs/NOW.mdin a fresh checkout and the two implementations agreed.The three red checks are pre-existing on master
build(cli-tri),coverage(seal-coverage) andwithdrawn-live(withdrawn-live-gate) fail here, and they fail onmastertoo — including at7e8de87b1, the exact commit this branched from:None is caused by this change. The
cli-trifailure isfpga::tests::test_smoke_gate_json_synthetic_verify_leanatcli/tri/src/fpga.rs:9977, which trips on[smoke-gate] SKIP: yosys not on PATH— unrelated tohooks.rs. All four required contexts (check-now-freshness,validate,check,check-linked-issue) pass.One thing observed and deliberately not changed:
now_gatecomputes "today" fromUtc::now(), while the livet27c check-nowuses the local clock. Those can disagree either side of midnight. Out of scope — flagged for whoever wirestri hooksup.