/** * The one place that decides how an artifact name and a findings filename map to * each other. * * Before this module there were two independent derivations of the same key, and * they disagreed. `aidlc review ` wrote * `` `${artifactArg}.review.md` `` from the argument as typed, while * `loadFindings` keyed its index on `file.replace('.review.md', '')` and * `checkReviewGate` looked up the template's artifact name — `requirements.md`. * Type `requirements`, which is the phase name and what the skill's prose calls * the artifact, and the review was written, parsed, counted and summarised * correctly while the gate reported "no findings file". * * The cost was not hypothetical: **11 findings files across 6 completed * instances** sat under the legacy spelling, every one of them a `full-feature` * instance and every one on `requirements` or `design` — the only two phases any * template gates. Eleven adversarial reviews, none of which counted toward the * gate they were run for. * * ## Why both directions live here * * Fixing only the writer would leave those 11 files dead. Fixing only the reader * would leave two spellings valid forever, which is what the roadmap item warned * against. So this module owns the mapping and both callers derive from it — a * second derivation anywhere else is the regression, which is why * `test/findings-naming.test.ts` asserts the inverse property rather than a list * of literals. * * The convenient part is that the inverse is nearly free: * * ``` * artifactFromFindingsFile('requirements.review.md') === 'requirements.md' * artifactFromFindingsFile('requirements.md.review.md') === 'requirements.md' * ``` * * Strip the suffix, then canonicalize. Both spellings on disk converge on one * key, so the legacy files start counting with no compatibility branch at any * call site — nothing downstream has to know which spelling it is looking at. * * ## Why `.md.review.md` is canonical * * The doubled `.md` is ugly, and it is the spelling that already works: * `checkReviewGate` looks up the template's artifact name, so the gate needs no * change to find these files. It is also the majority on disk — 31 files against * 11 — and every instance from `agent-portability` (2026-08-21) onward writes it. * Choosing the prettier spelling would move 31 files to stop 11 from moving. * * Requirements: AC-1, AC-2, AC-3, AC-4, AC-5, AC-10 * * @module */ /** * The suffix that marks a file as review findings. * * Exported because the doctor migration and `loadFindings` both filter on it, and * a literal `'.review.md'` in either would be a second declaration of the fact * this module exists to hold once. */ export declare const FINDINGS_SUFFIX = ".review.md"; /** * Resolve an artifact argument to the filename a template declares for it. * * `requirements` and `requirements.md` both yield `requirements.md`. That is the * whole fix for the writer side: the argument a human or agent naturally types is * the phase name, and the extension is load-bearing in a way nothing told them. * * A string already ending in {@link FINDINGS_SUFFIX} is returned unchanged rather * than having `.md` appended. Deciding whether such an argument is legal is * policy, and policy belongs in the caller's allowlist — this function's job is * the mapping, and quietly producing `x.review.md.md` would be worse than either * accepting or refusing it. * * @param arg - Artifact argument, with or without its extension. * @returns The artifact filename, e.g. `requirements.md`. */ export declare function canonicalArtifactName(arg: string): string; /** * The canonical findings filename for an artifact argument. * * @param arg - Artifact argument, with or without its extension. * @returns e.g. `requirements.md.review.md`. */ export declare function findingsFilename(arg: string): string; /** * The artifact a findings file reviews, under one spelling regardless of how the * file itself is spelled. * * Both the canonical `requirements.md.review.md` and the legacy * `requirements.review.md` resolve to `requirements.md`. This is the reader-side * half of the fix and the reason the 11 orphaned files need no migration in order * to start counting — the migration only tidies the names. * * @param file - A filename, not a path. * @returns The artifact filename, or `null` when `file` is not a findings file or * carries no name before the suffix. */ export declare function artifactFromFindingsFile(file: string): string | null; /** * Whether a findings filename is already the canonical spelling for the artifact * it reviews. * * The predicate the doctor migration selects on: false means the file is legacy * and can be renamed without touching its contents. A non-findings filename is * not canonical *and* not legacy, so callers must filter on * {@link FINDINGS_SUFFIX} first — this returns false for those, which is the safe * direction for a rename planner but would be the wrong answer to "should I * ignore this file?". * * @param file - A filename, not a path. */ export declare function isCanonicalFindingsFile(file: string): boolean; //# sourceMappingURL=findings-naming.d.ts.map