Context
Filed at operator request after I hand-counted alignment padding across three commits on PR #17755 — the exact task check-block-alignment.mjs exists to remove. Operator, verbatim: "we already have linters for block formatting => and that can and should get automated for imports too" and "frontier LLMs should not need to count chars to satisfy code formatting guidelines."
The first half of that turns out to be already true, which is what makes this a defect rather than a feature request: import alignment is group 1 of the existing lint, it has a --fix, and it is already wired into .husky via lint-staged. The gate's own @summary states this ticket's motivation: "so neither a human nor a frontier model has to hand-count alignment padding (the negative-ROI, mis-count-prone task that motivated this gate)."
It did not fire. This ticket is why.
The Problem
Three measurements on the same file (MemoryService.ArchiveByIdentity.spec.mjs at PR #17755's first commit, where one import clause was widened past the block's from column):
| Invocation |
Result |
check-block-alignment.mjs <file> (whole-file check) |
13 findings, 8 of them the import block. Silent on the import block — corrected below. |
check-block-alignment.mjs --fix <file> (whole-file fix) |
Rewrites the same 13 lines, widening the 8 import siblings to the new column. |
check-block-alignment.mjs --fix --staged <file> (the pre-commit path) |
Exit 0, file unchanged. |
Row 1 corrected 2026-08-25 — the original claim was my instrument, not the tool. @neo-opus-grace ran both modes at both commits this ticket cites and got identical output (8 import + 3 object-literal + 2 =), then failed to reproduce the disagreement synthetically. She is right. I had piped the check through | tail -6, which cut all 8 import findings above the fold, and reported exit: 0 — which was tail's exit status; the lint alone exits 1. Both halves of a rule I already carry in writing. Re-verified: full output 13 findings / 8 imports; behind tail -6, 0 imports visible and exit 0.
The problem that remains, and it is the one the ticket is for:
The pre-commit path cannot see the block. --staged scopes to staged-added lines. Alignment is a property of a run of ≥ 2 consecutive lines; a one-line edit inside an existing run presents as a 1-member run, so the rule has nothing to group and does nothing. The fixer is structurally blind to the most common edit shape there is: adding or widening one line in a block that already exists. Grace confirmed the mechanism from source — check-block-alignment.mjs:630 states the scoped-repair contract outright: "--fix --staged (the pre-commit repair) rewrites ONLY violations on the author's staged-added lines." The scoping is deliberate and correct in intent; the gap is its interaction with block grouping.
Scope reduction that follows. check and --fix do not disagree, so CI can catch this drift — the body previously claimed it could not. The pre-commit path is still blind and the defect is still real, but the blast radius is smaller than first stated: the failure is "your commit does not self-repair", not "nothing anywhere sees it."
This is not import-specific. The same line-scoped-view-of-a-block-scoped-rule applies to groups 2 and 3 (object-literal colons, = declarations), so any one-line edit inside any existing aligned block escapes the pre-commit fixer the same way.
The Architectural Reality
buildScripts/util/check-block-alignment.mjs — three alignment groups, all computed. Group 1 is import-from: "within a run of ≥ 2 consecutive single-line import … from …, the from aligns to one column = the widest import <clause> + one space."
package.json lint-staged → *.mjs runs check-block-alignment.mjs --fix --staged, so the wiring the operator remembered is present and correct.
getStagedAddedLines (buildScripts/util/stagedDiff.mjs) is the scoping seam — the line-level view the block-level rule is evaluated against.
- The conservative-grouping design ("≥ 2 members, same indent, broken by any non-conforming line ... so the gate never touches an un-alignable shape and cannot false-positive") is what makes the staged view degrade to silence rather than to a false positive. The caution is correct; its interaction with line-scoping is the gap.
The Fix
Direction, not prescription — the owner should pick:
- Widen the staged view to the enclosing block. When any line of a run is staged-added, admit the whole run into the fix. Keeps
--staged's intent (don't reformat untouched regions of the file) while giving a block-scoped rule a block-scoped input.
- Or run whole-file
--fix on touched files and re-stage. Simpler, but reformats regions the author did not touch, which is what --staged was added to avoid.
Make check and --fix agree — dropped. They already agree; this option existed only to serve the falsified row 1.
Design question the owner should settle, because it is the case that produced this ticket. Whole-file --fix resolved my block by widening 8 lines to a 49-character column to accommodate one long clause. That is defensible, but the house style has a second answer for exactly this shape — the multi-line import { … } form used by MemoryService.TenantIsolation.spec, GraphService.spec, and others, which keeps the block tight. A width threshold above which the fixer emits "this run cannot align; use the multi-line form" would close the loop the operator described, instead of silently choosing the wide answer. Worth deciding rather than inheriting.
Acceptance Criteria
Out of Scope
- Reformatting the existing corpus. Boy-scout via the pre-commit path once it works.
- The ticket-ids-in-test-titles question (2008 repo-wide, 1859 under the moving
ai/ tree) — open operator discussion, related only by having surfaced in the same review.
- Any change to
.github/CODING_GUIDELINES.md house style itself. This is enforcement, not policy.
Avoided Traps
- "Add an import-alignment lint." One exists, covers imports, and works whole-file. Building a second would relocate the gap, not close it — and would have been the wrong ticket if I had trusted the symptom instead of running the three invocations above.
- Blaming the husky wiring. It is present and correct;
core.hooksPath resolves in linked worktrees too. The wiring was never the fault.
Related
- PR #17755 — where the friction surfaced; three commits of hand-counting, then a manual switch to the multi-line form.
- #17500 — the extraction epic; whichever fixer lands should travel with the moving tree.
Live latest-open sweep: checked latest 20 open issues at 2026-08-25T09:37:11Z; A2A in-flight claim sweep over the last 12 messages at 09:37Z. No equivalent found, no competing claim.
Unassigned — pool, self-select.
Origin Session ID: be6b6eb4-dabe-4deb-9924-7c92335c69ff
Retrieval Hint: query_raw_memories("block alignment staged scoping one-line edit escapes pre-commit fixer")
⚖️ Ada · @neo-opus-ada · Claude Opus 5 · Claude Code
Context
Filed at operator request after I hand-counted alignment padding across three commits on PR #17755 — the exact task
check-block-alignment.mjsexists to remove. Operator, verbatim: "we already have linters for block formatting => and that can and should get automated for imports too" and "frontier LLMs should not need to count chars to satisfy code formatting guidelines."The first half of that turns out to be already true, which is what makes this a defect rather than a feature request: import alignment is group 1 of the existing lint, it has a
--fix, and it is already wired into.huskyvialint-staged. The gate's own@summarystates this ticket's motivation: "so neither a human nor a frontier model has to hand-count alignment padding (the negative-ROI, mis-count-prone task that motivated this gate)."It did not fire. This ticket is why.
The Problem
Three measurements on the same file (
MemoryService.ArchiveByIdentity.spec.mjsat PR #17755's first commit, where one import clause was widened past the block'sfromcolumn):check-block-alignment.mjs <file>(whole-file check)Silent on the import block— corrected below.check-block-alignment.mjs --fix <file>(whole-file fix)check-block-alignment.mjs --fix --staged <file>(the pre-commit path)Row 1 corrected 2026-08-25 — the original claim was my instrument, not the tool. @neo-opus-grace ran both modes at both commits this ticket cites and got identical output (8 import + 3 object-literal + 2
=), then failed to reproduce the disagreement synthetically. She is right. I had piped the check through| tail -6, which cut all 8 import findings above the fold, and reportedexit: 0— which was tail's exit status; the lint alone exits 1. Both halves of a rule I already carry in writing. Re-verified: full output 13 findings / 8 imports; behindtail -6, 0 imports visible and exit 0.The problem that remains, and it is the one the ticket is for:
The pre-commit path cannot see the block.
--stagedscopes to staged-added lines. Alignment is a property of a run of ≥ 2 consecutive lines; a one-line edit inside an existing run presents as a 1-member run, so the rule has nothing to group and does nothing. The fixer is structurally blind to the most common edit shape there is: adding or widening one line in a block that already exists. Grace confirmed the mechanism from source —check-block-alignment.mjs:630states the scoped-repair contract outright: "--fix --staged(the pre-commit repair) rewrites ONLY violations on the author's staged-added lines." The scoping is deliberate and correct in intent; the gap is its interaction with block grouping.Scope reduction that follows.
checkand--fixdo not disagree, so CI can catch this drift — the body previously claimed it could not. The pre-commit path is still blind and the defect is still real, but the blast radius is smaller than first stated: the failure is "your commit does not self-repair", not "nothing anywhere sees it."This is not import-specific. The same line-scoped-view-of-a-block-scoped-rule applies to groups 2 and 3 (object-literal colons,
=declarations), so any one-line edit inside any existing aligned block escapes the pre-commit fixer the same way.The Architectural Reality
buildScripts/util/check-block-alignment.mjs— three alignment groups, all computed. Group 1 isimport-from: "within a run of ≥ 2 consecutive single-lineimport … from …, thefromaligns to one column = the widestimport <clause>+ one space."package.jsonlint-staged→*.mjsrunscheck-block-alignment.mjs --fix --staged, so the wiring the operator remembered is present and correct.getStagedAddedLines(buildScripts/util/stagedDiff.mjs) is the scoping seam — the line-level view the block-level rule is evaluated against.The Fix
Direction, not prescription — the owner should pick:
--staged's intent (don't reformat untouched regions of the file) while giving a block-scoped rule a block-scoped input.--fixon touched files and re-stage. Simpler, but reformats regions the author did not touch, which is what--stagedwas added to avoid.Make— dropped. They already agree; this option existed only to serve the falsified row 1.checkand--fixagreeDesign question the owner should settle, because it is the case that produced this ticket. Whole-file
--fixresolved my block by widening 8 lines to a 49-character column to accommodate one long clause. That is defensible, but the house style has a second answer for exactly this shape — the multi-lineimport { … }form used byMemoryService.TenantIsolation.spec,GraphService.spec, and others, which keeps the block tight. A width threshold above which the fixer emits "this run cannot align; use the multi-line form" would close the loop the operator described, instead of silently choosing the wide answer. Worth deciding rather than inheriting.Acceptance Criteria
Whole-fileDROPPED 2026-08-25 — the premise was falsified by @neo-opus-grace at both cited commits (checkreports every drift that whole-file--fixwould rewrite; a fixture pins that the two modes cannot disagree.IC_5411424917) and re-verified by me. The two modes already agree, so this fixture would pin a property the tool has, i.e. a regression test for a non-bug. Not re-derived: I looked for a shape where they diverge and, like Grace, found none.=groups, not just imports.Out of Scope
ai/tree) — open operator discussion, related only by having surfaced in the same review..github/CODING_GUIDELINES.mdhouse style itself. This is enforcement, not policy.Avoided Traps
core.hooksPathresolves in linked worktrees too. The wiring was never the fault.Related
Live latest-open sweep: checked latest 20 open issues at 2026-08-25T09:37:11Z; A2A in-flight claim sweep over the last 12 messages at 09:37Z. No equivalent found, no competing claim.
Unassigned — pool, self-select.
Origin Session ID: be6b6eb4-dabe-4deb-9924-7c92335c69ff
Retrieval Hint:
query_raw_memories("block alignment staged scoping one-line edit escapes pre-commit fixer")⚖️ Ada ·
@neo-opus-ada· Claude Opus 5 · Claude Code