import { PAIR_SEPARATOR, ROSTER } from "../core/constants/conduct.constants.ts"; import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts"; import { UNBUILT_HALF, rosterRows } from "../core/validators/coverage.validator.ts"; import { corpusOf, observerResolves } from "../core/resolvers/conduct.resolver.ts"; import { unresolvedFinding, unstatedFinding } from "../core/factories/conduct.factory.ts"; import { ENTRYPOINT_ROOTS } from "../core/constants/path.constants.ts"; import { KINDS as GATE_KINDS } from "../core/steps/gate.step.ts"; import { RULE_ROOT } from "../core/constants/layer.constants.ts"; import type { RosterRow } from "../core/types/coverage.types.ts"; import { KINDS as SNAPSHOT_KINDS } from "../core/steps/snapshot.step.ts"; import { KINDS as TYPECHECK_KINDS } from "../core/steps/typecheck.step.ts"; import { identityOf } from "../core/registries/rule.registry.ts"; import { publishedKinds } from "../core/readers/gate.reader.ts"; import { declaredKinds as qualityKinds } from "../core/steps/quality.step.ts"; import { stepEmittedIds } from "../core/validators/emission.validator.ts"; const STATED_CELLS = 5; const NO_CHECKABLE_HALF = "—"; const isStated = function isStated(row: RosterRow): boolean { return row.cells >= STATED_CELLS && row.cell.length > 0; }; const isMarker = function isMarker(row: RosterRow): boolean { return row.cell === UNBUILT_HALF || row.cell === NO_CHECKABLE_HALF; }; const commandOf = function commandOf(path: string): string[] { const root = ENTRYPOINT_ROOTS.find((entry) => path.startsWith(entry)); const name = root === undefined ? "" : path.slice(root.length); const dot = name.indexOf("."); return dot > 0 ? [name.slice(0, dot)] : []; }; export const rule: RuleDeclaration = { check(context: RuleContext): RuleResult { if (!context.paths.includes(ROSTER)) { return { derivations: { roster: "outside this run's path set", skippedAsOutOfScope: [ROSTER] }, findings: [], healed: [], }; } const rows = rosterRows(context.read(ROSTER)); const unstated = rows.filter((row) => !isStated(row)); const ruleIds = new Set(context.paths.filter((path) => path.startsWith(RULE_ROOT)).map(identityOf)); const emitted = [ ...stepEmittedIds(context.repoRoot), ...GATE_KINDS, ...SNAPSHOT_KINDS, ...TYPECHECK_KINDS, ...qualityKinds(), ]; const stepIds = new Set(emitted.filter((id) => !id.includes(PAIR_SEPARATOR))); const stepKinds = new Set(emitted.filter((id) => id.includes(PAIR_SEPARATOR))); const commands = new Set(context.paths.flatMap(commandOf)); const registered = new Set([...ruleIds, ...stepIds, ...commands]); const certified = new Set(publishedKinds(context.repoRoot)); const keyed = new Set([...certified, ...stepKinds]); const observed = rows.filter((row) => isStated(row) && !isMarker(row)); const resolving = observed.filter((row) => observerResolves(row.cell, registered, keyed)); const unresolved = observed.filter((row) => !observerResolves(row.cell, registered, keyed)); const corpora = Object.fromEntries( resolving.map((row) => [row.slug, corpusOf(row.cell, ruleIds, stepIds, commands, certified, stepKinds)]), ); const findings = [...unstated.map(unstatedFinding), ...unresolved.map(unresolvedFinding)]; return { derivations: { corpusBound: "each resolving cell names which corpus every member came from, because the BARE namespace is two " + "merged flat — a registered rule id and an entry-point command name are the same SHAPE, so the " + "value's own form separates a keyed pair from a bare member and cannot separate the two bare kinds " + "from each other. Measured on the roster: one token names a rule in one cell and a command in " + "another, both correct and both resolving, with only the entry's prose telling a reader which. THE " + "RESOLUTION ALREADY KNOWS — rule ids come from the rule sources and command names from the " + "entry-point roots — so publishing it costs no authored vocabulary and asks nothing of an author, " + "which is why it is done here rather than by typing the cell", notChecked: "whether the named observer is the RIGHT one for that half — the join decides that the id " + "RESOLVES against the registered set and never that the check it names observes the property " + "the entry describes, which is a reading of both. The registered set is the rule ids this run " + "hands the check plus the ids the pipeline's own steps emit, which is the same set the coverage " + "walk builds, plus every entry point named by its command — because an entry point that REFUSES " + "a closure is a stronger observer than any registered check offers and carries no rule id, so a " + "join over rule ids alone reports the strongest enforcement in the tree as unresolved. A cell naming an emitted KIND " + "rather than any of the three still resolves against nothing and is reported. This check ranges " + "over every roster row for both axes and over nothing else", observerCorpora: corpora, population: "the ROWS of one declared digest, never the files this run hands every check — so this report " + "publishes its members under a key naming its own unit and declares no reached set at all. A " + "reached count is a claim about members OF THE HANDED SET, and answering it in a foreign unit " + "satisfies the disclosure while breaking the audit: the subtraction reads as a hundred skipped " + "files when the check was never walking files. One file is opened and every row in it is walked, " + "so there is nothing skipped and nothing to name", registeredObservers: [...registered].toSorted((left, right) => left.localeCompare(right, "en")), roster: "present", rosterRowsWalked: rows.map((row) => row.slug), rows: rows.length, unresolvedObserver: unresolved.map((row) => `${row.slug} → ${row.cell}`), unstated: unstated.map((row) => row.slug), }, findings, healed: [], }; }, extensions: [], heals: false, invariant: "every entry in the conduct roster carries a third cell, so an unstated enforcement half is distinguishable from an assessed one", jurisdiction: "all", kinds: ["unstatedHalf", "unresolvedObserver"], reads: [ROSTER], stage: "content", wholeScopeOnly: true, };