LearnNewsExamplesServices
Frontmatter
id13556
titleMechanize block-formatting: a check-block-alignment lint + --fix
stateClosed
labels
enhancementaibuild
assigneesneo-opus-vega
createdAtJun 19, 2026, 4:53 PM
updatedAtJun 19, 2026, 6:30 PM
githubUrlhttps://github.com/neomjs/neo/issues/13556
authorneo-opus-vega
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 19, 2026, 6:30 PM

Mechanize block-formatting: a check-block-alignment lint + --fix

Closed v13.1.0/archive-v13-1-0-chunk-4 enhancementaibuild
neo-opus-vega
neo-opus-vega commented on Jun 19, 2026, 4:53 PM

Context

Operator friction→gold (@tobiu, 2026-06-19): while finishing #13551 / #13553 I hand-aligned Neo's block formatting (aligned import-from, object-literal colons, =-blocks) one block at a time — and mis-counted the off-by-one twice + missed whole blocks. @tobiu: "a frontier model should not do this — set up [a lint] to cover the block-formatting basics." Hand-aligning whitespace is negative-ROI + mis-count-prone by construction; the repeated friction (build agent mis-aligned → reviewer mis-aligned → still missed blocks) is the signal to mechanize.

The Problem

Neo's house style aligns columns within a block — import-from, object-literal colons, and = in adjacent declaration blocks. There is no mechanical enforcement today, so every contributor/agent hand-maintains the alignment — and that alignment is exactly the fiddly off-by-one a frontier model gets wrong (and humans tediously). Result: misaligned diffs + correction cycles + reviewer time spent on whitespace.

The Architectural Reality

  • The existing lint family lives in buildScripts/util/check-*.mjs (check-whitespace, check-shorthand, check-jsdoc-types, check-ticket-archaeology, …), run via husky pre-commit + CI. A check-block-alignment.mjs is a natural sibling (no novel directory).
  • House alignment patterns:
    • Import groups: consecutive single-line import … from align the from column to the widest clause in the group.
    • Object literals: consecutive key: value lines align the : (longest key sets the column; shorthand keys skipped).
    • Declaration blocks: adjacent const/let … = … align the = (see Open Question — convention differs by tree).

The Fix

Add buildScripts/util/check-block-alignment.mjs:

  • check mode (default): scan changed .mjs files, detect alignment groups, flag any from/:/= column that doesn't match its group target; emit a clear file:line + expected-column diagnostic. Wire into husky pre-commit + the CI lint job alongside the other check-*.
  • --fix mode: re-pad columns to the group target (idempotent). One --fix pass auto-cleans existing drift (e.g. #13551 / #13553).
  • v1 scope: import-from + object-literal colon alignment (unambiguous, highest-frequency). =-block alignment is a fast-follow pending the Open Question.

Decision Record impact

aligned-with ADR 0008 (skill/lint-as-substrate + the check-* Map/Atlas family). Substrate-Accretion-Defense: NET-REDUCES recurring formatting-correction friction (eliminates the hand-align error class) — that is the gate's justification.

Acceptance Criteria

  • buildScripts/util/check-block-alignment.mjs flags misaligned import-from + object-literal-colon groups in changed .mjs files with a clear file:line + expected-column diagnostic.
  • A --fix mode re-pads columns to the group target (idempotent on already-aligned files).
  • Wired into husky pre-commit + the CI lint job (the existing check-* invocation path).
  • Unit coverage: aligned-passes / misaligned-fails / --fix-corrects fixtures for both patterns.
  • Running --fix over the #13551 / #13553 branch cleans its remaining alignment drift.

Out of Scope

  • Reformatting the entire existing codebase (the check runs on CHANGED files; a repo-wide --fix sweep is a separate op).
  • =-declaration-block alignment if the Open Question isn't resolved in v1 (fast-follow).
  • Any non-alignment style (covered by the other check-* / lint).

Avoided Traps

  • Prettier. Rejected: opinionated AGAINST alignment — it strips aligned colons/=/from, obliterating Neo's signature aligned-block style + a massive de-aligning repo diff. Only viable if Neo deliberately abandons the aligned aesthetic (a separate, bigger call — not this ticket).
  • ESLint key-spacing alone. {align} handles object-colons but has no rule for import-from or =-block alignment — can't cover the house style; hence the Neo-native check.
  • Hand-alignment. The friction this eliminates: a frontier model (or human) counting padding by hand is error-prone (the #13551 off-by-ones, twice).

Open Question

The =-declaration-block convention differs by tree: ai/daemons/* uses separate-const-with-aligned-=; src/ canonical (core.Base / Accounts.mjs) uses single-const comma-blocks. v1 enforces the unambiguous import-from + object-colon patterns; the =-block rule needs a house-wide convention decision before enforcement (else the lint fights one of the two existing styles).

Related

  • Friction origin: #13551 / #13553 (the watchdog PR where the hand-alignment friction surfaced).
  • Sibling lint family: buildScripts/util/check-*.mjs.
  • Sibling friction→gold (same session): a config-freshness MC-boot guard (stale config-overlay → cryptic (reading 'enabled') crash) — filed separately.

Release classification: Agent OS dev-experience hardening — boardless.

Origin Session ID: 64ee317e-53b6-4f76-8241-f4eade1c084d

Retrieval Hint: query_raw_memories "block-alignment lint check-block-alignment Neo aligned-block style not Prettier"; the #13551/#13553 hand-alignment friction.

Authored by Claude Opus 4.8 (Claude Code), @neo-opus-vega (Vega).