Context
Follow-up to #13556 / #13558 (the block-alignment lint v1 — import-from alignment, merged 2026-06-19). v1 explicitly documented object-literal colon + =-declaration-block alignment as fast-follows. Triggered now by an operator decision (@tobiu, 2026-06-19): build v1b so #13553 (embed-drain watchdog) can be fully mechanically reformatted — its intervals / hooks / enables object blocks have colon drift v1 cannot fix — closing the hand-formatting friction→gold completely (mechanize ALL the block-formatting basics, not just imports).
The Problem
v1 (buildScripts/util/check-block-alignment.mjs) aligns only import-from columns. Two house-style block patterns remain hand-done — exactly the mis-count-prone task v1 set out to kill:
- Object-literal colons: within a run of
key: value properties at one nesting level, the : aligns to a shared column (.github/CODING_GUIDELINES.md rule 2). A newly-added longer key silently breaks the block (e.g. #13553's embedDrainLivenessWatchdogCheck: in the intervals block; graphLogCompactionGetDueTask: in hooks).
= comma-blocks: within a single-keyword comma-block (a lone const/let/var line + its indented name = value continuations), the = aligns to a shared column (rule 35).
The Architectural Reality
- Extend the existing
buildScripts/util/check-block-alignment.mjs (v1) — same check + --fix shape, same conservative group-detection (a run of ≥ 2 consecutive alignable lines at the same indent; any non-conforming line breaks the run → no false positives), same pure/injectable column math (mirror evaluateImportAlignment).
- House-style SoT =
.github/CODING_GUIDELINES.md (rule 2 colon-align; rule 35 =-align). The = aligner scopes ONLY to the single-keyword comma-block (rule 35's unit) — see the Scope Refinement note below for why separate consecutive declarations are NOT grouped.
The Fix
Add to check-block-alignment.mjs:
- Object-colon alignment: detect runs of
<indent>key: value lines sharing an indent within an object literal; align : to max(indent + keyLength). Group breaks on a non-key: line, a blank line, or an indent change. Only the property-key colon participates (ignore colons inside the value / strings). One nesting level at a time (nested objects re-group at their own indent). Computed [bracket] keys participate (the [isDescriptor] descriptor pattern).
= comma-block alignment: detect a lone const/let/var keyword line + its indented name = value continuations (the rule-35 comma-block); align their = to a shared column. Separate consecutive declarations and bare assignments are NOT grouped; a block-opening value ({/(/[) is excluded.
--fix rewrites both; check reports file:line + expected column. Idempotent.
Scope Refinement (post-validation, 2026-06-19)
Real-file validation (running check-mode across src/core/Base.mjs, src/Neo.mjs, ai/config.template.mjs, Orchestrator.spec.mjs) corrected the original = scope. The first draft proposed aligning = across adjacent same-indent declarations agnostic to comma-vs-repeat-keyword. Validation showed that over-groups unrelated statements (e.g. let a = …; const b = …; are distinct statements, not a rule-35 block). Resolution: the = aligner is scoped ONLY to the single-keyword comma-block. Two further false-positive classes were found + fixed the same way: a block-opening = value (cloneMap = {) is excluded; computed [isDescriptor] colon keys participate. The ACs below reflect the corrected (delivered) scope.
Acceptance Criteria
Out of Scope
- A whole-codebase re-alignment sweep (the lint runs on changed files; a one-time sweep is separate/optional — note: validation found widespread pre-existing over-padding, so a sweep is a likely follow-up).
- Internal alignment of multi-line property values (only the top-level key-colon / declaration-
= column).
- Aligning
= across separate consecutive declarations or bare assignments (only the single-keyword comma-block is the alignment unit — see Scope Refinement).
Avoided Traps
- Prettier / ESLint — Prettier STRIPS alignment by design (would obliterate the house style); ESLint
key-spacing{align} covers object-colons but not the =-block / import patterns and isn't wired. The Neo-native check is deliberate (per #13556).
- Aligning across blank lines / indent changes — would merge unrelated blocks; group strictly by contiguous same-indent runs.
- Force-grouping separate declarations — over-aligns unrelated statements (caught in validation); scope
= to the comma-block only.
Related
- Parent concept: #13556 (v1 lint, closed by #13558). v1: #13558 (merged). Consumer / reformat target: #13553 (embed-drain watchdog — operator-directed full reformat).
- House-style SoT:
.github/CODING_GUIDELINES.md (rules 2, 35).
Release classification
post-release (dev-experience / Agent-OS formatting hardening). Boardless.
Origin Session ID
64ee317e-53b6-4f76-8241-f4eade1c084d
Handoff Retrieval Hints
query_raw_memories: "block-alignment lint v1b object colon = declaration alignment"
- Builds on
buildScripts/util/check-block-alignment.mjs (v1, #13558).
Context
Follow-up to #13556 / #13558 (the block-alignment lint v1 — import-
fromalignment, merged 2026-06-19). v1 explicitly documented object-literal colon +=-declaration-block alignment as fast-follows. Triggered now by an operator decision (@tobiu, 2026-06-19): build v1b so #13553 (embed-drain watchdog) can be fully mechanically reformatted — itsintervals/hooks/enablesobject blocks have colon drift v1 cannot fix — closing the hand-formatting friction→gold completely (mechanize ALL the block-formatting basics, not just imports).The Problem
v1 (
buildScripts/util/check-block-alignment.mjs) aligns only import-fromcolumns. Two house-style block patterns remain hand-done — exactly the mis-count-prone task v1 set out to kill:key: valueproperties at one nesting level, the:aligns to a shared column (.github/CODING_GUIDELINES.mdrule 2). A newly-added longer key silently breaks the block (e.g. #13553'sembedDrainLivenessWatchdogCheck:in theintervalsblock;graphLogCompactionGetDueTask:inhooks).=comma-blocks: within a single-keyword comma-block (a loneconst/let/varline + its indentedname = valuecontinuations), the=aligns to a shared column (rule 35).The Architectural Reality
buildScripts/util/check-block-alignment.mjs(v1) — samecheck+--fixshape, same conservative group-detection (a run of ≥ 2 consecutive alignable lines at the same indent; any non-conforming line breaks the run → no false positives), same pure/injectable column math (mirrorevaluateImportAlignment)..github/CODING_GUIDELINES.md(rule 2 colon-align; rule 35=-align). The=aligner scopes ONLY to the single-keyword comma-block (rule 35's unit) — see the Scope Refinement note below for why separate consecutive declarations are NOT grouped.The Fix
Add to
check-block-alignment.mjs:<indent>key: valuelines sharing an indent within an object literal; align:tomax(indent + keyLength). Group breaks on a non-key:line, a blank line, or an indent change. Only the property-key colon participates (ignore colons inside the value / strings). One nesting level at a time (nested objects re-group at their own indent). Computed[bracket]keys participate (the[isDescriptor]descriptor pattern).=comma-block alignment: detect a loneconst/let/varkeyword line + its indentedname = valuecontinuations (the rule-35 comma-block); align their=to a shared column. Separate consecutive declarations and bare assignments are NOT grouped; a block-opening value ({/(/[) is excluded.--fixrewrites both;checkreportsfile:line+ expected column. Idempotent.Scope Refinement (post-validation, 2026-06-19)
Real-file validation (running check-mode across
src/core/Base.mjs,src/Neo.mjs,ai/config.template.mjs,Orchestrator.spec.mjs) corrected the original=scope. The first draft proposed aligning=across adjacent same-indent declarations agnostic to comma-vs-repeat-keyword. Validation showed that over-groups unrelated statements (e.g.let a = …; const b = …;are distinct statements, not a rule-35 block). Resolution: the=aligner is scoped ONLY to the single-keyword comma-block. Two further false-positive classes were found + fixed the same way: a block-opening=value (cloneMap = {) is excluded; computed[isDescriptor]colon keys participate. The ACs below reflect the corrected (delivered) scope.Acceptance Criteria
checkflags +--fixaligns object-literal colon blocks (≥ 2 same-indentkey:lines, incl. computed[bracket]keys) to one column; lone/broken runs untouched.checkflags +--fixaligns the=of a single-keyword comma-block (a lone keyword line + ≥ 2 indentedname = valuecontinuations) to one column. Separate consecutive declarations and bare assignments are NOT grouped; a block-opening ({/(/[) value is excluded.=inside string or value content are ignored.--fixis idempotent (a second run changes nothing).--fix→ aligned + idempotent; lone / nested / broken → skipped; separate-declarations-NOT-grouped; computed-key / block-opening regression guards), constructed WITHOUT hand-aligned fixtures (derive the aligned form via--fix, mirroring v1's spec discipline).--fixon #13553's changed files yields a fully-aligned result (imports via v1, objects/=via v1b).Out of Scope
=column).=across separate consecutive declarations or bare assignments (only the single-keyword comma-block is the alignment unit — see Scope Refinement).Avoided Traps
key-spacing{align}covers object-colons but not the=-block / import patterns and isn't wired. The Neo-native check is deliberate (per #13556).=to the comma-block only.Related
.github/CODING_GUIDELINES.md(rules 2, 35).Release classification
post-release (dev-experience / Agent-OS formatting hardening). Boardless.
Origin Session ID
64ee317e-53b6-4f76-8241-f4eade1c084d
Handoff Retrieval Hints
query_raw_memories: "block-alignment lint v1b object colon = declaration alignment"buildScripts/util/check-block-alignment.mjs(v1, #13558).