Skip to content

fix(guard,test): check the pushed commit, and resolve band adoption by reachability - #1400

Merged
BigSimmo merged 17 commits into
mainfrom
claude/top-search-design-mockups-w53znc
Jul 30, 2026
Merged

fix(guard,test): check the pushed commit, and resolve band adoption by reachability#1400
BigSimmo merged 17 commits into
mainfrom
claude/top-search-design-mockups-w53znc

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

This PR outgrew its original title. It began as one AGENTS.md bullet and is now 5 files / +786 lines, because review found real defects in the two things the bullet described. The body below replaces the original "documentation only, two files, one line each", which is no longer true.

No production surface is touched. git diff --name-only origin/main...HEAD matches nothing under src/, supabase/, worker/, or .github/workflows/. The two code files are a local pre-push git hook and a Vitest gate. Nothing here can affect the running app, the database, ingestion, retrieval, or clinical output.

1. AGENTS.md — format before pushing, and commit the result

Three CI failures on 2026-07-30 were the same shape: an unformatted file reached Static PR checks, which runs prettier --check .. The ordinary loop cannot catch it — format:check is in none of test, typecheck, or lint. The bullet records two traps beyond "run it": formatting after committing leaves the unformatted blob on the branch, and a per-file prettier --check is not the repository-wide check (that was the missed file twice out of three).

2. scripts/guard-push.mjs — check the commit CI will check

The guard existed but answered the wrong question. It now materialises the pushed SHA in a temporary git worktree with node_modules linked in, and runs Prettier there. Six review findings drove this, each one a way working-tree state leaked into the verdict:

Defect Fix
Checked working-tree paths, so a formatted working copy vouched for an unformatted commit Reads the pushed blobs
Read the working tree's .prettierrc, so a committed-broken/tree-corrected config passed Config comes from the pushed tree
A dynamic prettier.config.mjs could not be evaluated at all Worktree has node_modules, so it loads its plugins
A prettier-policy change re-decides untouched files' verdicts Policy change escalates to whole-tree prettier --check .
Only added prettier fields were detected, not removed ones Both endpoints inspected via git
Formatted with this checkout's Prettier, not the pushed lockfile's Versions compared when the push touches dependencies

A Prettier execution error now blocks rather than failing open — being unable to check is not evidence a push is clean. SKIP_FORMAT_GUARD=1 remains the escape hatch and is named in every failure message.

3. tests/search-results-band-adoption.test.ts — reachability, not presence

Closes #115. Six false greens were reported on this gate in one day: an unrendered import, export { X }, export { X } from, export *, a bare side-effect import, JSX in an unmounted helper, and a lazy import reaching every sibling export. They are one defect — the walk asked whether a file mentions the band when the question is whether anything the route mounts reaches it. Two of the six were introduced by earlier patches to this same walker, which is why it was replaced rather than patched a seventh time.

Each module is now parsed into a small graph (exported name → local, local → identifiers its body references, locals that render the band), and the walk carries at each hop the set of exports the importer mounts. The special cases fall out of module semantics: dynamic(() => import("…").then((m) => m.Named)) follows only that binding; then((mod) => ({ default: mod.Named })) — the shape global-search-shell.tsx uses for ClinicalDashboard — resolves through the wrapper; a discarded void import(…) is a preload, not a mount; import type is erased and is not an edge; export * never supplies a default.

Also adds #116: an unmergeable PR runs no CI at all and says nothing. This PR hit that twice — GitHub cannot build the merge ref while conflicted, so every pull_request-triggered workflow is silently skipped and the symptom reads as "CI is broken".

Verification

  • npm run verify:cheapTest Files 432 passed (432), Tests 4470 passed | 4 skipped (4474)
  • npm run format:checkAll matched files use Prettier code style!
  • Every fix proved by reverting it. Gutting (search-app)/services/page.tsx and tools/page.tsx to <div /> each reports an orphan. Targeted mutations re-open each hole and the guarding fixture fails: presence-based band check, following bare imports, unhandling the object wrapper, recording discarded imports, and not skipping type-only imports.
  • Push guard verified in isolated scratch repos, real exit codes. Blocks: committed-unformatted with a clean working tree; committed-only broken static config; committed-only broken dynamic config; a config-only change breaking an untouched file; a removed prettier field an untouched file depended on; a pushed lockfile pinning a different Prettier. Passes: all-clean; a benign config change; a plain dependency bump; and a mismatched lockfile the push does not touch.
  • Two of my fixtures initially passed for the wrong reason — guarded by hop filtering rather than the mechanism they named. Replaced with fixtures that fail under mutation. Recorded because a fixture that cannot fail is not coverage.
  • npm run verify:uinot run: no UI, routing, styling, reduced-motion or forced-colors behaviour changed; Production UI is correctly out of scope for this diff.
  • npm run check:production-readiness, eval:*, verify:releasenot run: no clinical workflow, privacy, environment, Supabase, retrieval or deployment behaviour changed. No provider was contacted at any point.

RAG impact: no retrieval behaviour change — nothing under src/lib/rag/**, clinical-search, retrieval-selection, released-search-order, ranking-config, answer-ranking, the eval harness, the golden fixture, or the retrieval RPCs is touched.

Risk and rollout

  • Risk to the running system: none. No production code, schema, migration, API contract, or configuration. The guard runs only on git push from a checkout with core.hooksPath set; the gate runs only in Vitest.
  • Risk A — the guard can block a legitimate push. The lockfile-parity check fires when a push changes package.json/package-lock.json, which includes merging main when main carried a lockfile change. With stale node_modules that push is blocked until npm ci. Friction only, and SKIP_FORMAT_GUARD=1 is named in the message.
  • Risk B — the adoption gate's failure mode has flipped from false-green to false-red. It runs inside npm run test, so it blocks CI repo-wide. All five production search routes pass today and both negative controls behave. But a future page mounting through a pattern the graph does not model would be reported as an orphan until someone adds a documented BAND_ROUTE_ALLOWLIST entry. Loud is the better direction than silent, but it is a change in character for a shared gate.
  • Rollback: revert per concern. The three parts are independent — the AGENTS.md bullet, the guard, and the gate touch no shared code.
  • Provider or production effects: none.

Clinical Governance Preflight

Not applicable. classifyPullRequestFiles reports clinicalRisk: false for all five paths: no ingestion, answer generation, search/ranking, source rendering, document access, privacy, production environment, or clinical output behaviour is touched.

Notes

On merge vs squash. Auto-merge is armed with method merge, so the 15 commits — including two main merges — land intact. #088 asks for an eye on branch-review-ledger union-driver duplication as open PRs merge; this PR touches that file, so it is one to check afterwards.

Two client-side guards are inert for agents. guard-push.mjs reported auto-merge: gh not available — auto-merge check skipped (fail-open) for pushes from this environment, and core.hooksPath is set only by a local npm install. So neither the format guard nor the auto-merge sentinel protects a push made from an agent's own checkout — the reason the AGENTS.md instruction is still needed even though the tooling now exists.

What I deliberately did not do. I had proposed a merge=union driver for docs/outstanding-issues.md after a genuine conflict. Testing showed it is wrong: union concatenates conflicting hunks, so two sides each bumping the next-id marker produce two markers. A conflict fails loudly; a duplicated marker corrupts the ledger silently. Withdrawn. The real fix is probably to stop padding that table to fixed column widths — one row's edit currently re-pads all 116 — but not in a file several agents are writing to concurrently.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

claude and others added 2 commits July 30, 2026 03:22
Three CI failures on 2026-07-30 came from the same cause — an
unformatted file reaching Static PR checks and ci/circleci: verify,
which both run prettier --check . Each time the author had run the unit
suite, typecheck, lint, and a focused prettier check on the file they
were working on, and reported green.

The loop cannot catch it: format:check is in none of test, typecheck or
lint. A format-before-push guard already exists in .githooks/pre-push,
and it works — but core.hooksPath is configured by this checkout's npm
install, so an agent pushing from its own environment never runs it.
Hooks are client-side, so this cannot be fixed for other environments in
tooling; the instruction surface is the only lever.

Records the specific trap as well as the rule: the missed file was twice
a doc or ledger edit made alongside a source change, which a per-file
prettier check on the source file does not cover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
Tip 66c5eb2 failed Static PR on prettier padding in #96; fixed on
6131488, then main sync landed as 4a001ef. Closeout confirms required
checks green with no open review threads.

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 8 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a8086c48-e175-48df-9566-1b65d9b9b96d

📥 Commits

Reviewing files that changed from the base of the PR and between 20235cc and e869cb9.

📒 Files selected for processing (5)
  • AGENTS.md
  • docs/branch-review-ledger.md
  • docs/outstanding-issues.md
  • scripts/guard-push.mjs
  • tests/search-results-band-adoption.test.ts
📝 Walkthrough

Walkthrough

The PR strengthens pre-push formatting verification by checking pushed commit contents in temporary worktrees and refines route reachability analysis with Babel AST parsing and mount-aware import traversal.

Changes

Pushed-commit format verification

Layer / File(s) Summary
Commit blob and policy inputs
scripts/guard-push.mjs
Changed files are collected with commit SHAs, and Prettier policy files are detected.
Temporary worktree formatting checks
scripts/guard-push.mjs
Pushed commits are checked in detached temporary worktrees with cleanup, batching, policy escalation, and error classification.
Guard orchestration and process guidance
scripts/guard-push.mjs, AGENTS.md, docs/branch-review-ledger.md
Push orchestration uses blob-based checks, updated failure messages, and documents the format-and-commit process.

AST-based route reachability

Layer / File(s) Summary
Mount-aware specifier analysis
tests/search-results-band-adoption.test.ts
Babel parsing identifies mounted JSX and default-export bindings and selects the corresponding specifiers to follow.
Traversal integration and fixtures
tests/search-results-band-adoption.test.ts
Route traversal uses the new helper and tests mounted defaults, unmounted imports, named re-exports, and star re-exports.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant formatGuard
  participant checkPushedCommit
  participant GitWorktree
  participant Prettier
  formatGuard->>checkPushedCommit: check commit SHA and changed files
  checkPushedCommit->>GitWorktree: create detached worktree
  checkPushedCommit->>Prettier: run formatting checks
  Prettier-->>checkPushedCommit: return check result
  checkPushedCommit->>GitWorktree: remove temporary worktree
  checkPushedCommit-->>formatGuard: return verdict
Loading

Possibly related PRs

Suggested reviewers: cursoragent

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the main changes: guard-push commit checking and the band-adoption reachability fix.
Description check ✅ Passed The description follows the template well, with Summary, Verification, Risk and rollout, Clinical Governance, and Notes sections filled in.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@supabase

supabase Bot commented Jul 30, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@BigSimmo
BigSimmo marked this pull request as ready for review July 30, 2026 03:38
@BigSimmo

Copy link
Copy Markdown
Owner Author

@cursoragent fix merge conflict

@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Resolved and pushed on tip 87819325. PR #1400 is MERGEABLE again (currently BLOCKED only by required checks settling).

Classification

Simple — no real content conflict. Only docs/branch-review-ledger.md. GitHub showed DIRTY/CONFLICTING because the branch was behind main by the #1399 ledger squash (cd2c6662). Local git merge origin/main auto-merged via the ledger’s merge=union driver; no markers, no intent clash.

Side Change
This branch AGENTS.md format-before-push bullet + stranded #1394 closeout ledger row
main (#1399) Same closeout family as squash 0d47141f / ledger row for merged #1394

No product-code conflicts. AGENTS.md was untouched by main.

Resolution

  • Reset local to remote PR tip 9b7cec23
  • Merged origin/main87819325
  • Kept both ledger appends; PR intent unchanged (AGENTS.md + one branch ledger row vs main)

Complicated conflicts

None.

Open in Web Open in Cursor 

…ign-mockups-w53znc

Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b7cec2308

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread AGENTS.md Outdated
…ng it

Codex found my own instruction incomplete, and in a way that could
mislead: a push sends commits, not the working tree, so running the
formatter after committing leaves the unformatted blob on the branch.

Worse, guard-push.mjs runs prettier --check against working-tree paths,
so it reports clean while the pushed commit is still unformatted. Proved
it in a scratch repo — commit `const a   =    1`, format, and the
working tree reads `const a = 1;` while `git show HEAD:f.ts` still has
the original; --check on the path passes, --check on the committed blob
fails. A green guard is therefore not evidence.

Rewrote the bullet to require committing the formatter output and to name
both traps explicitly: that one, and the per-file check that passes on
the source file you edited while a doc or ledger edit in the same push
fails — which was the missed file in two of the three CI breaks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

Copy link
Copy Markdown
Owner Author

Re: "Require committing formatter output before pushing" — correct, and it made my own instruction actively misleading. Fixed in 2ac85d5b.

I proved the mechanism in a scratch repo rather than reasoning about it. Commit const a = 1, then run the formatter:

Content
Working tree after formatting const a = 1;
git show HEAD:f.ts — what a push sends const a = 1
prettier --check <path> (what guard-push.mjs runs) All matched files use Prettier code style!
prettier --check on the committed blob Code style issues found

So the guard reports clean while the pushed commit is unformatted. That is worse than my bullet simply being incomplete — anyone following "run npm run format before every push" would have seen the guard go green and pushed anyway. A passing guard is not evidence, and the bullet now says so.

Rewritten to require committing the formatter output, with both traps named:

  • formatting without committing does nothing for the push, and the guard's working-tree check hides it
  • a per-file prettier --check on the source file passes while a doc or ledger edit in the same push fails — that was the missed file in two of the three CI breaks

Worth separating what's mine from what's the tooling's: the wording was my error and is fixed here. The guard checking working-tree paths instead of the pushed blobs is a real weakness in scripts/guard-push.mjs that this PR does not address — it would need to check git show <sha>:<path> for the range. I'd rather that got its own change than be bundled into a documentation PR. Happy to record it as a ledger item or fix it separately, whichever you prefer.

Verification: npm run format:check clean; npm run docs:check-links — 1375 references resolve; npm run test4459 passed, 4 skipped; grep -c "^## Dependency shortcut" AGENTS.md → 1, per that section's own self-check.


Generated by Claude Code

@BigSimmo
BigSimmo enabled auto-merge (squash) July 30, 2026 03:43
Two gaps, both proven before fixing and both re-proven after.

guard-push's format guard ran prettier against working-tree paths, but a
push sends commits. Commit `const a   =    1`, run npm run format, and
--check on the path passed while git show HEAD:<file> was still
unformatted — the guard went green and CI failed. It now reads the pushed
blob via git show <sha>:<file>, fed through --stdin-filepath so Prettier
still picks the parser from the real path and still honours
.prettierignore for it. Verified: an unformatted commit with a formatted
working tree now exits 1, a formatted commit exits 0, and
SKIP_FORMAT_GUARD=1 still overrides. Unknown verdicts (deleted blob, no
parser) stay fail-open so nothing new can block a push.

The band adoption gate followed every import specifier, so a route that
kept its results import but stopped rendering it still counted as
adoption — the exact regression the gate exists to catch. It now parses
with @babel/parser and follows a static import only when the binding is
mounted: JSX element, default re-export, or named re-export. import(),
export-from and side-effect imports stay unconditional, since each is a
mount mechanism rather than a binding that can go unused, and the lazy
form is the only route to the code-split dashboard workspaces.

Verified by gutting (search-app)/services/page.tsx to <div /> with its
imports intact: previously green, now an orphan; restored, it passes.
Pinned by temp-dir fixtures for imported-but-unrendered, default
re-export, and lazy import.

Closes #115.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c0647aea97

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-push.mjs Outdated
Comment thread tests/search-results-band-adoption.test.ts Outdated
@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 04:06
Codex found me over-applying fail-open. A malformed prettier config in the
push makes Prettier exit non-zero; my catch returned null and formatGuard
only blocked on an explicit false, so a config error let the push through
while CI's prettier --check . failed for the same reason. That is the
guard waving through exactly the break it exists to catch.

Three verdicts now, each verified in its own scratch repo so a stray
config could not confound the others:
  unformatted commit -> exit 1, "found unformatted files"
  formatted commit   -> exit 0, silent
  malformed config   -> exit 1, "could not check this push"

Fail-open is now reserved for a blob that is absent at the pushed sha —
deleted in this push, so CI has nothing to check either. --ignore-unknown
still covers the benign no-parser case, so any other non-zero exit is a
real problem and is surfaced with Prettier's own stderr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc166c8fb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/search-results-band-adoption.test.ts Outdated
A page that re-exported a banded component while its own default rendered
<div /> reported adoption: the walker treated `export { Banded }` as a mount
and followed the import. Re-exporting renders nothing, so drop that branch —
wherever the re-export is finally mounted, the walk sees the JSX there.

Pinned by a fixture that fails against the previous behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 055df85698

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-push.mjs Outdated
Comment thread tests/search-results-band-adoption.test.ts Outdated
Resolves the docs/outstanding-issues.md conflict: main re-padded the whole
table and extended #109, so the conflict spanned all 58 rows while the only
semantic difference was this branch closing #115. Took main's block and kept
this branch's #115 row.

The conflict is why no CI ran here: GitHub cannot build refs/pull/1400/merge
for an unmergeable PR, so every pull_request-triggered workflow (CI, Gitleaks,
Semgrep) was skipped while pull_request_target ones still ran, and CircleCI
failed 3 seconds after each push.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25102a4d6a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-push.mjs Outdated
Comment thread scripts/guard-push.mjs Outdated
claude added 2 commits July 30, 2026 04:40
Two review findings, both about working-tree state leaking into the verdict:

- A dynamic `prettier.config.mjs` could not be evaluated by the previous
  hand-staged config approach, so the guard fell back to the working-tree
  config — recreating the mismatch it exists to prevent.
- A push that changes prettier policy (.prettierrc, .prettierignore,
  .editorconfig, package.json) changes the verdict for files the push never
  touched, which a changed-paths-only check cannot see.

Both are answered by checking the pushed commit where CI checks it: a
`git worktree` of that sha (<1s here) with node_modules linked in, so a
dynamic config loads its plugins. A policy change escalates to a whole-tree
`prettier --check .`; otherwise only the changed paths are checked. Failure
to create the worktree now fails closed — being unable to check is not
evidence the push is clean.

Verified on six isolated scratch repos, exit codes 1/0/1/1/1/0: committed
unformatted with a clean working tree blocks; all-clean passes; a
committed-only broken static config blocks; a committed-only broken dynamic
config blocks (was passing); a config-only change that breaks an untouched
file blocks (was passing); a benign config change still passes.

Also records #116: an unmergeable PR runs no CI at all and says nothing,
which is what cost this branch three pushes of missing checks today.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
Second conflict in docs/outstanding-issues.md in under an hour, same shape:
main re-padded the table so the hunk spanned every row, while only two rows
differed. Took main's #108 (completed by #1403) and kept this branch's #115
closure. #116 does not collide — main's next-id was still 116.

This recurrence is the case #116 itself describes: while conflicted, the PR
ran no CI at all and nothing said so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20235ccba1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-push.mjs
Comment thread tests/search-results-band-adoption.test.ts Outdated
Comment thread tests/search-results-band-adoption.test.ts Outdated
BigSimmo pushed a commit that referenced this pull request Jul 30, 2026
…able

Every open PR sampled carries the same ci/circleci: verify failure, including
#1400 which is a docs-only AGENTS.md change, so it is not branch-specific. The
job's whole contents were mirrored locally on #1396's tip and all of it is
green, including the PyMuPDF-gated PDF tests under a venv built exactly as
.circleci/config.yml builds it. That puts the fault in the job environment.

Recorded with the quota hypothesis marked explicitly unverified: the CircleCI
project is private, no session has a CircleCI token, and the unauthenticated
API returns "Build not found". Reading the failing step needs an operator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01361jh3eYVjJCzXWjAhdZiF

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
scripts/guard-push.mjs (1)

201-214: 🚀 Performance & Scalability | 🔵 Trivial

Any package.json edit anywhere in the tree triggers a full-repo prettier check.

Matching purely on basename means a dependency bump in an unrelated package.json (with no "prettier" field) escalates to [["."]] — a repository-wide prettier --check . — even though it can't actually change any other file's formatting verdict. This adds latency to the common case of routine dependency edits.

♻️ Only escalate when the package.json actually carries prettier config
-function isPrettierPolicyFile(file) {
-  return /^(?:\.prettierrc(?:\..+)?|prettier\.config\.(?:js|cjs|mjs|ts)|\.prettierignore|\.editorconfig|package\.json)$/.test(
-    path.basename(file),
-  );
-}
+function isPrettierPolicyFile(file, dir) {
+  const base = path.basename(file);
+  if (/^(?:\.prettierrc(?:\..+)?|prettier\.config\.(?:js|cjs|mjs|ts)|\.prettierignore|\.editorconfig)$/.test(base)) {
+    return true;
+  }
+  if (base !== "package.json") return false;
+  try {
+    const contents = readFileSync(path.join(dir, file), "utf8");
+    return JSON.parse(contents).prettier !== undefined;
+  } catch {
+    return true; // fail closed if it can't be read/parsed
+  }
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/guard-push.mjs` around lines 201 - 214, Update isPrettierPolicyFile
so package.json matches only when that file contains a Prettier configuration
field; retain unconditional matching for the dedicated Prettier and editor
configuration filenames. Ensure unrelated package.json edits no longer trigger
whole-tree formatting checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Around line 169-174: Update the guard-push.mjs behavior description in
AGENTS.md to reflect that checkPushedCommit verifies the pushed SHA in a
temporary git worktree with Prettier, rather than checking working-tree paths.
Remove the stale claim that the guard can pass while the pushed commit remains
unformatted.

In `@docs/outstanding-issues.md`:
- Line 155: The `#115` summary and detail contradict each other about named
re-export reachability. Update the summary text in the issue record to match the
tested behavior described in the detail: do not follow named or star re-exports,
while retaining default re-exports and lazy import behavior.
- Line 155: Restore the seven-column Markdown table structure for the `#115` row
in the outstanding-issues ledger by inserting the authoritative source value
between the detailed status text and the final 2026-07-30 date. Preserve the
existing issue number, priority, status, descriptions, and date.
- Line 152: Update the verification gate for docs/outstanding-issues.md to
enforce duplicate-ID uniqueness within the records table only, allowing
intentional IDs shared with the execution queue. Separately validate that queue
references correspond to valid records and that the marker is greater than the
maximum record ID; keep the document as the single durable ledger.

---

Nitpick comments:
In `@scripts/guard-push.mjs`:
- Around line 201-214: Update isPrettierPolicyFile so package.json matches only
when that file contains a Prettier configuration field; retain unconditional
matching for the dedicated Prettier and editor configuration filenames. Ensure
unrelated package.json edits no longer trigger whole-tree formatting checks.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f2f78c14-fbcd-4a9b-abb9-480a32b53424

📥 Commits

Reviewing files that changed from the base of the PR and between f937493 and 20235cc.

📒 Files selected for processing (5)
  • AGENTS.md
  • docs/branch-review-ledger.md
  • docs/outstanding-issues.md
  • scripts/guard-push.mjs
  • tests/search-results-band-adoption.test.ts

Comment thread AGENTS.md
Comment thread docs/outstanding-issues.md Outdated
Comment thread docs/outstanding-issues.md Outdated
Six false greens were reported on the adoption gate in one day — an unrendered
import, `export { X }`, `export { X } from`, `export *`, a bare side-effect
import, JSX inside an unmounted helper, and a lazy import reaching every
sibling export of the same module. They are one defect: the walk asked whether
a file mentions the band, when the question is whether anything the route
mounts reaches it. Two of the six were introduced by an earlier patch to this
same walker, so this replaces the heuristic rather than adding a seventh case.

Each module is now parsed into a small graph (exported name -> local, local ->
identifiers its body references, locals that render the band) and the walk
carries, at every hop, the set of exports the importer actually mounts. The
special cases fall out of module semantics instead of being enumerated:
`dynamic(() => import("…").then((m) => m.Named))` follows only that binding;
a bare `import "…"` renders nothing so is not followed; `export { X } from`
is followed only when the importer wants X; `export *` never supplies a
default, so a page needing only a default gets no hop from it.

Verified: all five production search routes still reach the band; gutting
services/page.tsx and tools/page.tsx to <div /> each reports an orphan; the two
fixtures guarding the new mechanisms were confirmed to fail under targeted
mutation (presence-based band check, and following bare imports) after an
initial pair that did not bite was replaced.

Also from review:
- guard-push escalates to a whole-tree check for a package.json only when it
  carries a prettier field, so a routine dependency bump does not. Verified:
  bump passes, prettier-field narrowing blocks, .prettierrc narrowing blocks.
- AGENTS.md no longer claims the guard checks working-tree paths; that was the
  defect this PR fixed, and leaving it would teach distrust of a fixed guard.
- Repairs the #115 ledger row, whose Source cell had been overwritten by the
  detail text, and rewrites it for the new design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
@BigSimmo
BigSimmo enabled auto-merge July 30, 2026 04:58
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

⚠️ Branch updated during autofix.

The branch was updated while autofix was in progress. Please try again.

Copy link
Copy Markdown
Owner Author

Thread status before the resolve pass — 10 of 11 are already fixed

@codex has been asked to fix every thread on this PR. Ten of them are marked is_outdated by GitHub because the code they cite no longer exists — tests/search-results-band-adoption.test.ts was rewritten in 0ce9f5e6 and scripts/guard-push.mjs in 20235ccb. Posting the map so the resolve pass doesn't re-fix fixed code, and so the one genuinely open finding isn't lost among them.

Exactly one finding is still live: "Resolve Prettier from the pushed dependency tree" (scripts/guard-push.mjs, the only thread with is_outdated: false).

Finding Status Where
Trace JSX only from components that are actually mounted Fixed 0ce9f5e6 — the band check is scoped to locals reachable from what the route mounts
Stop treating side-effect imports as component mounts Fixed 0ce9f5e6 — a bare import "…" produces no graph edge at all
Track the mounted binding for dynamic imports Fixed 0ce9f5e6import("…").then((m) => m.Named) follows only that binding
Do not count named exports as rendered mounts Fixed 0ce9f5e6 — a re-export is followed only when the importer wants that name
Exclude direct named re-exports from mount traversal Fixed 0ce9f5e6 — same mechanism; export * never supplies a default
Evaluate dynamic config from the pushed commit Fixed 20235ccb — the pushed SHA is checked in a git worktree with node_modules linked, so prettier.config.mjs loads
Check the full tree after formatter policy changes Fixed 20235ccb — a prettier-policy change escalates to a whole-tree prettier --check .
Treat Prettier execution failures as blocking Fixed fc166c8f — a config error is an explicit blocking verdict, not a fail-open null
Require committing formatter output before pushing Fixed 2ac85d5b + 20235ccb — wording corrected, and the guard now reads the commit, not the working tree
Any package.json edit triggers a full-repo check Fixed 0ce9f5e6 — escalates only when the file carries a prettier field
Resolve Prettier from the pushed dependency tree Open resolvePrettierBin() resolves from the hook's own install, and the linked node_modules is the current checkout's, not the pushed lockfile's

The six adoption-gate findings were one defect — the walk asked whether a file mentions the band when the question is whether anything the route mounts reaches it — so 0ce9f5e6 replaced the heuristic with a per-module reachability graph rather than adding a sixth special case. Two of those six were introduced by earlier patches to the same walker, which is why it stopped being patched.

Each fix was verified by reverting it and confirming the guard fails: services/page.tsx and tools/page.tsx gutted to <div /> are each reported as orphans; the two fixtures guarding the new walker mechanisms fail under targeted mutation (presence-based band check; following bare imports); the push guard blocks on a committed-unformatted blob with a clean working tree, on a committed-only broken static config, on a committed-only broken dynamic config, and on a config-only change that breaks an untouched file — while a benign config change and a plain dependency bump both pass. verify:cheap: Tests 4470 passed | 4 skipped (4474).

On the open one

A pre-push hook cannot run npm ci for the pushed lockfile, so "run with the pushed dependency tree" isn't reachable in this context. The two honest options are to detect that the push changes package-lock.json/package.json dependencies and either report that the verdict used the local Prettier, or fail closed. Blocking every dependency PR seems worse than a visible note, but that's a judgement call.

Two notes for whoever lands this: auto-merge is armed, so any commit from this pass merges once checks pass; and docs/outstanding-issues.md has conflicted with main twice in the last hour because its table is padded to fixed column widths, so one row's edit re-pads all 116 rows. While conflicted, GitHub cannot build the merge ref and every pull_request-triggered workflow is silently skipped — that failure mode is now recorded as #116.


Generated by Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ce9f5e632

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-push.mjs Outdated
Comment thread tests/search-results-band-adoption.test.ts
Comment thread tests/search-results-band-adoption.test.ts Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Added dependency-tree parity validation that compares the pushed package-lock.json with npm’s installed hidden lockfile. This prevents the formatting guard from borrowing a different Prettier version or config-loaded plugin while allowing legitimately omitted optional platform packages. scripts/guard-push.mjsL201-L227
  • Changed pushed-commit formatting verification to fail closed when local dependencies do not represent the pushed commit, with an actionable instruction to run npm ci at that commit. scripts/guard-push.mjsL268-L301
  • Added regression coverage for matching dependencies, mismatched Prettier versions, and missing Prettier plugins. tests/guard-push.test.tsL78-L100
  • Extended the standalone guard self-test with dependency-parity assertions. scripts/guard-push.mjsL519-L528
  • Committed the changes as ed6be22 (fix(guard): verify pushed dependency tree) and created the requested stacked pull-request metadata.

Testing

  • npm run format -- --log-level warn
  • node scripts/guard-push.mjs --self-test[guard-push] self-test passed
  • git diff --check
  • ⚠️ npm run test -- --run tests/guard-push.test.ts — could not start because this checkout lacks node_modules/vitest/vitest.mjs.
  • git status --short --branch — clean after commit (## work).

View task →

BigSimmo and others added 3 commits July 30, 2026 13:04
…rts, and policy removal

Three review findings on 0ce9f5e, all valid:

- `then((mod) => ({ default: mod.Foo }))` — the Next.js wrapper for a named
  export, which global-search-shell.tsx uses for ClinicalDashboard on the root
  dashboard chain. thenExportName returned null for it, so the walk fell back to
  following every export of that module: the exact over-approximation the
  redesign exists to remove.
- A dynamic import whose result is discarded (`void import(…)` in an effect, or
  a bare `import(…);` statement) is a preload and cannot mount anything. Scoped
  to discarded *results* rather than requiring lexical containment in
  `dynamic()`, because clinical-dashboard-lazy.tsx also writes the loader as a
  separate binding and requiring containment would report that unreachable.
- guard-push inspected only the pushed package.json for a `prettier` field, so
  *adding* one escalated to a whole-tree check but *removing* one did not —
  drop `tabWidth: 4` and four-space-formatted source starts failing CI. Both
  endpoints are now inspected via git rather than the checkout.

Each fix verified by mutation: unhandling the object wrapper makes the
wrapper-plain fixture reach the band; recording discarded imports makes the
preload fixture reach it. Both fail as they should.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
…-w53znc' into claude/top-search-design-mockups-w53znc

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de2d16d35a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/search-results-band-adoption.test.ts
…imports

Two further review findings:

- The guard formats with this checkout's Prettier while CI installs the pushed
  lockfile, so a push that bumps Prettier itself would be judged by the wrong
  version. When the push touches package.json or package-lock.json, the pinned
  and installed versions are compared and a difference blocks with an actionable
  `npm ci` message. Verified: a push changing the lockfile to a different pin
  blocks; a matching pin passes; and — the non-regression that matters — a
  mismatched lockfile the push does not touch still passes, so ordinary pushes
  are unaffected by node_modules drift.
- `import type { Banded } from "…"` is erased at runtime and cannot mount
  anything, but was recorded as a component edge, so a route with a type-only
  prop reached the band. Both spellings are skipped (declaration-level
  `importKind` and the per-specifier one from `import { type X }`), plus
  `export type { X } from`. Pinned by a fixture that fails without the skip.

This closes the last open Codex finding on the branch. Its own fixes for it
exist only as unreachable commits on a branch named `work` — seven SHAs, none
fetchable — so they could not be used.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY
@BigSimmo BigSimmo changed the title docs(agents): require npm run format before pushing fix(guard,test): check the pushed commit, and resolve band adoption by reachability Jul 30, 2026
@BigSimmo
BigSimmo disabled auto-merge July 30, 2026 05:24
@BigSimmo
BigSimmo enabled auto-merge July 30, 2026 05:24
…ferences

Found in my own review pass, not by a reviewer. The earlier fix skipped
`import type` declarations, but a *value* import used only in a type position
was still recorded as a runtime edge — and this repo does not enforce
`consistent-type-imports`, so `ComponentProps<typeof Banded>` is a legitimate
value import that never mounts anything.

References are no longer collected from typeAnnotation / returnType /
typeParameters / typeArguments subtrees. Value expressions never live under
those keys, so nothing real is lost; `x as Foo` still contributes `x`.

The first fixture I wrote for this passed for the wrong reason — a top-level
`type Props = …` alias is never scanned at all, so it proved nothing. Rewritten
with the annotation inline on the scanned declaration, and confirmed to fail
when the skip is removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

Copy link
Copy Markdown
Owner Author

All review threads dispositioned — resolving them now

Every finding on this PR is fixed on the branch. Verified against the file contents at e869cb9d, not from memory, and each fix located to its introducing commit with git log -S.

Finding Fixed in Mechanism now on the branch
Require committing formatter output before pushing 2ac85d5b + 20235ccb Wording corrected; the guard reads the commit, not the working tree
Treat Prettier execution failures as blocking fc166c8f A config error is an explicit blocking verdict, not a fail-open null
Track the mounted binding for dynamic imports 0ce9f5e6 import("…").then((m) => m.Named) follows only that binding
Do not count named exports as rendered mounts 0ce9f5e6 A re-export is followed only when the importer wants that name
Exclude direct named re-exports from mount traversal 0ce9f5e6 Same mechanism; export * never supplies a default
Load Prettier configuration from the pushed commit 20235ccb Config comes from a git worktree of the pushed SHA
Evaluate dynamic config from the pushed commit 20235ccb node_modules linked into that worktree, so prettier.config.mjs loads
Check the full tree after formatter policy changes 20235ccb A policy change escalates to whole-tree prettier --check .
Trace JSX only from components that are actually mounted 0ce9f5e6 Band check scoped to locals reachable from what the route mounts
Stop treating side-effect imports as component mounts 0ce9f5e6 A bare import "…" produces no graph edge
Any package.json edit triggers a full-repo check 0ce9f5e6 Escalates only when the file carries a prettier field
Detect removal of package-level Prettier policy 7c5c613e Both endpoints inspected via git show, so removal counts too
Resolve object-wrapped dynamic exports precisely 7c5c613e then((mod) => ({ default: mod.Named })) resolves through the wrapper
Restrict lazy mount edges to actual dynamic components 7c5c613e A discarded void import(…) is a preload, not a mount
Resolve Prettier from the pushed dependency tree 0258f336 Installed vs pinned version compared when the push touches dependencies
Exclude type-only imports from mount traversal 0258f336 import type / export type skipped, declaration- and specifier-level
#115 summary contradicted its detail de2d16d3 Row rewritten for the reachability design
#115 row had lost a cell de2d16d3 Seven-column structure restored — the Source cell had been overwritten

Skipped, with reason: "Scope duplicate-ID validation per table" describes a verification gate proposed inside #112's own text. #112 is main's row about work this PR does not do, so changing it here would be out of scope. The docstring-coverage warning is a generic 80% threshold, not a repo gate; the new code is heavily commented and npm run lint is clean.

One further issue, found in my own review rather than by a reviewer

e869cb9d stops counting identifiers in type positions as component references. The import type fix covered the declaration form, but a value import used only in a type position was still an edge — and this repo does not enforce consistent-type-imports, so ComponentProps<typeof Banded> is a legitimate value import that mounts nothing. References are no longer collected from typeAnnotation / returnType / typeParameters / typeArguments subtrees; x as Foo still contributes x.

Worth recording: my first fixture for it passed for the wrong reason. A top-level type Props = … alias is never scanned at all, so the fixture proved nothing about the skip. Rewritten with the annotation inline on the scanned declaration, it fails when the skip is removed. That is the third fixture on this PR that initially passed for the wrong reason — a fixture that cannot fail is not coverage, so every one here has been confirmed against a targeted mutation.

State

  • No merge conflict. git merge-tree --write-tree origin/main HEAD reports none; the branch is 0 behind / 17 ahead.
  • npm run verify:cheapTest Files 432 passed (432), Tests 4470 passed | 4 skipped (4474).
  • npm run format:check — clean.
  • All five production search routes still reach the band; gutting services/page.tsx and tools/page.tsx to <div /> each reports an orphan.

Generated by Claude Code

@BigSimmo
BigSimmo merged commit b15e267 into main Jul 30, 2026
18 checks passed
@BigSimmo
BigSimmo deleted the claude/top-search-design-mockups-w53znc branch July 30, 2026 05:37
BigSimmo added a commit that referenced this pull request Jul 30, 2026
…indings (#1424)

* docs(ledger): record PR #1400 closeout and capture three unrecorded findings

Documentation only — two ledger files, no code.

**Review closeout for PR #1400** appended with `ledger:append` (never
hand-written), recording the 17 findings fixed, the verification behind each,
and the post-merge check that all 8 commits are ancestors of main with the 4
changed files byte-identical.

**Three findings from that session that nothing else records:**

- `#125` — `@codex fix` produced 11 commits across a branch named `work`,
  none fetchable, the same finding rewritten four times. It reads as success
  while the branch is unchanged, which is the actual hazard.
- `#126` — both client-side push guards are inert for agent pushes:
  `gh` absent makes the auto-merge sentinel fail open, and `core.hooksPath`
  is set only by a local install. They protect the environment least likely to
  need them.
- `#127` — this ledger's fixed-width padding makes one row's edit re-pad all
  59, so it conflicts on nearly every main advance; each conflict silently
  stopped all CI on #1400 via `#116`. Records that `merge=union` is the wrong
  fix, with the evidence.

CircleCI was deliberately not filed — already captured as `#122`. Checked
before writing rather than after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

* docs(issues): correct unsafe pull_request_target advice in #129

Review caught a real problem in the guidance I filed, not in code: #129's
next-action suggested moving *both* push guards server-side into a
`pull_request_target` job. That context carries secrets and a write token, and
a format check must execute PR-head code — including the dynamic
`prettier.config.*` this very PR taught the guard to load. That is the classic
privileged-context vector, and `.github/workflows/pr-policy.yml` already avoids
it deliberately by checking out only `github.workflow_sha`.

Corrected, and the row now records why the whole idea was unnecessary:
formatting is already enforced server-side by `Static PR checks` running
`format:check` on ordinary `pull_request` CI, so the guard's only unique value
is failing fast before the push. Only the metadata-only auto-merge sentinel
could safely live in a target job.

Bad advice in a durable ledger is worse than no advice — someone would have
acted on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

* fix(issues): repair the duplicated table from the sixth main merge

Sixth conflict today, and the first that auto-merged *wrongly*: git's text
merge concatenated both tables, duplicating all 63 open rows. PR #1421 had
landed on main using #128/#129/#130 — the exact id collision #112 describes —
so both sides had those ids with different content and the merge kept both.

`npm run check:outstanding-issues` caught it and stated the correct resolution
verbatim: renumber the incoming rows above the marker and bump it, rather than
taking one side wholesale and dropping the other's rows. Done exactly that —
main's table is authoritative, this branch's four rows renumber to
#131/#132/#133/#134, marker to 135. Verified both sides' rows survive:
main's #128-#130 and mine are all present and distinct.

Worth noting main's new #129 (`update-branch` API does not honour the
`merge=ledger` driver) is the server-side twin of my #134 (the driver is absent
wherever `npm install` was skipped). Same root cause from two directions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Akwz3Sdms8uJ5AkDt3CduY

* docs: record PR 1424 review

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants