From dca67a79a3763f8d030b94496cd0231be232f939 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 31 Jul 2026 04:19:11 -0700 Subject: [PATCH] fix(census): a DELIBERATE-LITERAL marker on a ternary arm was invisible (#3099) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## The gap The marker works above a statement or a function. It does **not** work in the position people actually use it — on the fallback arm itself, right beside the literal it excuses: ```ts flags ? flags.hold === true /* DELIBERATE-LITERAL — the no-metadata fallback. */ : column === "in-progress"; ``` That comment sits **before the `:` token**, so it's the colon's leading trivia rather than the arm expression's — `getLeadingCommentRanges` at the arm's full start never sees it. The ancestor walk doesn't rescue it either: the next ancestor is the `ConditionalExpression`, whose own leading comments are somewhere else entirely. ## Measured, not hypothesised `in-review-stall.ts` carried a marker in exactly this position **and stayed on the backlog**. The only way I could clear it was to restructure the code into a named set (#3064). That's the tool dictating shape rather than reading intent — and a marker that silently does nothing trains people to stop marking. Given this fleet phase has had several workers reach for `DELIBERATE-LITERAL` (#3056 used it successfully at statement level), the failure mode is one worker's marker working and another's not, for reasons neither can see. ## Scope and controls Scoped to the span between the previous arm (or the condition) and this one, so it can't pick up a comment belonging to anything else. Verified both directions with a probe: | case | before | after | |---|---|---| | marker above the statement | `deliberate` | `deliberate` | | marker on the ternary arm | **`column`** | `deliberate` | | unrelated marker on a neighbouring statement | `column` | `column` (unchanged) | **The real tree's count is unchanged at 51** — nothing is silently reclassified, because the one site that had an arm marker was already converted away. This is forward-looking. ## Not fixed here — pre-existing red on `main` `lifecycle-column-census.test.ts` has two failures (`expected 22 to be 26`, `expected +0 to be 1`) whose fixture arithmetic drifts with real tree counts as fleet conversions land. **Verified identical on `origin/main`** before and after this change, so it isn't mine — but someone should decide whether that fixture ought to be derived rather than pinned, since every fleet merge moves it. Co-authored-by: Claude Opus 5 (1M context) --- scripts/lib/lifecycle-column-census-ast.mjs | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/scripts/lib/lifecycle-column-census-ast.mjs b/scripts/lib/lifecycle-column-census-ast.mjs index 65094c46a4..ca8ca3fe53 100644 --- a/scripts/lib/lifecycle-column-census-ast.mjs +++ b/scripts/lib/lifecycle-column-census-ast.mjs @@ -213,6 +213,37 @@ function hasDeliberateMarker(sourceFile, node) { if (ranges.some((range) => fullText.slice(range.pos, range.end).includes(DELIBERATE_MARKER))) { return true; } + /* + FNXC:LifecycleColumnCensus 2026-07-31-19:10: + A TERNARY ARM'S OWN MARKER WAS INVISIBLE, which is the position people actually use. + + flags + ? flags.hold === true + /* DELIBERATE-LITERAL — the no-metadata fallback. *\/ + : column === "in-progress"; + + That comment sits before the `:` token, so it is the COLON's leading trivia, not the arm + expression's — `getLeadingCommentRanges` at the arm's full start never sees it. The ancestor walk + does not help either: the next ancestor is the ConditionalExpression, whose own leading comments + are somewhere else entirely. + + Measured before fixing: `in-review-stall.ts` carried a marker in exactly this position and stayed + on the backlog, and the only way to clear it was to restructure the code into a named set. That + is the tool dictating shape rather than reading intent — and a marker that silently does nothing + trains people to stop marking. + + Scoped to the span between the previous arm (or the condition) and this one, so it cannot pick up + a comment belonging to anything else. + */ + const parent = current.parent; + if (parent && ts.isConditionalExpression(parent)) { + const previousEnd = current === parent.whenFalse ? parent.whenTrue.end + : current === parent.whenTrue ? parent.condition.end + : undefined; + if (previousEnd !== undefined && fullText.slice(previousEnd, current.getStart()).includes(DELIBERATE_MARKER)) { + return true; + } + } current = current.parent; } return false;