Centralize workflow column sorting in core and remove the duplicate dashboard implementation. - Export shared display-column sort options and complete-column modes from core. - Route board, lane, list, and column consumers through the shared sorter. - Harden inert flag seam checks for same-named module functions. Files changed: .../display-ranking-roles-resolved.test.ts | 6 +- packages/core/src/__tests__/task-priority.test.ts | 63 +++++++ packages/core/src/index.gate.ts | 2 + packages/core/src/index.ts | 2 + packages/core/src/tasks/task-priority.ts | 87 +++++---- packages/core/src/types.ts | 9 + packages/dashboard/app/components/Board.tsx | 45 +---- packages/dashboard/app/components/Column.tsx | 4 +- packages/dashboard/app/components/Lane.tsx | 34 +--- packages/dashboard/app/components/ListView.tsx | 19 +- .../app/components/__tests__/Lane.test.tsx | 8 +- .../app/components/__tests__/taskSorting.test.ts | 201 --------------------- packages/dashboard/app/components/taskSorting.ts | 138 -------------- scripts/__tests__/check-inert-flag-seams.test.mjs | 4 +- scripts/check-inert-flag-seams.mjs | 83 +++------ 15 files changed, 177 insertions(+), 528 deletions(-) Fusion-Task-Id: FN-8770 Fusion-Task-Lineage: 81740c52-0a3c-44df-9fbb-addaefdfeb82 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
552 lines
28 KiB
JavaScript
552 lines
28 KiB
JavaScript
#!/usr/bin/env node
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:50:
|
|
BLOCK NEW INERT CONVERSIONS — an optional trailing lane/flag parameter that no caller supplies.
|
|
|
|
The lifecycle-column program replaces `column === "done"` with a resolved-role read. A conversion
|
|
that adds the parameter and never wires a caller is WORSE than the literal:
|
|
|
|
tsc passes the parameter is optional, so omitting it is legal
|
|
tests pass the fallback IS the old behaviour — that is what the fallback is for
|
|
the census DROPS it counts comparisons, and the literal really is gone
|
|
|
|
So the instrument measuring the program scores the broken version as a win. Measured rate when this
|
|
check was written: five of nine conversions in one reviewed-and-green tranche were inert.
|
|
|
|
WHAT IT CHECKS. Exported functions whose LAST parameter is optional and named like resolved lanes
|
|
(`columnFlags`, `lifecycleColumns`, `reviewColumns`, `displayColumnOptions`, ...). At least one call site must pass that many
|
|
arguments. Component props are covered separately by
|
|
`packages/dashboard/app/__tests__/resolved-flags-seams-have-suppliers.test.ts`.
|
|
|
|
LIMITS, STATED SO NOBODY OVER-TRUSTS IT. Relative imports and local shadows resolve to the declaring
|
|
module, but unresolved calls remain a conservative name match; treat a report as a pointer to
|
|
investigate, never as a diff to apply. Tests are tracked separately from production so test-only
|
|
suppliers cannot clear a seam. It proves a caller passes SOMETHING in that position, not that the
|
|
value is correct or non-undefined. Cheap half of the question; it is the half that was silently wrong.
|
|
|
|
TO CLEAR A FAILURE: wire a supplier, or delete the parameter and leave the literal counted. Adding an
|
|
allow-list entry is the last resort and needs the reason spelled out.
|
|
*/
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join, relative, resolve, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import ts from "typescript";
|
|
|
|
const REPO = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
/*
|
|
FNXC:InertFlagSeams 2026-07-30-23:30:
|
|
`plugins/` IS SCANNED, because plugins hold real lane logic and this gate could not see any of it.
|
|
|
|
The walk was rooted at `packages/` alone. Measured with a control: the identical unwired seam is
|
|
caught under `packages/` and MISSED under `plugins/` — so every lane parameter a plugin declares or
|
|
calls was outside the ratchet entirely.
|
|
|
|
Not hypothetical. `plugins/fusion-plugin-even-realities-glasses` resolves workflow IRs and filters by
|
|
column in `src/cards.ts` and `src/routes/board-routes.ts`. The sibling `check-lane-wiring` already
|
|
lists `plugins` in its roots, and its header records the incident that put it there: an unwired
|
|
`completeColumnsByTaskId` sat on `main` unreported because that plugin was not scanned. This gate
|
|
re-opened the same hole rather than learning from it.
|
|
|
|
Found while auditing my own gates after #3000 showed this one never scanned `scripts/` either. Two
|
|
scope holes in one instrument is a pattern: the roots deserve the same scrutiny as the matcher, and
|
|
they had none.
|
|
*/
|
|
const SCAN_ROOTS = [join(REPO, "packages"), join(REPO, "plugins")];
|
|
const SKIP_DIRS = new Set(["node_modules", "dist", "__tests__", "__mocks__", "e2e", ".gate-bundle", "coverage"]);
|
|
const TRAILING_FLAG_PARAM = /([Cc]olumnFlags|[Ll]ifecycleColumns|[Rr]eviewColumns|[Tt]erminalColumns|[Pp]lannerLanes|[Dd]isplayColumnOptions)$/;
|
|
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:40:
|
|
PASSING `undefined` FOR THE LANE ANSWER IS NOT SUPPLYING IT.
|
|
|
|
The seam is a trailing optional parameter, so this gate asked how many ARGUMENTS each call site
|
|
passes. A call that spells the omission out —
|
|
|
|
resolveSomething("KB-1", undefined)
|
|
|
|
— satisfies that count while the callee receives exactly what it received before: nothing. The
|
|
parameter is still inert and the board still reads the legacy vocabulary.
|
|
|
|
That spelling is not exotic. It is what a partial wiring-up produces when the flags are threaded
|
|
through an intermediate that has none to pass, and what a mechanical edit produces when it fills
|
|
argument slots positionally. Either way the gate reported the seam as answered.
|
|
|
|
Missed by BOTH gates: check-lane-wiring (#2966) covers the default-valued and options-object shapes
|
|
this one is structurally blind to, but it counts arguments the same way here. Found by probing my own
|
|
gate with shapes I had not designed it for — the discipline argued for in #2979.
|
|
|
|
TRAILING ONLY. A middle `undefined` still positions the arguments after it, so those are real answers.
|
|
*/
|
|
const isUndefinedArgument = (arg) =>
|
|
(ts.isIdentifier(arg) && arg.text === "undefined") || ts.isVoidExpression(arg);
|
|
|
|
/** Arguments that actually carry a value, ignoring trailing `undefined` / `void 0` placeholders. */
|
|
export function effectiveArgCount(args) {
|
|
let count = args.length;
|
|
while (count > 0 && isUndefinedArgument(args[count - 1])) count -= 1;
|
|
return count;
|
|
}
|
|
|
|
/** Unanchored twin used only to skip files fast; see the note at the call site. */
|
|
const PREFILTER = /(olumnFlags|ifecycleColumns|eviewColumns|erminalColumns|lannerLanes|isplayColumnOptions)/;
|
|
|
|
/** Known-unsupplied seams, each with why it is tolerated. Shrink this list; never grow it casually. */
|
|
const ALLOWED = new Map([
|
|
/*
|
|
TEMPORARY — real offenders in packages owned by other batches, reported to them rather than edited
|
|
from outside. Remove each entry when that batch wires or deletes the parameter; the check will then
|
|
start guarding those files too. All three are the same shape this check exists to catch.
|
|
*/
|
|
[
|
|
"isRecoverableMissingWorktreeReviewFailure",
|
|
"No production caller; 5 test call sites. The previous entry blamed the scanner for excluding "
|
|
+ "__tests__ — that reason was wrong, the scan now reads tests and the count is real. The two "
|
|
+ "SIBLINGS it delegates to (`...WithProgress` / `...NoProgress`) are the live pair, called from "
|
|
+ "self-healing.ts and both supplying `reviewColumns`. This is the convenience wrapper over them, "
|
|
+ "kept as a public predicate and exercised only by its own tests. Engine-owned; left alone.",
|
|
],
|
|
|
|
|
|
]);
|
|
|
|
/*
|
|
PARTIAL-SUPPLY exemptions are keyed by CALL SITE, not by function name.
|
|
|
|
A name-level entry would waive every call site of the seam at once, which is the opposite of what a
|
|
partially-supplied seam needs: the whole point is that its OTHER sites are correct and must stay
|
|
guarded. `<file>::<function>` keeps the exemption to the one site whose omission is deliberate.
|
|
|
|
An omission earns an entry only when supplying the argument would be WRONG, not when it is awkward.
|
|
"Awkward" means wire it; the check exists to make that the cheaper path.
|
|
*/
|
|
const ALLOWED_OMISSIONS = new Map([
|
|
]);
|
|
|
|
/*
|
|
TEST CALL SITES ARE COLLECTED, AND COUNTED SEPARATELY FROM PRODUCTION ONES.
|
|
|
|
Excluding `__tests__` outright made a test-only export read as having NO callers. But naively
|
|
including tests is worse: a test that supplies the argument would clear a seam no production caller
|
|
supplies. So the two are tracked apart. "Supplied" means supplied by PRODUCTION. Test callers answer
|
|
a different and also useful question: is this function reachable at all, or is the export dead?
|
|
*/
|
|
const TEST_DIRS = new Set(["__tests__", "__mocks__", "e2e"]);
|
|
const isTestFile = (file) => file.split("/").some((segment) => TEST_DIRS.has(segment))
|
|
|| /\.(test|spec)\.tsx?$/.test(file);
|
|
|
|
function* walkAll(dir) {
|
|
for (const entry of readdirSync(dir)) {
|
|
if (entry === "node_modules" || entry === "dist" || entry === ".gate-bundle" || entry === "coverage") continue;
|
|
const full = join(dir, entry);
|
|
if (statSync(full).isDirectory()) yield* walkAll(full);
|
|
else if (/\.tsx?$/.test(full) && !/\.d\.ts$/.test(full)) yield full;
|
|
}
|
|
}
|
|
|
|
function* walk(dir) {
|
|
for (const entry of readdirSync(dir)) {
|
|
if (SKIP_DIRS.has(entry)) continue;
|
|
const full = join(dir, entry);
|
|
if (statSync(full).isDirectory()) yield* walk(full);
|
|
else if (/\.tsx?$/.test(full) && !/\.d\.ts$/.test(full)) yield full;
|
|
}
|
|
}
|
|
|
|
const declared = new Map();
|
|
const callSites = new Map();
|
|
|
|
/*
|
|
CALL SITES ARE COLLECTED FROM EVERY FILE, DECLARATIONS ONLY FROM CANDIDATES.
|
|
|
|
The prefilter must NOT gate call-site collection, and that was a real hole rather than a tidy-up: a
|
|
caller that OMITS the flags argument mentions no flag name, so a prefiltered scan skipped exactly the
|
|
files containing the omissions it exists to find. It saw only the callers that already pass the
|
|
argument, concluded "supplied", and stayed green. That is why this gate did not catch `isTaskStuck`'s
|
|
missing suppliers in ListView and Column — review did.
|
|
|
|
Declarations still use the prefilter: a file DECLARING a flags parameter necessarily contains the
|
|
name, so that half is safe and keeps the scan quick.
|
|
*/
|
|
for (const file of SCAN_ROOTS.flatMap((root) => [...walkAll(root)])) {
|
|
const source = readFileSync(file, "utf8");
|
|
const fileIsTest = isTestFile(relative(REPO, file).split("\\").join("/"));
|
|
const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
const declares = PREFILTER.test(source);
|
|
|
|
/*
|
|
LOCAL SHADOWS ARE NOT CALLS TO THE SEAM. A same-named local function can produce a false report or
|
|
mask a real omission by raising the global maximum argument count, so calls are attributed locally
|
|
before the generic matcher runs.
|
|
|
|
So a file that declares its own function with that name has its calls attributed to the local one.
|
|
|
|
IMPORTED shadows are handled separately, below — that limitation is now closed.
|
|
|
|
Two ways of matching by NAME remain: the one-supplier floor (any single caller passing the argument
|
|
clears the seam, even if ten others omit it) and the test-exclusion (a function exported only for
|
|
tests reads as having no callers, hence the two permanent ALLOWED entries).
|
|
*/
|
|
/*
|
|
IMPORTED SHADOWS, RESOLVED. Recording the module each callee was imported FROM lets a call be
|
|
matched to the seam's actual declaring file instead of a same-named export elsewhere. This avoids
|
|
both false reports and the worse failure: an unrelated call with more arguments masking an
|
|
under-supplied seam.
|
|
*/
|
|
const { importedFrom, localAlias } = collectImportBindings(sf);
|
|
|
|
const locallyDeclared = new Set();
|
|
const collectLocal = (node) => {
|
|
if ((ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) && node.name) locallyDeclared.add(node.name.text);
|
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer
|
|
&& (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
|
|
locallyDeclared.add(node.name.text);
|
|
}
|
|
ts.forEachChild(node, collectLocal);
|
|
};
|
|
collectLocal(sf);
|
|
|
|
const visit = (node) => {
|
|
if (declares && ts.isFunctionDeclaration(node) && node.name && node.parameters.length > 0) {
|
|
/* `exported` matches this file's stated contract; a module-private helper is not a seam
|
|
other packages can under-supply. */
|
|
const exported = node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) === true;
|
|
const last = node.parameters[node.parameters.length - 1];
|
|
if (!fileIsTest && exported && last.questionToken && ts.isIdentifier(last.name) && TRAILING_FLAG_PARAM.test(last.name.text)) {
|
|
declared.set(node.name.text, { file: relative(REPO, file), arity: node.parameters.length });
|
|
}
|
|
}
|
|
if (ts.isCallExpression(node)) {
|
|
const callee = ts.isIdentifier(node.expression) ? node.expression.text
|
|
: ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : null;
|
|
/*
|
|
Record the call WITH the file it came from; whether a local shadow disqualifies it cannot be
|
|
decided here, because the seam's declaring file is not known until every file is scanned.
|
|
Deciding it inline used a file-level "mentions a flag name" flag, which any COMMENT sets — so a
|
|
shadow in a file that merely discussed flags still counted, and the probe test caught that.
|
|
*/
|
|
if (callee) {
|
|
/* Attribute the call to the EXPORTED name when it came in under an alias. */
|
|
const target = localAlias.get(callee) ?? callee;
|
|
if (!callSites.has(target)) callSites.set(target, []);
|
|
callSites.get(target).push({
|
|
file: relative(REPO, file),
|
|
args: effectiveArgCount(node.arguments),
|
|
shadowed: locallyDeclared.has(callee),
|
|
from: importedFrom.get(callee),
|
|
viaProperty: ts.isPropertyAccessExpression(node.expression),
|
|
isTest: fileIsTest,
|
|
});
|
|
}
|
|
}
|
|
ts.forEachChild(node, visit);
|
|
};
|
|
visit(sf);
|
|
}
|
|
|
|
/*
|
|
A call in a file that declares its OWN function of the same name belongs to that local one, unless the
|
|
file is where the seam itself is declared. Resolved here, once the declaring file for each seam is
|
|
known.
|
|
*/
|
|
const callSitesFor = (fn, declaringFile) =>
|
|
(callSites.get(fn) ?? []).filter((site) => isRelevantCallSite(site, declaringFile));
|
|
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:20 (#2851 review — greptile, "call classification lacks
|
|
regression coverage"):
|
|
|
|
EXTRACTED SO THE CLASSIFICATION CAN BE TESTED WITHOUT WALKING THE REPO.
|
|
|
|
The alias remapping and the property-access exclusion were both added to fix REAL failures: one had
|
|
the gate reporting `enqueueMergeQueue() — best call passes 2 of 5` while its only production caller
|
|
supplied all five through an alias; the other had it red on main over two call sites that are
|
|
correct. Neither had a test, so the next edit could restore either false positive silently — and both
|
|
are the kind of rule whose breakage reads as the gate merely having an opinion, which is how a guard
|
|
trains its readers to skip it.
|
|
|
|
Pure by construction: it takes one recorded site plus the declaring file and returns a boolean. The
|
|
walk still produces the sites; this decides what they mean, which is the half with the rules in it.
|
|
*/
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:55 (#2851 review — the OTHER half the finding named):
|
|
|
|
EXPORTED SO THE ALIAS DIRECTION IS TESTABLE, because the direction is the whole risk.
|
|
|
|
In the TypeScript AST an `ImportSpecifier` for `import { a as b }` holds the EXPORTED name in
|
|
`propertyName` and the LOCAL name in `name`. Reading them the other way round still produces a
|
|
populated map and still type-checks — it just maps the wrong way, and the gate then attributes calls
|
|
to a name nothing declares. That is not hypothetical: removing a stale exemption surfaced
|
|
`enqueueMergeQueue() — best call passes 2 of 5` while its ONLY production caller passed all five
|
|
through an alias.
|
|
|
|
Returns both maps because they are populated from the same walk over the same specifiers; splitting
|
|
them would mean two walks that could disagree about which imports exist.
|
|
|
|
Returns: `importedFrom` maps local name -> module specifier; `localAlias` maps local name -> the name
|
|
the module exported it under.
|
|
*/
|
|
export function collectImportBindings(sf) {
|
|
const importedFrom = new Map();
|
|
const localAlias = new Map();
|
|
const visit = (node) => {
|
|
if (ts.isImportDeclaration(node) && node.importClause?.namedBindings
|
|
&& ts.isNamedImports(node.importClause.namedBindings)
|
|
&& ts.isStringLiteral(node.moduleSpecifier)) {
|
|
for (const element of node.importClause.namedBindings.elements) {
|
|
importedFrom.set(element.name.text, node.moduleSpecifier.text);
|
|
if (element.propertyName) localAlias.set(element.name.text, element.propertyName.text);
|
|
}
|
|
}
|
|
ts.forEachChild(node, visit);
|
|
};
|
|
visit(sf);
|
|
return { importedFrom, localAlias };
|
|
}
|
|
|
|
export function isRelevantCallSite(site, declaringFile) {
|
|
/* Basename of the seam's module, e.g. `near-duplicate-canonical` — enough to tell core's
|
|
`task-priority` from the dashboard's `taskSorting` without resolving the module graph. */
|
|
const declaringModule = declaringFile.replace(/\.tsx?$/, "").split("/").pop();
|
|
{
|
|
/*
|
|
A METHOD CALL IS NOT THIS FUNCTION. Seams are module-level `function` declarations, but matching
|
|
by name also swept up `obj.sameName(...)`. `store.enqueueMergeQueue(taskId, opts)` is a 2-arg
|
|
TaskStore METHOD that internally resolves the review columns; the module function it shadows
|
|
takes 5. Counting the method's calls reported the module seam as under-supplied and turned the
|
|
gate red on main over two call sites that are correct.
|
|
|
|
Tradeoff, stated: a genuine `namespace.fn(...)` call would now be skipped. This codebase calls
|
|
module functions as bare identifiers (aliased ones are resolved above), so that trade buys a
|
|
real false-positive fix at the cost of a shape that does not currently occur.
|
|
*/
|
|
if (site.viaProperty) return false;
|
|
if (site.file === declaringFile) return true; // the seam's own file
|
|
if (site.shadowed) return false; // a local same-named function
|
|
if (site.from === undefined) return true; // not imported: ambiguous, count it
|
|
/*
|
|
BARREL AND PACKAGE IMPORTS CANNOT BE RESOLVED BY BASENAME, SO THEY COUNT.
|
|
|
|
Correction to a regression I shipped while closing the imported-shadow hole. Engine and CLI reach
|
|
core through `import { ... } from "@fusion/core"`, whose basename is "core" and never matches a
|
|
module name like "near-duplicate-canonical". Comparing basenames therefore classified EVERY
|
|
barrel-imported call site as "a different function of the same name" and dropped it — so the
|
|
check stopped seeing engine's and cli's calls into core at all, which is most of the
|
|
cross-package surface it exists to watch.
|
|
|
|
Measured: `isNearDuplicateCanonicalInactive` reported "supplied by 5/6 call sites" while FOUR
|
|
engine sites (self-healing.ts x2, triage.ts x2) omitted the argument and were invisible. The
|
|
check read cleaner and caught less — the exact failure mode this gate exists to document.
|
|
|
|
Only a RELATIVE specifier identifies a module well enough to exclude on. Anything else is
|
|
unresolved, and unresolved must mean COUNTED: an over-counted seam produces a false report
|
|
somebody investigates, an under-counted one produces silence.
|
|
*/
|
|
if (!site.from.startsWith(".")) return true;
|
|
return site.from.replace(/\.js$/, "").split("/").pop() === declaringModule;
|
|
}
|
|
}
|
|
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:35 (#2851 review):
|
|
GUARDED REPORTING, so importing this module does not run the gate to completion.
|
|
|
|
`check-inert-flag-seams.test.mjs` imports `isRelevantCallSite`. Without this guard the import printed
|
|
the gate's report and could `process.exit(1)`, so the test file would pass or fail on unrelated repo
|
|
state rather than on what it asserts. Same fix, same reason, as check-sql-column-literals.
|
|
|
|
The AST WALK above stays unguarded on purpose: `declared` and `callSites` are the module's data, a
|
|
future test may want them, and the walk has no output and no exit. Only the reporting is entry-point
|
|
work.
|
|
*/
|
|
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
const offenders = [];
|
|
const partial = [];
|
|
const stale = [];
|
|
for (const [fn, { file, arity }] of declared) {
|
|
const allSites = callSitesFor(fn, file);
|
|
/*
|
|
PRODUCTION suppliers are the only ones that make a seam live. A test passing the argument proves
|
|
the parameter is exercised, not that anything in the shipped product ever reaches that branch.
|
|
*/
|
|
const sites = allSites.filter((site) => !site.isTest);
|
|
const testSites = allSites.filter((site) => site.isTest);
|
|
const best = sites.reduce((max, site) => Math.max(max, site.args), 0);
|
|
const unsupplied = best < arity;
|
|
/*
|
|
A seam with NO production caller is inert whether or not tests exercise it, so it is reported the
|
|
same way. Publication status does not change that: this gate evaluates repository suppliers, not
|
|
speculative external consumers. Test call sites are still tracked, and they must never CLEAR a
|
|
seam.
|
|
*/
|
|
const testNote = sites.length === 0 && testSites.length > 0 ? ` (${testSites.length} test call site(s))` : "";
|
|
/*
|
|
THE ONE-SUPPLIER FLOOR. `best < arity` asks only whether SOME caller supplies the argument, so one
|
|
correct call site clears the seam while every other caller silently takes the legacy fallback. That
|
|
is not hypothetical: `isTaskStuck` shipped with two of its three call sites omitting the flags, and
|
|
review caught it, not this gate — the gate was green because the third call site was right.
|
|
|
|
A partially-supplied seam is the harder defect of the two. A wholly-unsupplied one is at least
|
|
uniformly wrong; this one works on the board you tested and degrades on the column you did not.
|
|
*/
|
|
/*
|
|
FNXC:InertFlagSeams 2026-07-31-03:10 (#2822 review — greptile):
|
|
AN EXEMPTION IS BOUNDED BY COUNT, NOT OPEN-ENDED.
|
|
|
|
`<file>::<function>` previously exempted EVERY call to that function in that file, so a later call
|
|
added without the flags was silently covered and the gate stayed green — an exemption that grows to
|
|
fit whatever arrives is not an exemption, it is a hole. That is the same defect this gate exists to
|
|
catch (`isTaskStuck` shipped two of three sites unsupplied and the gate was green), one level up in
|
|
the gate itself.
|
|
|
|
Each entry now records HOW MANY omissions were reviewed. Extras beyond that count are reported like
|
|
any other unsupplied site, so adding a call site cannot inherit someone else's review.
|
|
*/
|
|
const omittingAll = sites.filter((site) => site.args < arity);
|
|
const usedPerKey = new Map();
|
|
const omitting = [];
|
|
for (const site of omittingAll) {
|
|
const key = `${site.file}::${fn}`;
|
|
const entry = ALLOWED_OMISSIONS.get(key);
|
|
if (entry === undefined) { omitting.push(site); continue; }
|
|
const used = usedPerKey.get(key) ?? 0;
|
|
if (used < entry.count) { usedPerKey.set(key, used + 1); continue; }
|
|
omitting.push(site);
|
|
}
|
|
|
|
/* Same staleness rule as the name-level list: an exemption whose site now supplies is dead. */
|
|
for (const [key, entry] of ALLOWED_OMISSIONS) {
|
|
const [siteFile, siteFn] = key.split("::");
|
|
if (siteFn !== fn) continue;
|
|
const omittingHere = sites.filter((candidate) => candidate.file === siteFile && candidate.args < arity).length;
|
|
if (omittingHere === 0) {
|
|
stale.push(` ${key} — no unsupplied call site remains; remove its ALLOWED_OMISSIONS entry`);
|
|
} else if (omittingHere < entry.count) {
|
|
/*
|
|
A count that overshoots is the same hazard in miniature: it silently pre-authorises an omission
|
|
that has not been reviewed. Narrow it in the change that fixed the site.
|
|
*/
|
|
stale.push(` ${key} — count is ${entry.count} but only ${omittingHere} site(s) omit; lower it`);
|
|
}
|
|
}
|
|
if (ALLOWED.has(fn)) {
|
|
/*
|
|
An allow-list entry whose site is now SUPPLIED is stale, and a stale exemption is how a guard
|
|
quietly stops guarding a file nobody is looking at any more. Fail so the entry is removed in the
|
|
same change that fixed the site — the same staleness rule the sync-resolver allow-list uses.
|
|
*/
|
|
if (!unsupplied) stale.push(` ${fn} — now supplied; remove its ALLOWED entry`);
|
|
continue;
|
|
}
|
|
if (unsupplied) {
|
|
offenders.push(` ${file}: ${fn}() — best call passes ${best} of ${arity}`);
|
|
} else if (omitting.length > 0) {
|
|
const where = omitting.map((site) => `${site.file}:${site.args}`).join(", ");
|
|
partial.push(` ${file}: ${fn}() — supplied by ${sites.length - omitting.length}/${sites.length}`
|
|
+ ` call sites; omitted at ${where} (of ${arity})`);
|
|
}
|
|
}
|
|
|
|
/*
|
|
TEMPORARY entries are exemptions for OTHER teams' code, granted so their CI does not break mid-batch.
|
|
They are the ones that rot: nobody who could remove them is looking at this file. Announce them on
|
|
every run so they stay visible rather than becoming permanent by silence.
|
|
*/
|
|
const temporary = [...ALLOWED].filter(([, reason]) => reason.startsWith("TEMPORARY"));
|
|
if (temporary.length > 0) {
|
|
console.log(`[check-inert-flag-seams] ${temporary.length} TEMPORARY exemption(s) still active:`);
|
|
for (const [fn, reason] of temporary) console.log(` ${fn} — ${reason}`);
|
|
}
|
|
|
|
if (declared.size === 0) {
|
|
console.error("[check-inert-flag-seams] found NO trailing lane/flag params — the scan is broken, not the code.");
|
|
process.exit(1);
|
|
}
|
|
|
|
/*
|
|
AN EXEMPTION FOR A FUNCTION THAT NO LONGER EXISTS ALSO ROTS.
|
|
|
|
The staleness check above only fires for a seam the scan still FINDS — it asks "is this site supplied
|
|
now?". Delete the declaration and the name is never iterated, so its entry sits in the list forever,
|
|
silently exempting nothing and misleading the next reader about what is tolerated. Found by deleting
|
|
`evaluateMergeBlockerGuard` and watching the gate stay quiet about its leftover entry.
|
|
*/
|
|
for (const fn of ALLOWED.keys()) {
|
|
if (!declared.has(fn)) stale.push(` ${fn} — no such seam declared any more; remove its ALLOWED entry`);
|
|
}
|
|
|
|
/*
|
|
FNXC:InertFlagSeams 2026-07-31-03:45 (#2830 review — greptile):
|
|
THE SAME ROT REACHES ALLOWED_OMISSIONS, and the pass above did not cover it.
|
|
|
|
Both staleness rules for the per-site list live inside the per-declaration loop, so they only run for
|
|
a function the scan still FINDS. Delete or rename the function and that loop never visits it: the
|
|
`<file>::<fn>` entry survives, exempting nothing, while reading as a reviewed and tolerated omission.
|
|
|
|
This is the identical defect the ALLOWED pass above was added to fix — written for one of the two
|
|
lists and not the other, which is the half-conversion shape this repo keeps producing. Same check,
|
|
same failure mode, so it belongs immediately beside it rather than folded into the loop that cannot
|
|
see deletions.
|
|
*/
|
|
for (const key of ALLOWED_OMISSIONS.keys()) {
|
|
const [, siteFn] = key.split("::");
|
|
if (!declared.has(siteFn)) {
|
|
stale.push(` ${key} — no such seam declared any more; remove its ALLOWED_OMISSIONS entry`);
|
|
}
|
|
}
|
|
|
|
/*
|
|
FNXC:LifecycleColumnCensus 2026-07-30-23:55 (a STALE exemption WARNS; it does not fail):
|
|
|
|
This used to exit 1. Same mistake as the SQL ratchet's drop check, and with the same measured cost:
|
|
an entry goes stale precisely because somebody FIXED the seam it covered, so the gate punished the
|
|
people who did the right thing.
|
|
|
|
Three times this week — `getTotalAgentActiveMs`, the two near-duplicate omission entries, and
|
|
`isPlanningContinuationTaskDispatchable`. Each fix was correct, each left an entry behind, and each
|
|
turned the check red for everyone until the entry was deleted by hand. Twice that was main.
|
|
|
|
A stale entry is worth removing: it exempts a function nobody is guarding any more. But the cost of
|
|
leaving it is bounded — one function unguarded, listed loudly on every run — while a gate that fails
|
|
on other people's correct fixes gets ignored, and then nothing is guarded at all. That is the
|
|
census's reasoning, applied unchanged.
|
|
|
|
The RISE case — a NEW unsupplied or partially-supplied seam, the actual purpose — still fails hard
|
|
below. Unlike the SQL baseline this cannot auto-prune: the entries live in source with their reasons
|
|
attached, and rewriting them from a script would delete the reasoning with the line.
|
|
*/
|
|
if (stale.length > 0) {
|
|
console.warn("\n[check-inert-flag-seams] STALE allow-list entries — supplied now, or no longer declared:\n");
|
|
for (const line of stale.sort()) console.warn(line);
|
|
console.warn(
|
|
"\nDelete them: each exempts a function that is no longer unguarded, so the list now claims to\n"
|
|
+ "tolerate something it does not. Not fatal — the seam it covered is FIXED, and failing here\n"
|
|
+ "would punish whoever fixed it.\n",
|
|
);
|
|
}
|
|
|
|
if (offenders.length > 0) {
|
|
console.error("\n[check-inert-flag-seams] optional trailing lane/flag parameter with no supplier:\n");
|
|
for (const line of offenders.sort()) console.error(line);
|
|
console.error(
|
|
"\nThe literal it replaced is gone, the census counted the conversion, and the behaviour is the\n"
|
|
+ "legacy fallback forever. Wire a supplier, or delete the parameter and leave the literal counted.\n",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (partial.length > 0) {
|
|
console.error("\n[check-inert-flag-seams] lane/flag parameter supplied at SOME call sites only:\n");
|
|
for (const line of partial.sort()) console.error(line);
|
|
console.error(
|
|
"\nThe listed call sites take the legacy fallback while their siblings resolve the real column,\n"
|
|
+ "so the guard is correct on the board you tested and degrades on the one you did not. Supply the\n"
|
|
+ "argument at every site, or delete the parameter and leave the literal counted.\n",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(
|
|
`[check-inert-flag-seams] ${declared.size} lane/flag seams, all supplied at every production call site.`,
|
|
);
|
|
}
|