diff --git a/packages/core/src/__tests__/project-lane-vocabulary.test.ts b/packages/core/src/__tests__/project-lane-vocabulary.test.ts index 6d7200ef90..63a0ef8b6b 100644 --- a/packages/core/src/__tests__/project-lane-vocabulary.test.ts +++ b/packages/core/src/__tests__/project-lane-vocabulary.test.ts @@ -9,11 +9,15 @@ impossible one for a read: await store.listTasks({ column: "in-review" }) // there is no task to resolve from yet -#2800 measured the consequence: `self-healing.ts` alone issues 49 such reads, and on a renamed board +#2800 measured the consequence: `self-healing.ts` alone issued 49 such reads, and on a renamed board every one returns an EMPTY array, so the sweep never executes. The census scores the comparison INSIDE the loop, not the query above it — so converting those comparisons drops a count while the loop body stays unreachable. In that file the census total is not a floor; it is misleading. +The 49 is dated, not fixed: 37 as of this writing, and falling as the fleet converts them. Regenerate +with `node scripts/lifecycle-column-census.mjs --json` (`queryByFile`, `queryRoles`) rather than +trusting the figure — an un-reproducible count is how a comment starts lying about another file. + WHAT THIS MODULE IS FOR. It gives the query class one shared answer instead of each site inventing its own. I wrote this logic once inline for the legacy auto-merge stamp backfill; a second copy is how two readers of the same fact begin to disagree. diff --git a/packages/core/src/project-lane-vocabulary.ts b/packages/core/src/project-lane-vocabulary.ts index 2c8f58cf43..2a720f892c 100644 --- a/packages/core/src/project-lane-vocabulary.ts +++ b/packages/core/src/project-lane-vocabulary.ts @@ -8,11 +8,17 @@ and the wrong shape for a QUERY, because a query runs before any task is in hand await store.listTasks({ column: "in-review" }) // ← nothing to resolve from -`#2800` measured the cost: `self-healing.ts` alone issues 49 such reads, and on a board whose lanes +`#2800` measured the cost: `self-healing.ts` alone issued 49 such reads, and on a board whose lanes are renamed every one returns an EMPTY array, so the sweep it feeds never executes. The census scores the comparison inside the loop, not the query above it, so converting those comparisons drops a count and changes nothing an operator can observe — the loop body was already unreachable. +That 49 is a MEASUREMENT WITH A DATE, not a constant: it was 37 at the time of writing and falls as +the fleet converts them. Reproduce rather than trust it — +`node scripts/lifecycle-column-census.mjs --json` reports `queryByFile` and `queryRoles`. Quoting a +hand-counted figure with no way to regenerate it is how a note starts lying about another file, which +this program has now corrected twice in comments that were true when written. + Fixing a query needs a different answer: not "this task's lane" but "every column ANY workflow in this project declares for this role". That is what this module returns, and it is deliberately shared rather than re-derived per call site — I wrote this logic once inline for the legacy auto-merge stamp diff --git a/packages/core/src/workflow-lifecycle-traits.ts b/packages/core/src/workflow-lifecycle-traits.ts index 2298f3c282..369c9c4616 100644 --- a/packages/core/src/workflow-lifecycle-traits.ts +++ b/packages/core/src/workflow-lifecycle-traits.ts @@ -395,12 +395,25 @@ MOVE-TARGET resolvers, kept beside `resolveTaskLifecycleColumns` because they an for the other half of a conversion. The lifecycle-column census is an AST scan for COMPARISONS, so a `moveTask` DESTINATION — a call -argument — is invisible to it. 51 such destinations exist in production; 22 deliberately pass -`recoveryRehome: true` (the #1411 legacy safe-landing escape, which must not be converted), and the rest -are rejected outright on a board that does not declare the target now that U12 hoisted the -`workflowHasColumn` check out of its dead flag-gated branch. See +argument — is invisible to it. A share of those deliberately pass `recoveryRehome: true` (the #1411 +legacy safe-landing escape, which must not be converted); the rest are rejected outright on a board +that does not declare the target, now that U12 hoisted the `workflowHasColumn` check out of its dead +flag-gated branch. See `docs/solutions/architecture-patterns/hardcoded-movetask-destinations-are-census-invisible.md`. +THE COUNTS THAT USED TO BE HERE ARE GONE ON PURPOSE. This note read "51 such destinations exist in +production; 22 deliberately pass `recoveryRehome: true`". Both were true when measured and neither is +now — the program has been converting them since — and unlike the census totals there is no command +that regenerates these, so the figures could only rot. A comment that states an un-reproducible count +about other files is a comment that will eventually lie; the shape is what matters here, and the +current numbers are one grep away: + + grep -rnE 'moveTask\([^,]+, *"(todo|in-progress|in-review|done|archived|triage)"' packages \ + --include='*.ts' | grep -v __tests__ + +(approximate — it sees single-line call sites only, which is precisely why it was never a total worth +pinning in prose). + Both fall back to the legacy id: `resolveWorkflowIrForTask` degrades to the BUILT-IN IR rather than throwing, so a board whose workflow cannot be read behaves exactly as before.