mason-context 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/review/cli.ts","../src/review/review.ts","../src/drift/drift.ts","../src/snapshot/snapshot.ts","../src/utils/files.ts","../src/utils/paths.ts","../src/utils/storage.ts","../src/test-map.ts","../src/decisions/provenance.ts","../src/context/trust.ts","../src/decisions/decisions.ts","../src/context/lexical.ts","../src/decisions/drift.ts","../src/review/cochange.ts","../src/review/evidence.ts","../src/review/evidence/vitest.ts","../src/review/evidence/paths.ts","../src/review/evidence/types.ts","../src/review/evidence/sarif.ts","../bin/mason-review.ts"],"sourcesContent":["import path from \"node:path\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport { computeReview, defaultBase } from \"./review.js\";\nimport type { ReviewReport } from \"./review.js\";\n\nexport const USAGE = `Usage: mason-review [--dir <path>] [--base <ref>] [--json] [--evidence <manifest>] [--require-evidence]\n\nReviews the current branch's diff against what git history and the Mason\ndecision store know:\n - co-change partners the diff forgot: files that historically change\n together with a changed file (>=60% of its commits, >=4 shared) but are\n absent from this diff\n - recorded decisions whose anchor files the diff touches (informational)\nDeterministic: no LLM call, no network – safe for CI.\n\nOptions:\n --dir <path> Project root (default: current directory)\n --base <ref> Base ref to diff against via merge-base (default: origin/HEAD,\n origin/main, origin/master, or main – first that resolves)\n --json Full report as JSON (additive-only schema)\n --evidence <manifest> Import a CI evidence manifest (repeatable; paths inside --dir)\n --require-evidence Require current, complete passing evidence; needs --evidence\n --help Show this help\n\nExit codes:\n 0 no missing co-change partners (touched decisions alone do not fail)\n 1 missing co-change partners found\n 2 error (base unresolvable, not a git repository, bad arguments)\n\nEvidence is advisory unless --require-evidence is set. With that flag, current\nfailed checks also exit 1; missing, skipped, stale, or incomplete evidence exits 2.\nNo check command from an imported report is executed.`;\n\nexport interface ReviewCliIo {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\ninterface ParsedArgs {\n dir: string;\n base: string | undefined;\n json: boolean;\n help: boolean;\n evidence: string[];\n requireEvidence: boolean;\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const parsed: ParsedArgs = {\n dir: process.cwd(),\n base: undefined,\n json: false,\n help: false,\n evidence: [], requireEvidence: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--json\") {\n parsed.json = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n parsed.help = true;\n } else if (arg === \"--dir\") {\n const value = argv[++i];\n if (!value) throw new Error(\"--dir requires a path argument\");\n parsed.dir = value;\n } else if (arg === \"--base\") {\n const value = argv[++i];\n if (!value) throw new Error(\"--base requires a ref argument\");\n parsed.base = value;\n } else if (arg === \"--evidence\") {\n const value = argv[++i];\n if (!value || value.startsWith(\"--\")) throw new Error(\"--evidence requires a manifest path\");\n parsed.evidence.push(value);\n } else if (arg === \"--require-evidence\") {\n parsed.requireEvidence = true;\n } else if (!arg.startsWith(\"-\") && parsed.dir === process.cwd()) {\n parsed.dir = arg;\n } else {\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n if (parsed.requireEvidence && !parsed.evidence.length) throw new Error(\"--require-evidence requires at least one --evidence manifest\");\n return parsed;\n}\n\nconst display = (value: string, limit = 500) => stripVTControlCharacters(value).replace(/[\\r\\n\\t]/g, \" \").slice(0, limit);\n\nfunction evidenceSummary(report: ReviewReport): string[] {\n const evidence = report.evidence;\n if (!evidence) return [];\n const lines = [`Imported CI evidence: ${evidence.status} (commit ${evidence.headHash.slice(0, 12)}; committed scope).`];\n for (const diagnostic of evidence.diagnostics) lines.push(` Evidence unavailable: ${display(diagnostic)}`);\n for (const check of evidence.checks) {\n lines.push(` [${check.kind}] ${display(check.id)}: ${check.outcome}, ${check.freshness} (${display(check.tool)})`);\n lines.push(` command: ${display(check.command)}; tested commit: ${check.commit ?? \"unknown\"}`);\n lines.push(` source: ${display(check.source ?? check.manifest)}; report: ${display(check.report?.path ?? \"none\")}`);\n if (Object.keys(check.counts).length) lines.push(` counts: ${JSON.stringify(check.counts)}`);\n for (const diagnostic of check.diagnostics.slice(0, 5)) lines.push(` note: ${display(diagnostic)}`);\n for (const finding of check.findings.slice(0, 10)) {\n const locations = finding.locations.map(l => `${l.file}${l.line ? `:${l.line}` : \"\"}`).join(\", \") || \"no resolved file location\";\n lines.push(` [${finding.state}/${finding.severity}] ${display(finding.ruleId ?? finding.id)} ${display(locations)}: ${display(finding.message)}`);\n if (finding.relatedChangedFiles.length) lines.push(` changed files: ${finding.relatedChangedFiles.map(f => `${display(f.file)} (${f.relationship}${f.confidence ? `, ${f.confidence}` : \"\"})`).join(\", \")}`);\n for (const decision of finding.acceptedDecisions) lines.push(` related accepted decision: ${display(decision.id)}; owner ${display(decision.owner ?? \"unknown\")}; freshness ${decision.freshness}${decision.reviewRequired ? \"; needs review\" : \"\"}`);\n }\n if (check.totalFindings > 10 || check.truncated || check.diagnostics.length > 5) lines.push(` Output abbreviated (${check.totalFindings} findings); inspect --json and the original artifact for full evidence.`);\n }\n if (!evidence.workingTree.available) lines.push(\" Working-tree state unavailable; imported evidence only describes the recorded commit.\");\n else if (evidence.workingTree.changedFiles.length) lines.push(` ${evidence.workingTree.changedFiles.length} uncommitted paths are outside this evidence's scope.`);\n lines.push(\" Related decisions are associations, not proven violations. Passing imported checks do not establish complete coverage.\");\n return lines;\n}\n\nexport function formatReviewSummary(report: ReviewReport): string {\n const lines: string[] = [];\n lines.push(\n `Diff vs ${report.base} (merge-base ${report.mergeBase.slice(0, 7)}): ${report.changedFiles.length} changed file${report.changedFiles.length === 1 ? \"\" : \"s\"}.`\n );\n for (const diagnostic of report.diagnostics ?? []) lines.push(`Invalid decision record ${diagnostic.path}: ${diagnostic.message}`);\n if (report.truncated) {\n lines.push(\n `Large diff – co-change analysis limited to the first ${50} files.`\n );\n }\n if (!report.historyAvailable) {\n lines.push(\n \"Git history unavailable (shallow clone?) – co-change analysis skipped.\"\n );\n }\n\n if (report.missingPartners.length > 0) {\n lines.push(\"Possible forgotten co-change partners:\");\n for (const f of report.missingPartners) {\n lines.push(\n ` [missing-partner] ${f.changedFile} changed without ${f.missingPartner} – they changed together in ${Math.round(f.rate * 100)}% of ${f.changedFile}'s last ${f.fileCommits} commits (${f.sharedCommits} shared)`\n );\n }\n }\n\n if (report.touchedDecisions.length > 0) {\n lines.push(\"Recorded decisions touched by this diff (check approval and freshness before relying on them):\");\n for (const d of report.touchedDecisions) {\n lines.push(\n ` [decision] ${d.title} (${d.category}; ${d.approval ?? \"unreviewed\"}; owner ${d.owner ?? \"unknown\"}; freshness ${d.freshness ?? \"unknown\"}; via ${d.touchedFiles.join(\", \") || \"pending proposal\"})`\n );\n if (d.sources?.length) lines.push(` sources: ${d.sources.map(s => s.reference).join(\", \")}`);\n if (d.lastReview) lines.push(` last review: ${d.lastReview.reviewer} at ${d.lastReview.gitHash.slice(0, 7)}`);\n if (d.pendingProposal) {\n const p = d.pendingProposal;\n lines.push(` [proposed revision ${p.revision}] ${p.title} (owner ${p.owner ?? \"unknown\"}; freshness ${p.trust.freshness}; via ${p.touchedFiles.join(\", \") || \"no draft anchors touched\"}); accepted revision ${d.revision} remains operative`);\n }\n }\n }\n\n lines.push(\n report.missingPartners.length === 0\n ? \"No missing co-change partners.\"\n : `${report.missingPartners.length} possible omission${report.missingPartners.length === 1 ? \"\" : \"s\"}.`\n );\n lines.push(...evidenceSummary(report));\n return lines.join(\"\\n\");\n}\n\nexport async function runReviewCli(\n argv: string[],\n io: ReviewCliIo = {\n out: (line) => process.stdout.write(`${line}\\n`),\n err: (line) => process.stderr.write(`${line}\\n`),\n }\n): Promise<number> {\n let args: ParsedArgs;\n try {\n args = parseArgs(argv);\n } catch (error) {\n io.err(error instanceof Error ? error.message : String(error));\n io.err(USAGE);\n return 2;\n }\n\n if (args.help) {\n io.out(USAGE);\n return 0;\n }\n\n const rootDir = path.resolve(args.dir);\n const base = args.base ?? (await defaultBase(rootDir));\n if (!base) {\n io.err(\n `Could not find a base ref in ${rootDir} (tried origin/HEAD, origin/main, origin/master, main). Pass one with --base.`\n );\n return 2;\n }\n\n const report = await computeReview(rootDir, base, args.evidence.length ? { evidence: args.evidence } : {});\n if (!report) {\n io.err(\n `Could not resolve a merge base between ${base} and HEAD in ${rootDir} – not a git repository, unknown ref, or unrelated histories.`\n );\n return 2;\n }\n\n if (args.json) {\n io.out(JSON.stringify(report, null, 2));\n } else {\n io.out(formatReviewSummary(report));\n if (args.evidence.length && !args.requireEvidence) io.out(\"Imported evidence is advisory for exit codes; use --require-evidence to require current passing checks.\");\n }\n if (args.requireEvidence && report.evidence?.status !== \"passed\") return report.evidence?.status === \"failed\" ? 1 : 2;\n return report.missingPartners.length > 0 ? 1 : 0;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { getChangesWithStatus, touchedPaths } from \"../drift/drift.js\";\nimport { decisionProvenance, decisionKnowledge, effectiveDecision } from \"../decisions/provenance.js\";\nimport { loadDecisionStore } from \"../decisions/decisions.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\nimport { computeDecisionDrift } from \"../decisions/drift.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport type { StoreDiagnostic } from \"../utils/storage.js\";\nimport type { DecisionRecord } from \"../decisions/decisions.js\";\nimport { findMissingPartners } from \"./cochange.js\";\nimport type { CochangeFinding } from \"./cochange.js\";\nimport { collectReviewEvidence, type ReviewEvidence } from \"./evidence.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\n\nconst exec = promisify(execFile);\n\n/** Diffs larger than this are refactors; partner analysis would be noise. */\nconst MAX_ANALYZED_FILES = 50;\n\nexport interface TouchedDecision extends Partial<ReturnType<typeof decisionProvenance>> {\n id: string;\n title: string;\n body: string;\n category: string;\n anchors: string[];\n freshness?: Freshness;\n touchedFiles: string[];\n pendingProposal?: NonNullable<ReturnType<typeof decisionKnowledge>[\"pendingProposal\"]> & { touchedFiles: string[] };\n}\n\nexport interface ReviewReport {\n /** Additive-only schema. */\n version: 1;\n diagnostics?: StoreDiagnostic[];\n root: string;\n base: string;\n mergeBase: string;\n changedFiles: string[];\n /** Historical partners this diff leaves untouched — drive exit 1. */\n missingPartners: CochangeFinding[];\n /** Decisions whose anchors the diff touches — informational only. */\n touchedDecisions: TouchedDecision[];\n historyAvailable: boolean;\n truncated: boolean;\n /** Optional imported CI results. Does not change the legacy review exit codes. */\n evidence?: ReviewEvidence;\n}\n\nasync function resolveMergeBase(\n resolvedRoot: string,\n base: string,\n head: string\n): Promise<string | null> {\n try {\n const { stdout } = await exec(\"git\", [\"merge-base\", base, head], {\n cwd: resolvedRoot,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\n/** First base ref that resolves: origin/HEAD, origin/main, origin/master, main. */\nexport async function defaultBase(resolvedRoot: string): Promise<string | null> {\n for (const ref of [\"origin/HEAD\", \"origin/main\", \"origin/master\", \"main\"]) {\n try {\n await exec(\"git\", [\"rev-parse\", \"--verify\", \"--quiet\", ref], {\n cwd: resolvedRoot,\n });\n return ref;\n } catch {\n // Try the next candidate.\n }\n }\n return null;\n}\n\nfunction anchorsTouched(\n record: DecisionRecord,\n changedFiles: string[]\n): string[] {\n return matchingPaths(record.files, changedFiles);\n}\n\n/**\n * Review a diff against what git history and the decision store know:\n * co-change partners the diff forgot, and recorded constraints it touches.\n * Deterministic — no LLM, no network. Returns null when the base ref or\n * merge base cannot be resolved.\n */\nexport async function computeReview(\n rootDir: string,\n base: string,\n options: { evidence?: string[] } = {}\n): Promise<ReviewReport | null> {\n const resolvedRoot = path.resolve(rootDir);\n const head = await getCurrentGitHash(resolvedRoot);\n if (head === \"unknown\") return null;\n const mergeBase = await resolveMergeBase(resolvedRoot, base, head);\n if (!mergeBase) return null;\n\n const changes = await getChangesWithStatus(resolvedRoot, mergeBase, head);\n if (changes === null) return null;\n\n const changedFiles = touchedPaths(changes);\n\n const report: ReviewReport = {\n version: 1,\n root: resolvedRoot,\n base,\n mergeBase,\n changedFiles,\n missingPartners: [],\n touchedDecisions: [],\n historyAvailable: true,\n truncated: false,\n };\n const store = await loadDecisionStore(resolvedRoot);\n report.diagnostics = store.diagnostics;\n const decisionDrift = await computeDecisionDrift(resolvedRoot, store.records);\n if (options.evidence !== undefined) {\n report.evidence = await collectReviewEvidence(resolvedRoot, options.evidence, changedFiles, store.records, decisionDrift.freshness, head);\n if (store.diagnostics.length) {\n report.evidence.diagnostics.push(\"Invalid decision records make knowledge associations incomplete; consult review diagnostics.\");\n if (report.evidence.status === \"passed\") report.evidence.status = \"incomplete\";\n }\n }\n const finalize = async () => {\n if (report.evidence && await getCurrentGitHash(resolvedRoot) !== head) {\n report.evidence.diagnostics.push(\"HEAD changed during the review; rerun to obtain consistent change and knowledge associations.\");\n for (const check of report.evidence.checks) check.freshness = \"unknown\";\n report.evidence.summary.stale = 0;\n report.evidence.summary.unknown = report.evidence.checks.length;\n if (report.evidence.status !== \"unavailable\") report.evidence.status = \"incomplete\";\n }\n return report;\n };\n if (changedFiles.length === 0) return finalize();\n\n let analyzed = changedFiles;\n if (changedFiles.length > MAX_ANALYZED_FILES) {\n analyzed = changedFiles.slice(0, MAX_ANALYZED_FILES);\n report.truncated = true;\n }\n\n const partners = await findMissingPartners(\n resolvedRoot,\n analyzed,\n async (relPath) => {\n try {\n await fs.access(path.join(resolvedRoot, relPath));\n return true;\n } catch {\n return false;\n }\n },\n changedFiles\n );\n if (partners === null) {\n report.historyAvailable = false;\n } else {\n report.missingPartners = partners;\n }\n\n const decisions = store.records;\n for (const record of decisions) {\n if (record.status !== \"active\") continue;\n const effective = effectiveDecision(record);\n const touched = anchorsTouched(effective, changedFiles);\n const proposalTouched = effective !== record ? anchorsTouched(record, changedFiles) : [];\n if (touched.length > 0 || proposalTouched.length > 0) {\n const { pendingProposal, ...knowledge } = decisionKnowledge(record, decisionDrift.freshness?.[record.id] ?? \"unknown\", decisionDrift.pendingProposals?.[record.id]?.freshness ?? \"unknown\");\n report.touchedDecisions.push({\n ...knowledge,\n ...(pendingProposal ? { pendingProposal: { ...pendingProposal, touchedFiles: proposalTouched } } : {}),\n id: record.id,\n anchors: effective.files,\n freshness: decisionDrift.freshness?.[record.id] ?? \"unknown\",\n touchedFiles: touched,\n });\n }\n }\n\n return finalize();\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport {\n loadSnapshot,\n getCurrentGitHash,\n listSourceFiles,\n} from \"../snapshot/snapshot.js\";\nimport type { Snapshot } from \"../snapshot/snapshot.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\n\nconst exec = promisify(execFile);\n\n// Incremental refresh stops paying off once a large share of the map is\n// touched — but small absolute counts are always cheap to refresh in place,\n// so both thresholds must be exceeded before recommending a full rebuild.\nconst FULL_REBUILD_FRACTION = 0.4;\nconst FULL_REBUILD_MIN_CHANGED_MAPPED_FILES = 10;\n\nexport type ChangeStatus = \"added\" | \"modified\" | \"deleted\" | \"renamed\";\n\nexport interface FileChange {\n status: ChangeStatus;\n /** Current path (the new path for renames). */\n path: string;\n /** Pre-rename path, only present for renames. */\n previousPath?: string;\n}\n\nexport type DriftRecommendation = \"up-to-date\" | \"incremental\" | \"full-rebuild\";\n\nexport interface WorkingTreeReport {\n available: boolean;\n changedFiles: string[];\n untrackedFiles: string[];\n}\n\nexport interface DriftReport {\n /** Live entry state; committed drift alone continues to drive CLI exit codes. */\n featureFreshness?: Record<string, Freshness>;\n flowFreshness?: Record<string, Freshness>;\n workingTree?: WorkingTreeReport;\n verification?: { neverVerified: number; failed: string[] };\n stale: boolean;\n snapshotHash: string;\n headHash: string;\n /** Commits between the snapshot and HEAD; null when history is unavailable. */\n commitsBehind: number | null;\n /**\n * False when the snapshot commit is unreachable (shallow clone, rewritten\n * history) — staleFeatures/unmappedFiles/renames cannot be computed then.\n */\n historyAvailable: boolean;\n /** Current paths of every file changed since the snapshot. */\n changedFiles: string[];\n /** Stale feature name → the mapped files that changed under it. */\n staleFeatures: Record<string, string[]>;\n /** Stale flow name → the chain files that changed under it. */\n staleFlows: Record<string, string[]>;\n totalFeatures: number;\n totalFlows: number;\n /** New source files not referenced by any feature or flow. */\n unmappedFiles: string[];\n /** Files referenced by the map that no longer exist on disk. */\n ghostFiles: string[];\n renames: Array<{ from: string; to: string }>;\n recommendation: DriftRecommendation;\n}\n\nfunction parseChanges(output: string): FileChange[] {\n const fields = output.split(\"\\0\");\n const changes: FileChange[] = [];\n for (let i = 0; i < fields.length && fields[i];) {\n const code = fields[i++];\n const first = fields[i++];\n if (!first) break;\n const second = /^[RC]/.test(code) ? fields[i++] : undefined;\n const change: FileChange = second\n ? code.startsWith(\"R\") ? { status: \"renamed\", path: second, previousPath: first } : { status: \"added\", path: second }\n : { status: code === \"A\" ? \"added\" : code === \"D\" ? \"deleted\" : \"modified\", path: first };\n if (change.path.startsWith(\".mason/\") && (!change.previousPath || change.previousPath.startsWith(\".mason/\"))) continue;\n changes.push(change);\n }\n return changes;\n}\n\nexport function touchedPaths(changes: FileChange[]): string[] {\n return [...new Set(changes.flatMap(c => c.previousPath ? [c.previousPath, c.path] : [c.path]))].sort();\n}\n\nexport async function getChangesWithStatus(resolvedRoot: string, fromHash: string, toHash = \"HEAD\"): Promise<FileChange[] | null> {\n if (!fromHash || fromHash === \"unknown\" || fromHash.startsWith(\"-\") || !toHash || toHash === \"unknown\" || toHash.startsWith(\"-\")) return null;\n try {\n const { stdout } = await exec(\"git\", [\"diff\", \"--name-status\", \"-z\", \"-M\", fromHash, toHash, \"--\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 });\n return parseChanges(stdout);\n } catch { return null; }\n}\n\nexport async function getWorkingTree(resolvedRoot: string): Promise<WorkingTreeReport> {\n try {\n const [diff, untracked] = await Promise.all([\n exec(\"git\", [\"diff\", \"--name-status\", \"-z\", \"-M\", \"HEAD\", \"--\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),\n exec(\"git\", [\"ls-files\", \"-z\", \"--others\", \"--exclude-standard\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),\n ]);\n const untrackedFiles = untracked.stdout.split(\"\\0\").filter(f => f && !f.startsWith(\".mason/\"));\n return { available: true, changedFiles: [...new Set([...touchedPaths(parseChanges(diff.stdout)), ...untrackedFiles])].sort(), untrackedFiles };\n } catch { return { available: false, changedFiles: [], untrackedFiles: [] }; }\n}\n\nasync function countCommitsBehind(\n resolvedRoot: string,\n fromHash: string\n): Promise<number | null> {\n if (!fromHash || fromHash === \"unknown\" || fromHash.startsWith(\"-\")) return null;\n try {\n const { stdout } = await exec(\n \"git\",\n [\"rev-list\", \"--count\", `${fromHash}..HEAD`],\n { cwd: resolvedRoot }\n );\n const count = Number.parseInt(stdout.trim(), 10);\n return Number.isNaN(count) ? null : count;\n } catch {\n return null;\n }\n}\n\nfunction collectMappedFiles(snapshot: Snapshot): Set<string> {\n const mappedFiles = new Set<string>();\n for (const feature of Object.values(snapshot.features)) {\n for (const f of feature.files) mappedFiles.add(f);\n for (const t of feature.tests ?? []) mappedFiles.add(t);\n }\n for (const flow of Object.values(snapshot.flows)) {\n for (const f of flow.chain) mappedFiles.add(f);\n }\n return mappedFiles;\n}\n\nasync function findGhostFiles(\n resolvedRoot: string,\n mappedFiles: Set<string>\n): Promise<string[]> {\n const ghosts: string[] = [];\n for (const file of mappedFiles) {\n try {\n await fs.access(path.join(resolvedRoot, file));\n } catch {\n ghosts.push(file);\n }\n }\n return ghosts.sort();\n}\n\n/**\n * Compare the concept map against HEAD and report feature-level drift.\n * Fully deterministic — git + filesystem only, no LLM involved.\n * Returns null when no snapshot exists.\n */\nexport async function computeDrift(rootDir: string): Promise<DriftReport | null> {\n const root = path.resolve(rootDir);\n const snapshot = await loadSnapshot(root);\n if (!snapshot) return null;\n const [headHash, workingTree] = await Promise.all([getCurrentGitHash(root), getWorkingTree(root)]);\n const hashFor = (entry: { refreshedHash?: string }) => entry.refreshedHash ?? snapshot.gitHash;\n const entries = [...Object.values(snapshot.features), ...Object.values(snapshot.flows)];\n const hashes = new Set([snapshot.gitHash, ...entries.map(hashFor)]);\n const changesByHash = new Map<string, FileChange[] | null>();\n await Promise.all([...hashes].map(async hash => {\n changesByHash.set(hash, hash === headHash && headHash !== \"unknown\" ? [] : await getChangesWithStatus(root, hash));\n }));\n const historyAvailable = headHash !== \"unknown\" && [...changesByHash.values()].every(changes => changes !== null);\n const mappedFiles = collectMappedFiles(snapshot);\n const report: DriftReport = {\n stale: !historyAvailable,\n snapshotHash: snapshot.gitHash, headHash,\n commitsBehind: 0, historyAvailable,\n changedFiles: [], staleFeatures: {}, staleFlows: {},\n totalFeatures: Object.keys(snapshot.features).length,\n totalFlows: Object.keys(snapshot.flows).length,\n unmappedFiles: [], ghostFiles: await findGhostFiles(root, mappedFiles), renames: [],\n recommendation: historyAvailable ? \"up-to-date\" : \"full-rebuild\",\n featureFreshness: {}, flowFreshness: {}, workingTree,\n verification: {\n neverVerified: entries.filter(e => !e.verifiedAt).length,\n failed: [...Object.entries(snapshot.features), ...Object.entries(snapshot.flows)].filter(([, e]) => e.verificationFailed).map(([name]) => name),\n },\n };\n const counts = await Promise.all([...hashes].map(hash => hash === headHash ? 0 : countCommitsBehind(root, hash)));\n const knownCounts = counts.filter((n): n is number => n !== null);\n report.commitsBehind = knownCounts.length ? Math.max(...knownCounts) : null;\n\n const check = (name: string, files: string[], hash: string, staleEntries: Record<string, string[]>, freshness: Record<string, Freshness>) => {\n const changes = changesByHash.get(hash);\n const committedHits = changes ? matchingPaths(files, touchedPaths(changes)) : [];\n if (committedHits.length) staleEntries[name] = committedHits;\n const localHits = matchingPaths(files, workingTree.changedFiles);\n freshness[name] = files.length === 0 || changes === null || changes === undefined || !workingTree.available ? \"unknown\"\n : committedHits.length || localHits.length || files.some(f => report.ghostFiles.includes(f)) ? \"changed\" : \"current\";\n };\n for (const [name, feature] of Object.entries(snapshot.features)) {\n check(name, [...feature.files, ...(feature.tests ?? [])], hashFor(feature), report.staleFeatures, report.featureFreshness!);\n }\n for (const [name, flow] of Object.entries(snapshot.flows)) {\n check(name, flow.chain, hashFor(flow), report.staleFlows, report.flowFreshness!);\n }\n\n const allChanges = [...changesByHash.values()].flatMap(changes => changes ?? []);\n report.changedFiles = [...new Set(allChanges.map(c => c.path))].sort();\n // Complete coverage, including omissions from a map saved at HEAD. Untracked\n // files remain in workingTree and never change the committed-drift exit code.\n const sourceFiles = new Set(await listSourceFiles(root));\n let committedFiles: Set<string> = new Set();\n try {\n const { stdout } = await exec(\"git\", [\"ls-tree\", \"-r\", \"--name-only\", \"-z\", \"HEAD\"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });\n committedFiles = new Set(stdout.split(\"\\0\").filter(Boolean));\n } catch { report.historyAvailable = false; report.stale = true; }\n report.unmappedFiles = [...sourceFiles].filter(f => committedFiles.has(f) && !mappedFiles.has(f)).sort();\n const renames = new Map<string, { from: string; to: string }>();\n for (const change of allChanges) {\n if (change.status === \"renamed\" && change.previousPath) renames.set(`${change.previousPath}\\0${change.path}`, { from: change.previousPath, to: change.path });\n }\n report.renames = [...renames.values()];\n const changedMapped = new Set([...Object.values(report.staleFeatures).flat(), ...Object.values(report.staleFlows).flat()]);\n // A locally deleted file is a live-edit warning, not committed map drift.\n const committedGhosts = report.ghostFiles.filter(f => !workingTree.changedFiles.includes(f));\n report.stale ||= changedMapped.size > 0 || report.unmappedFiles.length > 0 || committedGhosts.length > 0;\n if (!report.historyAvailable) report.recommendation = \"full-rebuild\";\n else if (!report.stale) report.recommendation = \"up-to-date\";\n else report.recommendation = changedMapped.size >= FULL_REBUILD_MIN_CHANGED_MAPPED_FILES && changedMapped.size / Math.max(1, mappedFiles.size) > FULL_REBUILD_FRACTION ? \"full-rebuild\" : \"incremental\";\n return report;\n}\n","import path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { createFileAccess } from \"../utils/files.js\";\nexport { SOURCE_GLOB, SOURCE_IGNORE } from \"../utils/files.js\";\nimport { readStoreJson, writeStoreJson, type StoreDiagnostic } from \"../utils/storage.js\";\nimport { z } from \"zod\";\nimport { normalizeRepoPath } from \"../utils/paths.js\";\nimport { buildTestMap } from \"../test-map.js\";\n\nconst exec = promisify(execFile);\n\nexport interface FeatureEntry {\n description: string;\n files: string[];\n tests?: string[];\n /**\n * Commit this entry was last verified against. Entries updated by an\n * incremental save carry HEAD here; untouched entries keep the hash the\n * map had before the save, so drift stays visible per entry. Absent means\n * \"as of the snapshot's top-level gitHash\".\n */\n refreshedHash?: string;\n /**\n * Whether this is a user-facing capability or internal infrastructure\n * (DI wiring, config loading, logging, provider/transport plumbing).\n * Capabilities are published to product-facing docs (Confluence);\n * infrastructure stays in the AI concept map only. Defaults to \"capability\"\n * when absent (older snapshots) — see normalizeFeatureType.\n */\n type?: \"capability\" | \"infrastructure\";\n /**\n * When an assistant last confirmed this entry's files actually implement\n * the claimed feature (verify_snapshot flow). Absent on older snapshots\n * and never-verified entries. Drift checks freshness against git; this\n * checks the map was CORRECT in the first place.\n */\n verifiedAt?: string;\n verifiedHash?: string;\n /** Set when verification judged the entry wrong — re-map it. */\n verificationFailed?: boolean;\n verificationNote?: string;\n}\n\nexport type FeatureType = \"capability\" | \"infrastructure\";\n\n/**\n * Coerce an arbitrary type value to a known classification. Anything that\n * isn't explicitly \"infrastructure\" defaults to \"capability\" — so older\n * snapshots and unclassified entries are treated as user-facing (published),\n * never silently hidden.\n */\nexport function normalizeFeatureType(value: unknown): FeatureType {\n return value === \"infrastructure\" ? \"infrastructure\" : \"capability\";\n}\n\nexport interface FlowEntry {\n description: string;\n chain: string[];\n /** See FeatureEntry.refreshedHash. */\n refreshedHash?: string;\n /** See FeatureEntry.verifiedAt / verificationFailed. */\n verifiedAt?: string;\n verifiedHash?: string;\n verificationFailed?: boolean;\n verificationNote?: string;\n}\n\nexport interface Snapshot {\n version: 2;\n createdAt: string;\n updatedAt: string;\n gitHash: string;\n features: Record<string, FeatureEntry>;\n flows: Record<string, FlowEntry>;\n}\n\nconst repoPath = z.string().refine(value => normalizeRepoPath(value) !== null, \"Expected a relative repository path\");\nconst verificationFields = {\n refreshedHash: z.string().optional(), verifiedAt: z.string().optional(),\n verifiedHash: z.string().optional(), verificationFailed: z.boolean().optional(),\n verificationNote: z.string().optional(),\n};\nexport const featureSchema = z.object({\n description: z.string(), files: z.array(repoPath), tests: z.array(repoPath).optional(),\n type: z.enum([\"capability\", \"infrastructure\"]).optional(), ...verificationFields,\n}).passthrough();\nexport const flowSchema = z.object({ description: z.string(), chain: z.array(repoPath), ...verificationFields }).passthrough();\nconst snapshotSchema = z.object({\n version: z.literal(2), createdAt: z.string(), updatedAt: z.string(), gitHash: z.string(),\n features: z.record(featureSchema), flows: z.record(flowSchema),\n}).passthrough();\n\nexport async function loadSnapshot(rootDir: string): Promise<Snapshot | null> {\n const parsed = await readStoreJson(rootDir, \".mason/snapshot.json\");\n if (parsed === null || (parsed as { version?: number }).version === 1) return null;\n const result = snapshotSchema.safeParse(parsed);\n if (!result.success) throw new Error(`Invalid Mason snapshot: ${result.error.message}`);\n return result.data;\n}\n\n/** Context and onboarding can use decisions even when the optional map is broken. */\nexport async function inspectSnapshot(rootDir: string): Promise<{\n status: \"available\" | \"missing\" | \"invalid\";\n snapshot: Snapshot | null;\n diagnostics: StoreDiagnostic[];\n}> {\n try {\n const raw = await readStoreJson(rootDir, \".mason/snapshot.json\");\n const snapshot = raw === null ? null : snapshotSchema.parse(raw);\n return { status: snapshot ? \"available\" : \"missing\", snapshot, diagnostics: [] };\n } catch (error) {\n return { status: \"invalid\", snapshot: null, diagnostics: [{\n path: \".mason/snapshot.json\", message: error instanceof Error ? error.message : String(error),\n }] };\n }\n}\n\nexport async function saveSnapshot(rootDir: string, snapshot: Snapshot): Promise<void> {\n await writeStoreJson(rootDir, \".mason/snapshot.json\", snapshotSchema.parse(snapshot));\n}\n\nexport async function getCurrentGitHash(rootDir: string): Promise<string> {\n try {\n const { stdout } = await exec(\"git\", [\"rev-parse\", \"HEAD\"], {\n cwd: rootDir,\n });\n return stdout.trim();\n } catch {\n return \"unknown\";\n }\n}\n\nexport const DEFAULT_BATCH_SIZE = 50;\nconst SKELETON_CHARS = 500;\nconst DEEP_SAMPLE_CHARS = 1500;\nconst DEEP_SAMPLES_PER_BATCH = 3;\n\nexport interface SnapshotBatch {\n offset: number;\n batchSize: number;\n nextOffset: number | null;\n totalFiles: number;\n skeletons: Array<{ path: string; content: string }>;\n samples: Array<{ path: string; content: string }>;\n testPairs: Array<{ test: string; source: string; confidence: string }>;\n}\n\nexport async function listSourceFiles(resolvedRoot: string): Promise<string[]> {\n return (await createFileAccess(resolvedRoot)).list();\n}\n\nexport async function prepareSnapshotBatch(\n rootDir: string,\n offset: number,\n batchSize: number = DEFAULT_BATCH_SIZE,\n scopeFiles?: string[]\n): Promise<SnapshotBatch> {\n const resolvedRoot = path.resolve(rootDir);\n const access = await createFileAccess(resolvedRoot);\n let allFiles = await access.list();\n if (scopeFiles) {\n // Intersect with the real source list: keeps ignore rules and path safety,\n // and silently drops scope entries that no longer exist on disk. An empty\n // scope stays empty — it must not fall back to walking the whole project.\n const scopeSet = new Set(scopeFiles);\n allFiles = allFiles.filter((f) => scopeSet.has(f));\n }\n const totalFiles = allFiles.length;\n const safeOffset = Math.max(0, Math.min(offset, totalFiles));\n const batchPaths = allFiles.slice(safeOffset, safeOffset + batchSize);\n\n const skeletons: Array<{ path: string; content: string }> = [];\n for (const filePath of batchPaths) {\n const full = await access.read(filePath);\n if (full) {\n skeletons.push({\n path: full.path,\n content: full.content.slice(0, SKELETON_CHARS),\n });\n }\n }\n\n // Pick a few files from this batch to read deeply for grounding. Spread\n // evenly across the batch so the deep samples represent the batch's range.\n const samples: Array<{ path: string; content: string }> = [];\n if (skeletons.length > 0) {\n const step = Math.max(1, Math.floor(skeletons.length / DEEP_SAMPLES_PER_BATCH));\n for (let i = 0; i < skeletons.length && samples.length < DEEP_SAMPLES_PER_BATCH; i += step) {\n const full = await access.read(skeletons[i].path);\n if (full) {\n samples.push({\n path: full.path,\n content: full.content.slice(0, DEEP_SAMPLE_CHARS),\n });\n }\n }\n }\n\n // Only include test pairs that involve files in this batch — keeps the\n // appendix relevant and small.\n const batchPathSet = new Set(batchPaths);\n const allTestPairs = (await buildTestMap(resolvedRoot)).paired;\n const testPairs = allTestPairs.filter(\n (p) => batchPathSet.has(p.test) || batchPathSet.has(p.source)\n );\n\n const nextOffset =\n safeOffset + batchSize >= totalFiles ? null : safeOffset + batchSize;\n\n return {\n offset: safeOffset,\n batchSize,\n nextOffset,\n totalFiles,\n skeletons,\n samples,\n testPairs,\n };\n}\n","import fs from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport fg from \"fast-glob\";\nimport { isWithinRoot, normalizeRepoPath } from \"./paths.js\";\n\nconst exec = promisify(execFile);\nexport const SOURCE_EXTENSIONS = [\"ts\", \"tsx\", \"js\", \"jsx\", \"mts\", \"cts\", \"mjs\", \"cjs\", \"vue\", \"svelte\", \"kt\", \"kts\", \"java\", \"py\", \"go\", \"rs\", \"swift\", \"rb\", \"cs\", \"cpp\", \"c\", \"h\", \"hpp\", \"dart\", \"php\"];\nexport const SOURCE_GLOB = `**/*.{${SOURCE_EXTENSIONS.join(\",\")}}`;\nexport const SOURCE_IGNORE = [\n \"**/node_modules/**\", \"**/dist/**\", \"**/build/**\", \"**/.gradle/**\",\n \"**/target/**\", \"**/.git/**\", \"**/.mason/**\", \"**/vendor/**\", \"**/__pycache__/**\",\n \"**/venv/**\", \"**/.venv/**\", \"**/*.min.*\", \"**/*.map\", \"**/*.lock\",\n \"**/generated/**\", \"**/*.generated.*\", \"**/R.java\", \"**/BuildConfig.java\",\n \"**/package-lock.json\", \"**/yarn.lock\", \"**/pnpm-lock.yaml\",\n];\nexport const MAX_SOURCE_BYTES = 1024 * 1024;\nexport interface ProjectConfig { patterns?: string[]; alwaysInclude?: string[]; ignore?: string[] }\nexport interface SourceFile { path: string; content: string; totalLines: number }\n\nexport function isSensitiveFile(file: string): boolean {\n return file.split(/[\\\\/]/).some(part =>\n /^(?:\\.env(?:\\..*)?|id_rsa.*|id_ed25519.*)$|\\.(?:pem|key|p12|pfx|jks|keystore)$|credentials\\.|secret|^local\\.properties$/i.test(part)\n );\n}\n\n/** Bound reads even if a file grows after stat. Only read regular files. */\nexport async function readBoundedFile(file: string, maxBytes: number): Promise<string | null> {\n // Do not block on a FIFO or follow a symlink substituted after resolution.\n const handle = await fs.open(file, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);\n try {\n const stat = await handle.stat();\n if (!stat.isFile() || stat.size > maxBytes) return null;\n const buffer = Buffer.alloc(Math.min(maxBytes + 1, stat.size + 1));\n let bytes = 0;\n while (bytes < buffer.length) {\n const result = await handle.read(buffer, bytes, buffer.length - bytes, null);\n if (result.bytesRead === 0) break;\n bytes += result.bytesRead;\n }\n return bytes === buffer.length ? null : buffer.subarray(0, bytes).toString(\"utf8\");\n } finally { await handle.close(); }\n}\n\nexport async function loadProjectConfig(root: string): Promise<ProjectConfig> {\n try {\n const canonicalRoot = await fs.realpath(root);\n const configPath = await fs.realpath(path.join(root, \".mason/config.json\"));\n if (!isWithinRoot(canonicalRoot, configPath)) throw new Error(\"Project configuration resolves outside the repository\");\n const raw = await readBoundedFile(configPath, 64 * 1024);\n if (raw === null) throw new Error(\"Project configuration is not a regular file or exceeds 64 KiB\");\n const value = JSON.parse(raw);\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"Expected a configuration object\");\n const config: ProjectConfig = {};\n for (const key of [\"patterns\", \"alwaysInclude\", \"ignore\"] as const) {\n if (value[key] === undefined) continue;\n if (!Array.isArray(value[key]) || !value[key].every((s: unknown) => typeof s === \"string\")) {\n throw new Error(`Configuration ${key} must be an array of strings`);\n }\n config[key] = value[key];\n }\n return config;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw new Error(`Cannot apply project file policy: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/** Scoped to one operation, so a later tool call sees newly edited files/ignores. */\nexport async function createFileAccess(rootDir: string) {\n const root = path.resolve(rootDir);\n const canonicalRoot = await fs.realpath(root).catch(() => root);\n const config = await loadProjectConfig(root);\n const ignore = [...SOURCE_IGNORE, ...(config.ignore ?? [])];\n let gitFiles: Set<string> | null = null;\n try {\n const { stdout } = await exec(\"git\", [\"ls-files\", \"-z\", \"--cached\", \"--others\", \"--exclude-standard\"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });\n gitFiles = new Set(stdout.split(\"\\0\").filter(Boolean));\n } catch {\n // File-system projects are supported. Fail closed if this IS a Git repo.\n let inGit = false;\n try { await exec(\"git\", [\"rev-parse\", \"--git-dir\"], { cwd: root }); inGit = true; } catch { /* no Git */ }\n if (inGit) throw new Error(\"Cannot enumerate Git files safely\");\n }\n\n async function resolve(file: string): Promise<string | null> {\n const relative = normalizeRepoPath(file);\n if (!relative || isSensitiveFile(relative) || (gitFiles && !gitFiles.has(relative))) return null;\n const candidate = path.join(root, relative);\n try {\n const real = await fs.realpath(candidate);\n if (!isWithinRoot(canonicalRoot, real) || isSensitiveFile(path.relative(canonicalRoot, real))) return null;\n const stat = await fs.stat(real);\n if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES) return null;\n // A symlink must not bypass the target's ignore policy either.\n if (gitFiles && !gitFiles.has(path.relative(canonicalRoot, real).split(path.sep).join(\"/\"))) return null;\n return real;\n } catch { return null; }\n }\n\n async function list(patterns: string | string[] = SOURCE_GLOB, options: { deep?: number; dot?: boolean } = {}): Promise<string[]> {\n const found = await fg(patterns, { cwd: root, ignore, followSymbolicLinks: false, ...options });\n const safe = await Promise.all(found.map(async f => (await resolve(f)) ? f : null));\n return safe.filter((f): f is string => f !== null).sort();\n }\n\n async function read(file: string): Promise<SourceFile | null> {\n const relative = normalizeRepoPath(file);\n if (!relative) return null;\n const real = await resolve(relative);\n if (!real) return null;\n // Apply the same glob exclusions to explicit reads and symlink targets.\n for (const rel of new Set([relative, path.relative(canonicalRoot, real).split(path.sep).join(\"/\")])) {\n if (!(await fg(fg.escapePath(rel), { cwd: root, ignore, dot: true })).length) return null;\n }\n try {\n const content = await readBoundedFile(real, MAX_SOURCE_BYTES);\n return content === null ? null : { path: relative, content, totalLines: content.split(\"\\n\").length };\n } catch { return null; }\n }\n return { root, config, list, read };\n}\n","import path from \"node:path\";\n\n/** One canonical representation for stored paths and decision anchors. */\nexport function normalizeRepoPath(value: string): string | null {\n const slash = value.replace(/\\\\/g, \"/\");\n if (!slash || slash.includes(\"\\0\") || path.posix.isAbsolute(slash) || /^[A-Za-z]:/.test(slash)) return null;\n if (slash.split(\"/\").includes(\"..\")) return null;\n const normalized = path.posix.normalize(slash).replace(/\\/$/, \"\");\n return normalized === \".\" ? null : normalized;\n}\n\nexport function sanitizeRepoPaths(files: string[]): string[] {\n return [...new Set(files.map(normalizeRepoPath).filter((p): p is string => p !== null))];\n}\n\nexport function isWithinRoot(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\nexport function anchorMatches(anchor: string, file: string): boolean {\n const a = normalizeRepoPath(anchor);\n const f = normalizeRepoPath(file);\n return a !== null && f !== null && (a === f || f.startsWith(`${a}/`));\n}\n\nexport function matchingPaths(anchors: string[], files: Iterable<string>): string[] {\n return [...new Set(files)].filter(file => anchors.some(anchor => anchorMatches(anchor, file)));\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { normalizeRepoPath } from \"./paths.js\";\nimport { readBoundedFile } from \"./files.js\";\n\nexport interface StoreDiagnostic { path: string; message: string }\n\n/** Metadata paths may not contain symlinks, including their parent directories. */\nexport async function storePath(root: string, relative: string, createParents = false): Promise<string> {\n const normalized = normalizeRepoPath(relative);\n if (!normalized) throw new Error(`Invalid store path: ${relative}`);\n let current = await fs.realpath(root);\n const parts = normalized.split(\"/\");\n for (let i = 0; i < parts.length; i++) {\n current = path.join(current, parts[i]);\n let stat;\n try { stat = await fs.lstat(current); } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n if (createParents && i < parts.length - 1) {\n try { await fs.mkdir(current); } catch (mkdirError) {\n if ((mkdirError as NodeJS.ErrnoException).code !== \"EEXIST\") throw mkdirError;\n }\n stat = await fs.lstat(current);\n }\n }\n if (stat?.isSymbolicLink()) throw new Error(`Symlink in store path: ${relative}`);\n }\n return current;\n}\n\nexport async function readStoreJson(root: string, relative: string): Promise<unknown | null> {\n try {\n const file = await storePath(root, relative);\n const raw = await readBoundedFile(file, 10 * 1024 * 1024);\n if (raw === null) throw new Error(\"file is not regular or exceeds 10 MiB\");\n const parsed: unknown = JSON.parse(raw);\n if (parsed === null) throw new Error(\"expected a JSON object, received null\");\n return parsed;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw new Error(`Invalid Mason store ${relative}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });\n }\n}\n\nexport async function writeStoreJson(root: string, relative: string, value: unknown): Promise<void> {\n const payload = JSON.stringify(value, null, 2) + \"\\n\";\n if (Buffer.byteLength(payload) > 10 * 1024 * 1024) {\n throw new Error(`Mason store ${relative} exceeds 10 MiB`);\n }\n const file = await storePath(root, relative, true);\n const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${randomUUID()}.tmp`);\n try {\n const handle = await fs.open(temporary, \"wx\", 0o600);\n try { await handle.writeFile(payload, \"utf8\"); await handle.sync(); }\n finally { await handle.close(); }\n await fs.rename(temporary, file);\n } finally { await fs.rm(temporary, { force: true }); }\n}\n","import path from \"node:path\";\nimport { createFileAccess } from \"./utils/files.js\";\n\nexport interface TestPair {\n test: string;\n source: string;\n confidence: string;\n}\n\nexport interface TestMapResult {\n totalTestFiles: number;\n paired: TestPair[];\n unmatched: string[];\n}\n\nexport async function buildTestMap(dir: string): Promise<TestMapResult> {\n const rootDir = path.resolve(dir);\n const access = await createFileAccess(rootDir);\n\n // Find all test files\n const testPatterns = [\n \"**/*.test.*\", \"**/*.spec.*\",\n \"**/*Test.kt\", \"**/*Test.java\", \"**/*Tests.kt\", \"**/*Tests.java\",\n \"**/test_*.py\", \"**/*_test.py\",\n \"**/*_test.go\",\n \"**/*Tests.swift\", \"**/*Test.swift\",\n \"**/*_test.rs\",\n ];\n const testFiles = await access.list(testPatterns);\n\n // Find all source files\n const sourceFiles = await access.list();\n\n // Build source file index by base name (without extension)\n const sourceByBaseName = new Map<string, string[]>();\n for (const file of sourceFiles) {\n if (testFiles.includes(file)) continue; // Skip test files\n const baseName = path.basename(file).replace(/\\.[^.]+$/, \"\");\n const existing = sourceByBaseName.get(baseName) ?? [];\n existing.push(file);\n sourceByBaseName.set(baseName, existing);\n }\n\n // Match test files to source files by name\n const paired: TestPair[] = [];\n const unmatched: string[] = [];\n\n for (const testFile of testFiles) {\n const testBaseName = path.basename(testFile).replace(/\\.[^.]+$/, \"\");\n\n // Strip test suffixes/prefixes to get the source name\n const sourceName = testBaseName\n .replace(/Test$|Tests$|Spec$|\\.test$|\\.spec$/, \"\")\n .replace(/^test_|_test$/, \"\");\n\n if (!sourceName) {\n unmatched.push(testFile);\n continue;\n }\n\n const candidates = sourceByBaseName.get(sourceName);\n if (candidates && candidates.length > 0) {\n // If multiple candidates, prefer one in a similar directory path\n const testDir = path.dirname(testFile);\n const bestMatch = candidates.reduce((best, candidate) => {\n const candidateDir = path.dirname(candidate);\n const bestDir = path.dirname(best);\n const candidateOverlap = commonSegments(testDir, candidateDir);\n const bestOverlap = commonSegments(testDir, bestDir);\n return candidateOverlap > bestOverlap ? candidate : best;\n });\n\n paired.push({\n test: testFile,\n source: bestMatch,\n confidence: candidates.length === 1 ? \"exact\" : \"best-guess\",\n });\n } else {\n unmatched.push(testFile);\n }\n }\n\n return { totalTestFiles: testFiles.length, paired, unmatched };\n}\n\nfunction commonSegments(pathA: string, pathB: string): number {\n const segsA = pathA.split(\"/\");\n const segsB = pathB.split(\"/\");\n let count = 0;\n for (let i = 0; i < Math.min(segsA.length, segsB.length); i++) {\n if (segsA[i] === segsB[i]) count++;\n else break;\n }\n return count;\n}\n","import { z } from \"zod\";\nimport { normalizeRepoPath } from \"../utils/paths.js\";\nimport { assessTrust, type Freshness } from \"../context/trust.js\";\n\nconst text = (max: number) => z.string().trim().min(1).max(max);\nexport const decisionSourceSchema = z.object({\n kind: z.enum([\"pull_request\", \"issue\", \"incident\", \"discussion\", \"document\", \"other\"]),\n reference: text(1000),\n note: text(500).optional(),\n}).strict();\nexport type DecisionSource = z.infer<typeof decisionSourceSchema>;\nexport const attributionSchema = z.object({\n owner: text(200).nullable().optional(),\n sources: z.array(decisionSourceSchema).max(20).optional(),\n actor: text(200).optional(),\n});\nconst contentSchema = z.object({\n title: z.string().min(1), body: z.string().min(1),\n category: z.enum([\"decision\", \"gotcha\", \"deprecation\", \"convention\"]),\n files: z.array(z.string().refine(f => normalizeRepoPath(f) !== null)),\n owner: text(200).optional(), sources: z.array(decisionSourceSchema).max(20),\n});\nconst approvalSchema = z.enum([\"unreviewed\", \"proposed\", \"accepted\"]);\nconst statusSchema = z.enum([\"active\", \"superseded\", \"retired\"]);\nexport const reviewEvidenceSchema = z.object({\n baseHash: z.string(), headHash: z.string(), historyAvailable: z.boolean(),\n changedFiles: z.array(z.string()), localChanges: z.array(z.string()),\n});\nconst eventSchema = z.object({\n kind: z.enum([\"imported\", \"created\", \"revised\", \"accepted\", \"reaffirmed\", \"retired\", \"superseded\"]),\n at: z.string().datetime(), actor: text(200).optional(), note: text(1500).optional(),\n revision: z.number().int().positive(), content: contentSchema,\n approval: approvalSchema, status: statusSchema, refreshedHash: z.string(),\n evidence: reviewEvidenceSchema.optional(),\n});\nexport type DecisionEvent = z.infer<typeof eventSchema>;\nexport type DecisionApproval = z.infer<typeof approvalSchema>;\nexport type DecisionContent = z.infer<typeof contentSchema>;\n\nconst legacySchema = z.object({\n version: z.literal(1), id: z.string().regex(/^[a-zA-Z0-9_-]+$/),\n title: z.string().min(1), body: z.string().min(1),\n category: contentSchema.shape.category, files: contentSchema.shape.files,\n createdAt: z.string(), updatedAt: z.string(), refreshedHash: z.string(),\n status: z.enum([\"active\", \"superseded\"]), supersededBy: z.string().optional(),\n}).passthrough();\nconst currentSchema = legacySchema.extend({\n version: z.literal(2), status: statusSchema,\n approval: approvalSchema, revision: z.number().int().positive(),\n owner: text(200).optional(), sources: z.array(decisionSourceSchema).max(20),\n history: z.array(eventSchema).min(1),\n}).superRefine((record, ctx) => {\n const invalid = (message: string) => ctx.addIssue({ code: \"custom\", message });\n const same = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b);\n let previous: DecisionEvent | undefined;\n for (const event of record.history) {\n if (!previous) {\n if (![\"created\", \"imported\"].includes(event.kind) || event.revision !== 1) invalid(\"History must begin with creation or legacy import at revision 1\");\n if (event.approval !== (event.kind === \"created\" ? \"proposed\" : \"unreviewed\")) invalid(\"Initial records cannot claim acceptance\");\n } else {\n if ([\"created\", \"imported\"].includes(event.kind)) invalid(\"History cannot restart\");\n if (previous.status !== \"active\") invalid(\"Archived decisions cannot be changed\");\n if (event.revision !== previous.revision + (event.kind === \"revised\" ? 1 : 0)) invalid(\"Invalid revision sequence\");\n if (event.kind !== \"revised\" && !same(event.content, previous.content)) invalid(\"A review cannot silently revise decision content\");\n if (event.kind === \"reaffirmed\" && previous.approval !== \"accepted\") invalid(\"Only accepted decisions can be reaffirmed\");\n if (event.kind === \"accepted\" && previous.approval === \"accepted\") invalid(\"Use reaffirmation for an accepted decision\");\n const approval = event.kind === \"revised\" ? \"proposed\" : [\"accepted\", \"reaffirmed\"].includes(event.kind) ? \"accepted\" : previous.approval;\n if (event.approval !== approval) invalid(\"Approval disagrees with review history\");\n if (![\"accepted\", \"reaffirmed\"].includes(event.kind) && event.refreshedHash !== previous.refreshedHash) invalid(\"Only a review can refresh the evidence baseline\");\n }\n if (event.kind !== \"imported\" && event.status !== (event.kind === \"retired\" ? \"retired\" : event.kind === \"superseded\" ? \"superseded\" : \"active\")) invalid(\"Lifecycle disagrees with history\");\n if ([\"accepted\", \"reaffirmed\", \"retired\"].includes(event.kind) && (!event.actor || !event.note || !event.evidence)) invalid(\"Reviews require a named reviewer, reason, and code evidence\");\n if ([\"accepted\", \"reaffirmed\"].includes(event.kind)) {\n if (!event.content.owner || !event.content.sources.length) invalid(\"Accepted decisions require an owner and source\");\n if (!event.evidence || !/^[a-f0-9]{40,64}$/.test(event.evidence.headHash) || event.refreshedHash !== event.evidence.headHash || event.evidence.localChanges.length) invalid(\"Acceptance requires a committed evidence baseline\");\n }\n previous = event;\n }\n if (!previous || !same(previous.content, decisionContent(record)) || previous.approval !== record.approval || previous.status !== record.status || previous.revision !== record.revision || previous.refreshedHash !== record.refreshedHash) invalid(\"Decision does not match the final history event\");\n});\n\nexport const decisionSchema = z.union([legacySchema, currentSchema]);\nexport type DecisionRecord = z.infer<typeof decisionSchema>;\nexport type ReviewedDecisionRecord = z.infer<typeof currentSchema>;\n\nexport function decisionContent(record: Pick<DecisionRecord, \"title\" | \"body\" | \"category\" | \"files\"> & { owner?: unknown; sources?: unknown }): DecisionContent {\n return { title: record.title, body: record.body, category: record.category, files: record.files,\n ...(typeof record.owner === \"string\" ? { owner: record.owner } : {}),\n sources: Array.isArray(record.sources) ? record.sources as DecisionSource[] : [],\n };\n}\n\n/** Reading legacy records never upgrades their approval or rewrites their files. */\nexport function decisionApproval(record: DecisionRecord): DecisionApproval {\n return record.version === 1 ? \"unreviewed\" : record.approval;\n}\n\n/** The last accepted revision remains operative while a replacement is drafted.\n * This is a read-only projection; writes and review tokens use the complete record.\n * Archived records never regain authority from their history.\n */\nexport function effectiveDecision(record: DecisionRecord): DecisionRecord {\n if (record.version !== 2 || record.status !== \"active\" || record.approval !== \"proposed\") return record;\n let index = record.history.length - 1;\n while (index >= 0 && ![\"accepted\", \"reaffirmed\"].includes(record.history[index].kind)) index--;\n if (index < 0) return record;\n const event = record.history[index];\n return { ...record, ...event.content, owner: event.content.owner, approval: \"accepted\", revision: event.revision,\n refreshedHash: event.refreshedHash, updatedAt: event.at, history: record.history.slice(0, index + 1) };\n}\n\n/** Anchors relevant to either the operative knowledge or its pending proposal. */\nexport function decisionAnchors(record: DecisionRecord): string[] {\n return [...new Set([...effectiveDecision(record).files, ...record.files])];\n}\n\nexport function importLegacy(record: DecisionRecord, now: string): ReviewedDecisionRecord {\n if (record.version === 2) return record;\n // Ignore unrecognized legacy fields: they are not evidence of authorship or approval.\n const content = decisionContent({ title: record.title, body: record.body, category: record.category, files: record.files });\n return { id: record.id, createdAt: record.createdAt, updatedAt: record.updatedAt, status: record.status, refreshedHash: record.refreshedHash, supersededBy: record.supersededBy, ...content, version: 2, approval: \"unreviewed\", revision: 1,\n history: [{ kind: \"imported\", at: now, revision: 1, content, approval: \"unreviewed\", status: record.status, refreshedHash: record.refreshedHash,\n note: \"Imported a legacy record. Prior authorship and review history are unknown.\" }],\n };\n}\n\nexport function decisionProvenance(record: DecisionRecord, freshness: Freshness = \"unknown\") {\n const approval = decisionApproval(record);\n const review = record.version === 2 ? [...record.history].reverse().find(e => [\"accepted\", \"reaffirmed\"].includes(e.kind) && e.revision === record.revision) : undefined;\n return {\n approval, revision: record.version === 2 ? record.revision : 0,\n owner: record.version === 2 ? record.owner ?? null : null,\n sources: record.version === 2 ? record.sources : [],\n guidance: record.status !== \"active\" ? \"historical\" : approval === \"accepted\" ? \"constraint\" : approval === \"proposed\" ? \"proposal\" : \"unreviewed\",\n reviewRequired: record.status === \"active\" && (approval !== \"accepted\" || freshness !== \"current\"),\n lastReview: review ? { reviewer: review.actor!, at: review.at, note: review.note!, gitHash: review.refreshedHash } : null,\n };\n}\n\nexport function decisionTrust(record: DecisionRecord, freshness: Freshness) {\n const review = decisionProvenance(record, freshness).lastReview;\n return assessTrust(review ? { verifiedAt: review.at, verifiedHash: review.gitHash } : {}, freshness);\n}\n\nfunction revisionKnowledge(record: DecisionRecord, freshness: Freshness) {\n return { ...decisionContent(record), ...decisionProvenance(record, freshness), trust: decisionTrust(record, freshness) };\n}\n\n/** Readers show accepted content first and label the unaccepted draft separately. */\nexport function decisionKnowledge(record: DecisionRecord, freshness: Freshness = \"unknown\", proposalFreshness: Freshness = \"unknown\") {\n const effective = effectiveDecision(record);\n return { ...revisionKnowledge(effective, freshness),\n ...(effective !== record ? { pendingProposal: revisionKnowledge(record, proposalFreshness) } : {}) };\n}\n\nexport function compactDecisionKnowledge(...args: Parameters<typeof decisionKnowledge>) {\n const { body, pendingProposal, ...summary } = decisionKnowledge(...args);\n if (!pendingProposal) return summary;\n const { body: proposalBody, ...proposal } = pendingProposal;\n return { ...summary, pendingProposal: proposal };\n}\n\nexport const DECISION_GUIDANCE = \"Accepted decisions are recorded team constraints, subject to freshness checks. A pendingProposal is an unaccepted replacement; the accepted revision remains operative until explicit acceptance or retirement. Proposals are suggestions; legacy unreviewed records need confirmation. Use review_decision to inspect provenance and record an authorized review; identities and sources are recorded assertions, not authenticated proof.\";\n","export type Freshness = \"current\" | \"changed\" | \"unknown\";\nexport interface TrustState {\n freshness: Freshness;\n verification: \"unverified\" | \"passed\" | \"failed\";\n verifiedAt?: string;\n verifiedHash?: string;\n reasons: string[];\n}\n\nexport function assessTrust(entry: { verifiedAt?: string; verifiedHash?: string; verificationFailed?: boolean; verificationNote?: string }, freshness: Freshness): TrustState {\n const verification = entry.verificationFailed ? \"failed\" : entry.verifiedAt ? \"passed\" : \"unverified\";\n const reasons: string[] = [];\n if (freshness === \"unknown\") reasons.push(\"Anchors, history, or working-tree evidence are unavailable; verify before relying on this entry.\");\n if (freshness === \"changed\") reasons.push(\"Anchored files changed; verify against current code before relying on this entry.\");\n if (verification === \"failed\") reasons.push(`Verification failed: ${entry.verificationNote ?? \"re-map this entry before relying on it\"}`);\n if (verification === \"unverified\") reasons.push(\"No correctness verification has been recorded.\");\n return { freshness, verification, verifiedAt: entry.verifiedAt, verifiedHash: entry.verifiedHash, reasons };\n}\n\nexport function trustHint(states: TrustState[]): string {\n const parts: string[] = [];\n if (states.some(s => s.verification === \"failed\")) parts.push(\"Verification failed for returned entries; do not rely on those descriptions until corrected.\");\n if (states.some(s => s.freshness === \"unknown\")) parts.push(\"Freshness is unknown for some returned entries; inspect their files before relying on them.\");\n if (states.some(s => s.freshness === \"changed\")) parts.push(\"Some returned entries have changed files, including possible local edits; verify against the current code.\");\n if (!parts.length) parts.push(\"No changes detected in the returned anchors. This does not prove the descriptions are correct.\");\n if (states.some(s => s.verification === \"unverified\")) parts.push(\"Some entries have never been verified; read their evidence or use verify_snapshot for map descriptions.\");\n return parts.join(\" \");\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\nimport { readStoreJson, writeStoreJson, storePath, type StoreDiagnostic } from \"../utils/storage.js\";\nimport { sanitizeRepoPaths } from \"../utils/paths.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { jaccard, tokenSet } from \"../context/lexical.js\";\nimport { attributionSchema, decisionSchema, decisionContent, decisionApproval, effectiveDecision, importLegacy, type DecisionSource, type DecisionRecord, type ReviewedDecisionRecord } from \"./provenance.js\";\nexport type { DecisionRecord } from \"./provenance.js\";\n\nexport type DecisionCategory =\n | \"decision\"\n | \"gotcha\"\n | \"deprecation\"\n | \"convention\";\nexport type DecisionStatus = \"active\" | \"superseded\" | \"retired\";\n\nexport const TITLE_MAX_CHARS = 80;\nexport const BODY_RECOMMENDED_CHARS = 1500;\nexport const BODY_MAX_CHARS = 2500;\nexport const MAX_ACTIVE_DECISIONS = 150;\n\n// Share validation with MCP so rejected tool calls include the actual length.\nconst boundedText = (field: string, max: number, hint: string) => z.string({\n errorMap: (issue, ctx) => ({ message: issue.code === \"too_big\"\n ? `${field} has ${ctx.data.length} characters; maximum is ${max} (${ctx.data.length - max} over). ${hint}`\n : ctx.defaultError }),\n}).trim().min(1, `${field} must be non-empty`).max(max);\n\nexport const decisionTitleSchema = boundedText(\"title\", TITLE_MAX_CHARS, \"Tighten it to a specific headline.\");\nexport const decisionBodySchema = boundedText(\"body\", BODY_MAX_CHARS,\n `Aim for ${BODY_RECOMMENDED_CHARS} characters or fewer. Preserve the rule, reason, and exceptions; put supporting references in sources.`);\n\nconst DUPLICATE_JACCARD = 0.5;\nconst DUPLICATE_JACCARD_WITH_SHARED_FILE = 0.35;\n\nexport async function loadDecisionStore(rootDir: string): Promise<{ records: DecisionRecord[]; diagnostics: StoreDiagnostic[] }> {\n const records: DecisionRecord[] = [];\n const diagnostics: StoreDiagnostic[] = [];\n let entries: string[];\n try { entries = await fs.readdir(await storePath(rootDir, \".mason/decisions\")); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") diagnostics.push({ path: \".mason/decisions\", message: String(error) });\n return { records, diagnostics };\n }\n for (const entry of entries.sort()) {\n if (!entry.endsWith(\".json\")) continue;\n const relative = `.mason/decisions/${entry}`;\n try {\n const record = decisionSchema.parse(await readStoreJson(rootDir, relative));\n if (entry !== `${record.id}.json`) throw new Error(\"Record id does not match its filename\");\n records.push(record);\n } catch (error) { diagnostics.push({ path: relative, message: error instanceof Error ? error.message : String(error) }); }\n }\n return { records, diagnostics };\n}\n\nexport async function loadDecisions(rootDir: string): Promise<DecisionRecord[]> {\n return (await loadDecisionStore(rootDir)).records;\n}\n\nexport async function saveDecisionRecord(rootDir: string, record: DecisionRecord): Promise<void> {\n const validated = decisionSchema.parse(record);\n await writeStoreJson(rootDir, `.mason/decisions/${validated.id}.json`, validated);\n}\n\n/**\n * Deterministic, human-readable id: base slug ≤60 chars, ending at a word\n * boundary when possible. A single longer word is cut to fit.\n * A slug collision with a DIFFERENT record appends a 6-hex content suffix.\n */\nexport function decisionIdFor(\n title: string,\n body: string,\n existingIds: Set<string>\n): string {\n const fullSlug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n let slug = fullSlug.slice(0, 60);\n if (fullSlug.length > 60 && fullSlug[60] !== \"-\") {\n const boundary = slug.lastIndexOf(\"-\");\n if (boundary > 0) slug = slug.slice(0, boundary);\n }\n slug = slug.replace(/-+$/, \"\") || \"decision\";\n if (!existingIds.has(slug)) return slug;\n const suffix = createHash(\"sha1\")\n .update(title + body)\n .digest(\"hex\")\n .slice(0, 6);\n return `${slug}-${suffix}`;\n}\n\nexport function findNearDuplicate(\n candidate: { title: string; body: string; files: string[] },\n existing: DecisionRecord[]\n): { record: DecisionRecord; similarity: number } | null {\n const candidateTokens = tokenSet(`${candidate.title} ${candidate.body}`);\n const candidateFiles = new Set(candidate.files);\n let best: { record: DecisionRecord; similarity: number } | null = null;\n\n for (const record of existing) {\n if (record.status !== \"active\") continue;\n const similarity = jaccard(\n candidateTokens,\n tokenSet(`${record.title} ${record.body}`)\n );\n const sharesFile = record.files.some((f) => candidateFiles.has(f));\n const threshold = sharesFile\n ? DUPLICATE_JACCARD_WITH_SHARED_FILE\n : DUPLICATE_JACCARD;\n if (similarity >= threshold && (!best || similarity > best.similarity)) {\n best = { record, similarity };\n }\n }\n return best;\n}\n\nexport interface UpsertDecisionInput {\n title: string;\n body: string;\n category: DecisionCategory;\n files?: string[];\n owner?: string | null;\n sources?: DecisionSource[];\n /** Only supply a known identity; never infer authorship from Git configuration. */\n actor?: string;\n /** Existing id to revise. Unchanged content is a no-op; use review_decision to reaffirm. */\n id?: string;\n /** Id of a decision this one replaces; the old record is kept, marked superseded. */\n supersedes?: string;\n /** Save even when a near-duplicate was detected. */\n force?: boolean;\n}\n\nexport type UpsertDecisionResult =\n | {\n status: \"created\" | \"updated\" | \"unchanged\" | \"superseded_and_created\";\n id: string;\n totalActive: number;\n warnings: string[];\n approval?: \"unreviewed\" | \"proposed\" | \"accepted\";\n hint?: string;\n pruneCandidates?: string[];\n }\n | { status: \"duplicate_suspected\"; existing: DecisionRecord; hint: string }\n | { status: \"error\"; error: string };\n\n/** Serialize tool writes so prepared reviews cannot overwrite another decision edit. */\nexport async function withDecisionWrite<T>(root: string, operation: () => Promise<T>): Promise<T | { status: \"error\"; error: string }> {\n const lockPath = await storePath(root, \".mason/decisions/.write-lock\", true);\n let lock;\n try { lock = await fs.open(lockPath, \"wx\", 0o600); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") return { status: \"error\", error: \"Decision store is locked by another write. Retry after it finishes; an abandoned .mason/decisions/.write-lock must be removed only after confirming no writer is running.\" };\n throw error;\n }\n try { return await operation(); }\n finally { await lock.close(); await fs.unlink(lockPath); }\n}\n\nexport async function upsertDecision(rootDir: string, input: UpsertDecisionInput): Promise<UpsertDecisionResult> {\n const parsedTitle = decisionTitleSchema.safeParse(input.title), parsedBody = decisionBodySchema.safeParse(input.body);\n if (!parsedTitle.success) return { status: \"error\", error: parsedTitle.error.issues[0].message };\n if (!parsedBody.success) return { status: \"error\", error: parsedBody.error.issues[0].message };\n const title = parsedTitle.data, body = parsedBody.data;\n const attribution = attributionSchema.safeParse(input);\n if (!attribution.success) return { status: \"error\", error: attribution.error.message };\n if (input.id && input.supersedes) return { status: \"error\", error: \"Use either id to revise or supersedes to replace a record, not both.\" };\n return withDecisionWrite(rootDir, async () => {\n const store = await loadDecisionStore(rootDir);\n if (store.diagnostics.length) return { status: \"error\", error: \"Repair malformed decision records before saving: \" + store.diagnostics.map(d => d.path).join(\", \") };\n const existing = store.records, byId = new Map(existing.map(r => [r.id, r]));\n const now = new Date().toISOString(), head = await getCurrentGitHash(rootDir);\n const warnings: string[] = [];\n if (body.length > BODY_RECOMMENDED_CHARS) warnings.push(`body has ${body.length} characters, above the recommended ${BODY_RECOMMENDED_CHARS}; matching context and hooks include it in full. Keep the rule, reason, and exceptions concise; use sources for supporting references.`);\n const files = sanitizeRepoPaths(input.files ?? []);\n if (input.files && files.length < input.files.length) warnings.push(\"some anchor paths were outside the repo or duplicated and were dropped\");\n for (const file of files) {\n try { await fs.access(path.join(rootDir, file)); }\n catch { warnings.push(`anchor file does not exist on disk: ${file}`); }\n }\n const hint = \"Saved locally for review and commit. Proposals are not accepted constraints; an existing accepted revision remains operative while its replacement is proposed. Use review_decision to inspect evidence and record an authorized acceptance or reaffirmation.\";\n if (input.id) {\n const original = byId.get(input.id);\n if (!original) return { status: \"error\", error: `no decision with id \"${input.id}\"` };\n if (original.status !== \"active\") return { status: \"error\", error: \"Archived records cannot be revised; create a new proposal.\" };\n const record = importLegacy(original, now);\n const content = decisionContent({ ...record, title, body, category: input.category,\n files: input.files !== undefined ? files : record.files,\n owner: attribution.data.owner === undefined ? record.owner : attribution.data.owner ?? undefined,\n sources: attribution.data.sources ?? record.sources,\n });\n if (JSON.stringify(content) === JSON.stringify(decisionContent(record))) {\n return { status: \"unchanged\", id: record.id, totalActive: existing.filter(r => r.status === \"active\").length, approval: decisionApproval(original), warnings,\n hint: \"Unchanged content; no review or freshness stamp was written. Use review_decision for explicit re-verification.\" };\n }\n const revision = record.revision + 1;\n const updated: ReviewedDecisionRecord = { ...record, ...content, owner: content.owner, updatedAt: now, revision, approval: \"proposed\",\n history: [...record.history, { kind: \"revised\", at: now, actor: attribution.data.actor, revision, content, approval: \"proposed\", status: \"active\", refreshedHash: record.refreshedHash }],\n };\n await saveDecisionRecord(rootDir, updated);\n return { status: \"updated\", id: record.id, totalActive: existing.filter(r => r.status === \"active\").length, approval: \"proposed\", warnings, hint };\n }\n const old = input.supersedes ? byId.get(input.supersedes) : undefined;\n if (input.supersedes && !old) return { status: \"error\", error: `no decision with id \"${input.supersedes}\" to supersede` };\n if (old && (old.status !== \"active\" || decisionApproval(effectiveDecision(old)) === \"accepted\")) {\n return { status: \"error\", error: \"A proposal cannot supersede an accepted or archived record. Create and review the replacement separately, then explicitly retire the old decision with review_decision.\" };\n }\n if (!input.force) {\n const duplicate = findNearDuplicate({ title, body, files }, existing);\n if (duplicate) return { status: \"duplicate_suspected\", existing: duplicate.record, hint: `A similar decision exists (\"${duplicate.record.title}\"). Call save_decision with id=\"${duplicate.record.id}\" to revise it, or force:true if distinct.` };\n }\n const id = decisionIdFor(title, body, new Set(byId.keys()));\n if (byId.has(id)) return { status: \"error\", error: `Decision id collision: ${id}. Choose a distinct title or revise the existing record.` };\n const content = decisionContent({ title, body, category: input.category, files, owner: attribution.data.owner ?? undefined, sources: attribution.data.sources ?? [] });\n const record: ReviewedDecisionRecord = { ...content, version: 2, id, createdAt: now, updatedAt: now, refreshedHash: head,\n status: \"active\", approval: \"proposed\", revision: 1,\n history: [{ kind: \"created\", at: now, actor: attribution.data.actor, revision: 1, content, approval: \"proposed\", status: \"active\", refreshedHash: head }],\n };\n // Write the replacement first: a failed second write leaves both records\n // available instead of removing the original before its replacement exists.\n await saveDecisionRecord(rootDir, record);\n if (old) {\n const imported = importLegacy(old, now);\n await saveDecisionRecord(rootDir, { ...imported, status: \"superseded\", supersededBy: id, updatedAt: now,\n history: [...imported.history, { kind: \"superseded\", at: now, actor: attribution.data.actor, note: `Replaced by proposal ${id}`,\n revision: imported.revision, content: decisionContent(imported), approval: imported.approval, status: \"superseded\", refreshedHash: imported.refreshedHash }],\n });\n }\n const totalActive = existing.filter(r => r.status === \"active\").length + (old ? 0 : 1);\n const result: UpsertDecisionResult = { status: old ? \"superseded_and_created\" : \"created\", id, totalActive, approval: \"proposed\", warnings, hint };\n if (totalActive > MAX_ACTIVE_DECISIONS) {\n result.pruneCandidates = existing.filter(r => r.status !== \"active\").map(r => r.id).slice(0, 10);\n warnings.push(`${totalActive} active decisions exceeds the soft cap of ${MAX_ACTIVE_DECISIONS} — consider a cleanup PR (archived records first)`);\n }\n return result;\n });\n}\n","import path from \"node:path\";\n\n// Question/filler words that carry no signal about which entry a task\n// touches. Domain words (\"auth\", \"drift\") are never in this list.\nconst STOPWORDS = new Set([\n \"the\", \"a\", \"an\", \"and\", \"or\", \"of\", \"to\", \"in\", \"on\", \"for\", \"with\",\n \"how\", \"does\", \"do\", \"is\", \"are\", \"was\", \"what\", \"where\", \"which\", \"why\",\n \"when\", \"who\", \"i\", \"we\", \"my\", \"our\", \"you\", \"your\", \"it\", \"its\", \"this\",\n \"that\", \"these\", \"those\", \"can\", \"could\", \"should\", \"would\", \"will\",\n \"want\", \"need\", \"please\", \"about\", \"into\", \"from\", \"when\", \"there\", \"any\",\n \"all\", \"some\", \"not\", \"but\", \"also\", \"just\", \"like\", \"get\", \"make\", \"use\",\n \"new\", \"work\", \"works\", \"working\", \"implement\", \"implemented\", \"change\",\n \"changed\", \"file\", \"files\", \"code\",\n]);\n\n/** Split camelCase/PascalCase/kebab/snake/path into lowercase word tokens. */\nexport function tokenize(text: string): string[] {\n return text\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 2 && !STOPWORDS.has(t));\n}\n\n/** Crude singular/plural folding so \"flows\" matches \"flow\" etc. */\nexport function stem(token: string): string {\n return token.length > 3 && token.endsWith(\"s\") ? token.slice(0, -1) : token;\n}\n\nexport function tokenSet(text: string): Set<string> {\n return new Set(tokenize(text).map(stem));\n}\n\nexport interface Scorable {\n name: string;\n description: string;\n files: string[];\n}\n\n/**\n * Lexical relevance of one entry to the task. Name hits are the strongest\n * signal, then description, then file-path words. Each distinct task token\n * counts once at its best weight, so a token appearing everywhere doesn't\n * triple-count.\n */\nexport function scoreEntry(taskTokens: Set<string>, entry: Scorable): number {\n const nameTokens = tokenSet(entry.name);\n const descTokens = tokenSet(entry.description);\n const fileTokens = tokenSet(entry.files.map((f) => path.basename(f)).join(\" \"));\n\n let score = 0;\n for (const token of taskTokens) {\n if (nameTokens.has(token)) score += 3;\n else if (descTokens.has(token)) score += 1;\n else if (fileTokens.has(token)) score += 1;\n }\n return score;\n}\n\n/** Jaccard similarity of two token sets: |∩| / |∪|, 0 when both empty. */\nexport function jaccard(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 0;\n let intersection = 0;\n for (const token of a) if (b.has(token)) intersection++;\n return intersection / (a.size + b.size - intersection);\n}\n","import path from \"node:path\";\nimport { getChangesWithStatus, getWorkingTree, touchedPaths } from \"../drift/drift.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport type { StoreDiagnostic } from \"../utils/storage.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { loadDecisionStore } from \"./decisions.js\";\nimport type { DecisionRecord } from \"./decisions.js\";\nimport { effectiveDecision } from \"./provenance.js\";\n\n/**\n * Deliberately separate from DriftReport: mason-drift's exit codes and\n * --json shape are a CI contract, and `stale` there means MAP staleness.\n * Decision staleness is additive on top.\n */\nexport interface DecisionDriftReport {\n historyAvailable: boolean;\n freshness?: Record<string, Freshness>;\n diagnostics?: StoreDiagnostic[];\n totalDecisions: number;\n /** Decision id → anchor files changed since the record's refreshedHash. */\n staleDecisions: Record<string, string[]>;\n /** Draft anchors have their own freshness; they cannot replace accepted anchors. */\n pendingProposals?: Record<string, { freshness: Freshness; changedFiles: string[] }>;\n}\n\n/**\n * Flag active decisions whose anchor files changed since the record was\n * last verified. Anchorless decisions have unknown freshness and do not\n * contribute to committed drift.\n * Deterministic — git only, no LLM.\n */\nexport async function computeDecisionDrift(\n rootDir: string,\n decisions?: DecisionRecord[]\n): Promise<DecisionDriftReport> {\n const resolvedRoot = path.resolve(rootDir);\n const store = decisions ? { records: decisions, diagnostics: [] } : await loadDecisionStore(resolvedRoot);\n const report: DecisionDriftReport = { historyAvailable: true, totalDecisions: store.records.length, staleDecisions: {}, freshness: {}, diagnostics: store.diagnostics };\n const [head, workingTree] = await Promise.all([getCurrentGitHash(resolvedRoot), getWorkingTree(resolvedRoot)]);\n const changesByHash = new Map<string, string[] | null>();\n const inspect = async (record: DecisionRecord): Promise<{ freshness: Freshness; changedFiles: string[] }> => {\n if (record.files.length === 0) return { freshness: \"unknown\", changedFiles: [] };\n let touched = changesByHash.get(record.refreshedHash);\n if (touched === undefined) {\n const changes = record.refreshedHash === head && head !== \"unknown\" ? [] : await getChangesWithStatus(resolvedRoot, record.refreshedHash);\n touched = changes === null ? null : touchedPaths(changes);\n changesByHash.set(record.refreshedHash, touched);\n }\n if (touched === null) report.historyAvailable = false;\n const hits = touched ? matchingPaths(record.files, touched) : [];\n const localHits = matchingPaths(record.files, workingTree.changedFiles);\n return { freshness: touched === null || !workingTree.available ? \"unknown\" : hits.length || localHits.length ? \"changed\" : \"current\", changedFiles: hits };\n };\n for (const record of store.records) {\n if (record.status !== \"active\") continue;\n const effective = effectiveDecision(record);\n const state = await inspect(effective);\n report.freshness![record.id] = state.freshness;\n if (state.changedFiles.length) report.staleDecisions[record.id] = state.changedFiles;\n if (effective !== record) (report.pendingProposals ??= {})[record.id] = await inspect(record);\n }\n return report;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst exec = promisify(execFile);\n\n/**\n * History window for the co-change matrix. One capped git log for the whole\n * repo — unlike impact.ts's per-target walk, review analyzes many files at\n * once and needs a single pass.\n */\nconst HISTORY_COMMITS = 1500;\n\n/** Below this many commits for a file, a co-change rate is noise. */\nconst MIN_FILE_COMMITS = 5;\n/** A partner must share at least this many commits to count. */\nconst MIN_SHARED_COMMITS = 4;\n/** ...and appear in at least this fraction of the changed file's commits. */\nconst MIN_COCHANGE_RATE = 0.6;\n/** Commits touching more files than this are refactors, not signal. */\nconst MAX_COMMIT_FILES = 30;\n\nexport interface CochangeFinding {\n changedFile: string;\n missingPartner: string;\n sharedCommits: number;\n fileCommits: number;\n /** sharedCommits / fileCommits, rounded to 2 places. */\n rate: number;\n}\n\ninterface CochangeMatrix {\n commitsByFile: Map<string, Set<number>>;\n totalCommits: number;\n}\n\nasync function buildMatrix(resolvedRoot: string): Promise<CochangeMatrix | null> {\n try {\n const { stdout: shallow } = await exec(\"git\", [\"rev-parse\", \"--is-shallow-repository\"], { cwd: resolvedRoot });\n if (shallow.trim() === \"true\") return null;\n const { stdout } = await exec(\n \"git\",\n [\"log\", `-n${HISTORY_COMMITS}`, \"--format=%x01\", \"--name-only\", \"-M\"],\n { cwd: resolvedRoot, maxBuffer: 100 * 1024 * 1024 }\n );\n const commitsByFile = new Map<string, Set<number>>();\n const blocks = stdout.split(\"\\x01\");\n let index = 0;\n for (const block of blocks) {\n const files = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\".mason/\"));\n if (files.length === 0 || files.length > MAX_COMMIT_FILES) continue;\n for (const file of files) {\n let set = commitsByFile.get(file);\n if (!set) {\n set = new Set();\n commitsByFile.set(file, set);\n }\n set.add(index);\n }\n index++;\n }\n return { commitsByFile, totalCommits: index };\n } catch {\n return null;\n }\n}\n\n/**\n * For each changed file, find its historical co-change partners that this\n * diff leaves untouched: files that appeared in >= MIN_COCHANGE_RATE of the\n * changed file's commits (within the window) but are absent from the diff.\n * Deterministic — pure git history, no LLM. Returns null when history is\n * unavailable.\n */\nexport async function findMissingPartners(\n resolvedRoot: string,\n changedFiles: string[],\n existsOnDisk: (relPath: string) => Promise<boolean>,\n allChangedFiles: string[] = changedFiles\n): Promise<CochangeFinding[] | null> {\n const matrix = await buildMatrix(resolvedRoot);\n if (!matrix) return null;\n\n const changedSet = new Set(allChangedFiles);\n const findings: CochangeFinding[] = [];\n\n for (const changedFile of changedFiles) {\n const fileCommits = matrix.commitsByFile.get(changedFile);\n if (!fileCommits || fileCommits.size < MIN_FILE_COMMITS) continue;\n\n for (const [partner, partnerCommits] of matrix.commitsByFile) {\n if (partner === changedFile || changedSet.has(partner)) continue;\n let shared = 0;\n for (const c of fileCommits) {\n if (partnerCommits.has(c)) shared++;\n }\n if (shared < MIN_SHARED_COMMITS) continue;\n const rate = shared / fileCommits.size;\n if (rate < MIN_COCHANGE_RATE) continue;\n if (!(await existsOnDisk(partner))) continue;\n findings.push({\n changedFile,\n missingPartner: partner,\n sharedCommits: shared,\n fileCommits: fileCommits.size,\n rate: Math.round(rate * 100) / 100,\n });\n }\n }\n\n findings.sort((a, b) => b.rate - a.rate || b.sharedCommits - a.sharedCommits);\n return findings;\n}\n","import path from \"node:path\";\nimport { z } from \"zod\";\nimport { readStoreJson } from \"../utils/storage.js\";\nimport { normalizeRepoPath, matchingPaths } from \"../utils/paths.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { getWorkingTree } from \"../drift/drift.js\";\nimport { buildTestMap, type TestPair } from \"../test-map.js\";\nimport { decisionApproval, decisionProvenance, effectiveDecision, type DecisionRecord } from \"../decisions/provenance.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport { parseVitest } from \"./evidence/vitest.js\";\nimport { parseSarif } from \"./evidence/sarif.js\";\nimport { MAX_FINDINGS, type CheckOutcome, type RawFinding, type ParsedEvidence } from \"./evidence/types.js\";\n\nconst checkSchema = z.object({\n id: z.string().min(1).max(100), kind: z.enum([\"tests\", \"static-analysis\", \"security\", \"complexity\", \"duplication\"]),\n tool: z.string().min(1).max(200), command: z.string().min(1).max(2000),\n commit: z.string().regex(/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/).nullable().optional(),\n workingTreeClean: z.boolean().optional(),\n source: z.string().max(2000).optional(), sourceRoot: z.string().min(1).max(4000).optional(),\n status: z.enum([\"completed\", \"skipped\", \"unavailable\"]).default(\"completed\"), reason: z.string().min(1).max(2000).optional(),\n exitCode: z.number().int().nullable().optional(),\n report: z.object({ format: z.enum([\"vitest-json\", \"sarif\"]), path: z.string().min(1).max(4000) }).optional(),\n});\ntype CheckInput = z.infer<typeof checkSchema>;\nexport interface LinkedFinding extends RawFinding {\n relatedChangedFiles: Array<{ file: string; relationship: \"direct\" | \"paired-test\"; confidence?: string }>;\n acceptedDecisions: Array<{ id: string; title: string; owner: string | null; freshness: Freshness; reviewRequired: boolean; viaFiles: string[] }>;\n totalAcceptedDecisions: number;\n}\nexport interface EvidenceCheck {\n id: string; kind: CheckInput[\"kind\"]; tool: string; command: string; commit: string | null;\n workingTreeClean: boolean | null;\n source: string | null; manifest: string; report: CheckInput[\"report\"] | null;\n outcome: CheckOutcome; freshness: \"current\" | \"stale\" | \"unknown\";\n findings: LinkedFinding[]; totalFindings: number; counts: Record<string, number>;\n incomplete: boolean; diagnostics: string[]; truncated: boolean;\n reportedCommands?: string[]; reportedTools?: string[];\n}\nexport interface ReviewEvidence {\n version: 1; scope: \"committed\"; headHash: string;\n status: \"passed\" | \"failed\" | \"incomplete\" | \"unavailable\";\n checks: EvidenceCheck[]; diagnostics: string[];\n summary: { passed: number; failed: number; skipped: number; unavailable: number; stale: number; unknown: number };\n workingTree: Awaited<ReturnType<typeof getWorkingTree>>;\n hint: string;\n}\n\nfunction relativeArtifact(root: string, file: string): string {\n const relative = path.isAbsolute(file) ? path.relative(root, file) : file;\n const normalized = normalizeRepoPath(relative);\n if (!normalized) throw new Error(`Evidence artifact must be inside the repository: ${file}`);\n return normalized;\n}\n\nfunction linkFinding(finding: RawFinding, changed: Set<string>, pairs: TestPair[], decisions: DecisionRecord[], freshness: Record<string, Freshness>): LinkedFinding {\n const located = [...new Set(finding.locations.map(l => l.file))];\n const paired = pairs.filter(pair => located.includes(pair.test));\n const relatedChangedFiles: LinkedFinding[\"relatedChangedFiles\"] = located.filter(file => changed.has(file)).map(file => ({ file, relationship: \"direct\" }));\n for (const pair of paired) {\n if (changed.has(pair.source) && !relatedChangedFiles.some(f => f.file === pair.source)) relatedChangedFiles.push({ file: pair.source, relationship: \"paired-test\", confidence: pair.confidence });\n }\n const allFiles = [...new Set([...located, ...paired.map(pair => pair.source)])];\n const acceptedDecisions = decisions.map(effectiveDecision).filter(d => d.status === \"active\" && decisionApproval(d) === \"accepted\")\n .map(d => ({ d, viaFiles: matchingPaths(d.files, allFiles) })).filter(match => match.viaFiles.length)\n .map(({ d, viaFiles }) => {\n const state = freshness[d.id] ?? \"unknown\", provenance = decisionProvenance(d, state);\n return { id: d.id, title: d.title, owner: provenance.owner, freshness: state, reviewRequired: provenance.reviewRequired, viaFiles };\n });\n return { ...finding, relatedChangedFiles, acceptedDecisions: acceptedDecisions.slice(0, 5), totalAcceptedDecisions: acceptedDecisions.length };\n}\n\n/** Read-only imports. Commands, URLs, and result locations are never executed or fetched. */\nexport async function collectReviewEvidence(root: string, manifests: string[], changedFiles: string[], decisions: DecisionRecord[], decisionFreshness: Record<string, Freshness> = {}, reviewedHead?: string): Promise<ReviewEvidence> {\n const [headHash, workingTree] = await Promise.all([reviewedHead ?? getCurrentGitHash(root), getWorkingTree(root)]);\n const output: ReviewEvidence = {\n version: 1, scope: \"committed\", headHash, status: \"unavailable\", checks: [], diagnostics: [], workingTree,\n summary: { passed: 0, failed: 0, skipped: 0, unavailable: 0, stale: 0, unknown: 0 },\n hint: \"Evidence describes the recorded check runs for a commit, not uncommitted edits or complete test coverage. Commands and CI provenance are imported assertions, not authenticated execution. File and test-pair associations identify relevant decisions; they do not prove a decision was violated. Missing checks must be declared in the manifest to be reported.\",\n };\n const seen = new Set<string>(), changed = new Set(changedFiles);\n let pairs: TestPair[] | undefined;\n if (manifests.length > 10) output.diagnostics.push(\"Only the first 10 evidence manifests were imported.\");\n for (const supplied of manifests.slice(0, 10)) {\n let manifest: string, raw: { version: 1; checks: unknown[] };\n try {\n manifest = relativeArtifact(root, supplied);\n raw = z.object({ version: z.literal(1), checks: z.array(z.unknown()) }).parse(await readStoreJson(root, manifest));\n } catch (error) { output.diagnostics.push(`${supplied}: ${String(error)}`); continue; }\n if (!raw.checks.length) output.diagnostics.push(`${manifest}: no checks declared.`);\n for (const [index, item] of raw.checks.entries()) {\n if (output.checks.length >= 50) { output.diagnostics.push(\"Only the first 50 checks were imported.\"); break; }\n const input = checkSchema.safeParse(item);\n if (!input.success) { output.diagnostics.push(`${manifest} check ${index}: ${input.error.message}`); continue; }\n const check = input.data;\n if (seen.has(check.id)) { output.diagnostics.push(`Duplicate check id ${check.id}; give different runs distinct ids.`); continue; }\n seen.add(check.id);\n const result: EvidenceCheck = {\n id: check.id, kind: check.kind, tool: check.tool, command: check.command,\n commit: check.commit?.toLowerCase() ?? null, workingTreeClean: check.workingTreeClean ?? null, source: check.source ?? null, manifest, report: check.report ?? null,\n outcome: \"unavailable\", freshness: \"unknown\", findings: [], totalFindings: 0, counts: {}, incomplete: false, diagnostics: [], truncated: false,\n };\n output.checks.push(result);\n if (check.workingTreeClean !== true) result.diagnostics.push(\"The check's working tree was dirty or not recorded; its results cannot be attributed to the claimed commit alone.\");\n else if (result.commit && headHash !== \"unknown\") result.freshness = result.commit === headHash.toLowerCase() ? \"current\" : \"stale\";\n else result.diagnostics.push(\"The tested commit or reviewed HEAD is unknown.\");\n if (check.status !== \"completed\") {\n result.outcome = check.status;\n result.diagnostics.push(check.reason ?? \"No reason was recorded for this skipped or unavailable check.\");\n continue;\n }\n try {\n if (!check.report) throw new Error(\"Completed check has no report artifact.\");\n if ((check.kind === \"tests\") !== (check.report.format === \"vitest-json\")) throw new Error(\"Test checks require vitest-json; analysis checks require sarif.\");\n const file = relativeArtifact(root, check.report.path);\n const report = await readStoreJson(root, file);\n if (report === null) throw new Error(`Report artifact is missing: ${file}`);\n const sourceRoot = check.sourceRoot ?? root;\n if (!path.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\\\/]/.test(sourceRoot)) throw new Error(\"sourceRoot must identify the absolute checkout root on the check runner.\");\n const parsed: ParsedEvidence = check.report.format === \"vitest-json\" ? parseVitest(report, sourceRoot) : parseSarif(report, sourceRoot);\n result.outcome = parsed.outcome; result.counts = parsed.counts; result.incomplete = parsed.incomplete;\n result.diagnostics.push(...parsed.diagnostics);\n result.reportedCommands = parsed.reportedCommands; result.reportedTools = parsed.reportedTools;\n if (parsed.reportedCommits?.some(commit => !result.commit || commit.toLowerCase() !== result.commit)) {\n result.freshness = \"unknown\"; result.incomplete = true;\n result.diagnostics.push(\"Report revision metadata conflicts with, or cannot be tied to, the manifest's tested commit.\");\n }\n if (check.exitCode == null && !parsed.executed) {\n result.incomplete = true; result.diagnostics.push(\"Neither an exit code nor successful analysis invocation was recorded; completion cannot be confirmed.\");\n }\n if (check.exitCode != null && check.exitCode !== 0 && result.outcome === \"passed\") {\n result.outcome = \"failed\"; result.diagnostics.push(`Check command exited ${check.exitCode} despite a report with no active failures.`);\n }\n if (check.report.format === \"vitest-json\" && pairs === undefined) {\n try { pairs = (await buildTestMap(root)).paired; }\n catch (error) { pairs = []; output.diagnostics.push(`Test pairing unavailable: ${String(error)}`); }\n }\n result.totalFindings = parsed.findings.length;\n // Prioritize findings on changed files while retaining overall outcomes and counts.\n const testPairs = check.kind === \"tests\" ? pairs ?? [] : [];\n const relevant = new Set([...changed, ...testPairs.filter(p => changed.has(p.source)).map(p => p.test)]);\n const touchesChange = (f: RawFinding) => f.locations.some(l => relevant.has(l.file));\n parsed.findings.sort((a, b) => Number(b.state === \"active\") - Number(a.state === \"active\") || Number(touchesChange(b)) - Number(touchesChange(a)));\n result.findings = parsed.findings.slice(0, MAX_FINDINGS).map(f => linkFinding(f, changed, testPairs, decisions, decisionFreshness));\n result.truncated = parsed.findings.length > MAX_FINDINGS || result.findings.some(f => f.truncated || f.totalAcceptedDecisions > f.acceptedDecisions.length);\n } catch (error) {\n result.outcome = \"unavailable\"; result.incomplete = true; result.diagnostics.push(String(error));\n }\n }\n }\n if (!output.checks.length) output.diagnostics.push(\"No readable checks were imported.\");\n for (const check of output.checks) {\n output.summary[check.outcome]++;\n if (check.freshness !== \"current\") output.summary[check.freshness]++;\n }\n if (output.checks.some(c => c.outcome === \"failed\" && c.freshness === \"current\")) output.status = \"failed\";\n else if (!output.checks.length || output.checks.every(c => c.outcome === \"unavailable\")) output.status = \"unavailable\";\n else if (output.diagnostics.length || output.checks.some(c => c.outcome !== \"passed\" || c.freshness !== \"current\" || c.incomplete)) output.status = \"incomplete\";\n else output.status = \"passed\";\n return output;\n}\n\nexport function summarizeEvidence(evidence: ReviewEvidence) {\n const previews = (values: string[], limit: number) => values.slice(0, limit).map(value => value.slice(0, 2000));\n const checks = evidence.checks.slice(0, 10).map(check => {\n const findings = check.findings.slice(0, 5).map(finding => ({ ...finding,\n ruleId: finding.ruleId?.slice(0, 200),\n locations: finding.locations.slice(0, 5), totalLocations: finding.locations.length,\n relatedChangedFiles: finding.relatedChangedFiles.slice(0, 5), totalRelatedChangedFiles: finding.relatedChangedFiles.length,\n acceptedDecisions: finding.acceptedDecisions.map(decision => ({ ...decision, viaFiles: decision.viaFiles.slice(0, 5) })),\n truncated: finding.truncated || finding.locations.length > 5 || finding.relatedChangedFiles.length > 5 ||\n (finding.ruleId?.length ?? 0) > 200 || finding.acceptedDecisions.some(d => d.viaFiles.length > 5),\n }));\n return { ...check, findings, reportedCommands: check.reportedCommands ? previews(check.reportedCommands, 5) : undefined,\n reportedTools: check.reportedTools ? previews(check.reportedTools, 5) : undefined,\n diagnostics: previews(check.diagnostics, 10),\n truncated: check.truncated || check.findings.length > 5 || findings.some(f => f.truncated) || check.diagnostics.length > 10 ||\n check.diagnostics.some(d => d.length > 2000) || [check.reportedCommands ?? [], check.reportedTools ?? []].some(values => values.length > 5 || values.some(v => v.length > 2000)),\n };\n });\n return { ...evidence, checks, diagnostics: previews(evidence.diagnostics, 20),\n truncated: evidence.checks.length > 10 || evidence.diagnostics.length > 20 || evidence.diagnostics.some(d => d.length > 2000) || checks.some(c => c.truncated),\n };\n}\n","import { z } from \"zod\";\nimport { evidencePath } from \"./paths.js\";\nimport { messagePreview, type ParsedEvidence, type RawFinding } from \"./types.js\";\n\nconst count = z.number().int().nonnegative();\nconst schema = z.object({\n success: z.boolean(), numTotalTests: count, numPassedTests: count, numFailedTests: count,\n numPendingTests: count, numTodoTests: count, numFailedTestSuites: count,\n testResults: z.array(z.object({\n name: z.string().min(1), status: z.enum([\"passed\", \"failed\"]), message: z.string().optional(),\n assertionResults: z.array(z.object({\n fullName: z.string(), status: z.enum([\"passed\", \"failed\", \"pending\", \"skipped\", \"todo\", \"disabled\"]),\n failureMessages: z.array(z.string()).nullable().optional(),\n location: z.object({ line: count, column: count }).nullable().optional(),\n })),\n })),\n});\n\n/** Vitest JSON reporter output; summary and assertion counts must agree. */\nexport function parseVitest(raw: unknown, sourceRoot: string): ParsedEvidence {\n const report = schema.parse(raw);\n const findings: RawFinding[] = [], diagnostics: string[] = [];\n let passed = 0, failed = 0, skipped = 0;\n for (const [index, suite] of report.testResults.entries()) {\n const file = evidencePath(suite.name, sourceRoot);\n if (!file) diagnostics.push(`Test path is outside the declared checkout or invalid: ${suite.name}`);\n let suiteFailures = 0;\n for (const [testIndex, test] of suite.assertionResults.entries()) {\n if (test.status === \"passed\") passed++;\n else if (test.status === \"failed\") {\n failed++; suiteFailures++;\n findings.push({ id: `${index}:${testIndex}`, ...messagePreview([test.fullName, ...(test.failureMessages ?? [])].join(\"\\n\")),\n severity: \"error\", state: \"active\", locations: file ? [{ file, ...(test.location ? { line: test.location.line, column: test.location.column } : {}) }] : [] });\n } else skipped++;\n }\n if (suite.status === \"failed\" && !suiteFailures) {\n findings.push({ id: `${index}:suite`, ...messagePreview(suite.message || `Test suite failed: ${suite.name}`), severity: \"error\", state: \"active\", locations: file ? [{ file }] : [] });\n }\n }\n if (passed !== report.numPassedTests || failed !== report.numFailedTests || skipped !== report.numPendingTests + report.numTodoTests || passed + failed + skipped !== report.numTotalTests) {\n throw new Error(\"Vitest summary counts disagree with its assertion results\");\n }\n const hasFailures = failed > 0 || report.numFailedTestSuites > 0 || report.testResults.some(s => s.status === \"failed\");\n if (report.success && hasFailures) throw new Error(\"Vitest success conflicts with failed tests or suites\");\n const outcome = hasFailures || !report.success ? \"failed\" : !report.numTotalTests ? \"unavailable\" : !passed ? \"skipped\" : \"passed\";\n if (!report.numTotalTests) diagnostics.push(\"No tests executed; an empty report is not passing test evidence.\");\n if (skipped) diagnostics.push(`${skipped} tests were skipped, pending, disabled, or todo.`);\n return { outcome, findings, counts: { total: report.numTotalTests, passed, failed, skipped, failedSuites: report.numFailedTestSuites },\n incomplete: skipped > 0 || diagnostics.length > 0, diagnostics };\n}\n","import { normalizeRepoPath } from \"../../utils/paths.js\";\n\n/** Map reported paths from the runner's checkout; never read source via a report URI. */\nexport function evidencePath(value: string, sourceRoot: string, uri = false): string | null {\n if (value.length > 4000) return null;\n let file = value;\n try {\n if (uri) {\n if (file.startsWith(\"file:\")) {\n const url = new URL(file);\n if (url.hostname && url.hostname !== \"localhost\") return null;\n file = decodeURIComponent(url.pathname).replace(/^\\/([A-Za-z]:\\/)/, \"$1\");\n } else {\n if (/^[a-z][a-z0-9+.-]*:/i.test(file)) return null;\n file = decodeURIComponent(file);\n }\n }\n } catch { return null; }\n file = file.replace(/\\\\/g, \"/\");\n const root = sourceRoot.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n if (file.startsWith(\"/\") || /^[A-Za-z]:/.test(file)) {\n if (!file.startsWith(root + \"/\")) return null;\n file = file.slice(root.length + 1);\n }\n return normalizeRepoPath(file);\n}\n","export type CheckOutcome = \"passed\" | \"failed\" | \"skipped\" | \"unavailable\";\nexport interface EvidenceLocation { file: string; line?: number; column?: number }\nexport interface RawFinding {\n id: string;\n message: string;\n severity: \"error\" | \"warning\" | \"note\";\n state: \"active\" | \"suppressed\" | \"absent\" | \"informational\";\n locations: EvidenceLocation[];\n ruleId?: string;\n truncated?: boolean;\n}\nexport interface ParsedEvidence {\n outcome: CheckOutcome;\n findings: RawFinding[];\n counts: Record<string, number>;\n incomplete: boolean;\n diagnostics: string[];\n reportedCommits?: string[];\n reportedCommands?: string[];\n reportedTools?: string[];\n executed?: boolean;\n}\nexport const MAX_FINDINGS = 200;\nexport function messagePreview(message: string) {\n return { message: message.slice(0, 4000), ...(message.length > 4000 ? { truncated: true } : {}) };\n}\n","import { z } from \"zod\";\nimport { evidencePath } from \"./paths.js\";\nimport { messagePreview, type ParsedEvidence, type RawFinding, type EvidenceLocation } from \"./types.js\";\n\nconst index = z.number().int().nonnegative();\nconst artifact = z.object({ uri: z.string().optional(), uriBaseId: z.string().optional(), index: index.optional() });\nconst message = z.object({ text: z.string().optional(), markdown: z.string().optional(), id: z.string().optional(), arguments: z.array(z.string()).optional() });\nconst level = z.enum([\"error\", \"warning\", \"note\", \"none\"]);\nconst location = z.object({ physicalLocation: z.object({ artifactLocation: artifact.optional(), region: z.object({ startLine: index.optional(), startColumn: index.optional() }).optional() }).optional() });\nconst schema = z.object({\n version: z.literal(\"2.1.0\"), runs: z.array(z.object({\n tool: z.object({ driver: z.object({ name: z.string().min(1), rules: z.array(z.object({ id: z.string(), defaultConfiguration: z.object({ level: level.optional() }).optional(), messageStrings: z.record(message).optional() })).optional(), globalMessageStrings: z.record(message).optional() }) }),\n invocations: z.array(z.object({ executionSuccessful: z.boolean(), commandLine: z.string().optional(), toolExecutionNotifications: z.array(z.object({ level: level.optional(), message })).optional() })).optional(),\n versionControlProvenance: z.array(z.object({ revisionId: z.string().optional() })).optional(),\n originalUriBaseIds: z.record(artifact).optional(), artifacts: z.array(z.object({ location: artifact.optional() })).optional(),\n results: z.array(z.object({\n ruleId: z.string().optional(), ruleIndex: index.optional(), message, level: level.optional(),\n kind: z.enum([\"fail\", \"pass\", \"open\", \"informational\", \"notApplicable\", \"review\"]).optional(),\n baselineState: z.enum([\"new\", \"unchanged\", \"updated\", \"absent\"]).optional(),\n suppressions: z.array(z.object({ kind: z.enum([\"inSource\", \"external\"]), status: z.enum([\"accepted\", \"underReview\", \"rejected\"]).optional() })).nullable().optional(),\n locations: z.array(location).optional(), relatedLocations: z.array(location).optional(),\n })).optional(),\n })),\n});\n\nexport function parseSarif(raw: unknown, sourceRoot: string): ParsedEvidence {\n const report = schema.parse(raw), findings: RawFinding[] = [], diagnostics: string[] = [];\n let active = 0, suppressed = 0, absent = 0, unresolved = 0;\n let executed = report.runs.length > 0, executionFailed = false;\n const reportedCommits: string[] = [], reportedCommands: string[] = [], reportedTools: string[] = [];\n for (const [runIndex, run] of report.runs.entries()) {\n reportedTools.push(run.tool.driver.name);\n reportedCommits.push(...(run.versionControlProvenance ?? []).flatMap(v => v.revisionId ? [v.revisionId] : []));\n if (!run.invocations?.length) executed = false;\n for (const invocation of run.invocations ?? []) {\n if (invocation.commandLine) reportedCommands.push(invocation.commandLine);\n if (!invocation.executionSuccessful) executionFailed = true;\n for (const notification of invocation.toolExecutionNotifications ?? []) {\n diagnostics.push(notification.message.text ?? notification.message.markdown ?? \"SARIF tool execution notification\");\n if (notification.level === \"error\") executionFailed = true;\n }\n }\n if (!run.results) { diagnostics.push(`Run ${runIndex} omits results; analysis output is unavailable.`); executed = false; }\n const resolve = (ref: z.infer<typeof artifact>, seen = new Set<string>()): string | null => {\n if (!ref.uri && ref.index !== undefined) {\n const key = `artifact:${ref.index}`;\n if (seen.has(key)) return null;\n const entry = run.artifacts?.[ref.index]?.location;\n return entry ? resolve(entry, new Set([...seen, key])) : null;\n }\n if (!ref.uri) return null;\n if (!ref.uriBaseId) return ref.uri;\n if (seen.has(ref.uriBaseId)) return null;\n const base = run.originalUriBaseIds?.[ref.uriBaseId];\n if (!base) return null;\n const prefix = resolve(base, new Set([...seen, ref.uriBaseId]));\n if (!prefix) return null;\n // Base URIs use concatenation, preserving traversal for the path validator.\n return /^[a-z][a-z0-9+.-]*:/i.test(ref.uri) ? ref.uri : prefix + ref.uri;\n };\n for (const [resultIndex, result] of (run.results ?? []).entries()) {\n const kind = result.kind ?? \"fail\";\n const isSuppressed = result.suppressions?.some(s => s.status === \"accepted\");\n if (result.suppressions?.some(s => !s.status || s.status === \"underReview\")) {\n diagnostics.push(`Suppression state unresolved for result ${runIndex}:${resultIndex}.`); unresolved++;\n }\n const state = result.baselineState === \"absent\" ? \"absent\" : isSuppressed ? \"suppressed\" : kind === \"fail\" ? \"active\" : \"informational\";\n if (state === \"active\") active++;\n if (state === \"absent\") absent++;\n if (state === \"suppressed\") suppressed++;\n if ([\"open\", \"review\"].includes(kind) && state === \"informational\") { unresolved++; diagnostics.push(`Result ${runIndex}:${resultIndex} needs further analysis or review.`); }\n if (kind === \"pass\" || kind === \"notApplicable\") continue;\n const rule = result.ruleIndex !== undefined ? run.tool.driver.rules?.[result.ruleIndex] : run.tool.driver.rules?.find(rule => rule.id === result.ruleId);\n const template = result.message.id ? rule?.messageStrings?.[result.message.id] ?? run.tool.driver.globalMessageStrings?.[result.message.id] : undefined;\n const rawMessage = result.message.text ?? result.message.markdown ?? template?.text ?? template?.markdown;\n if (!rawMessage) diagnostics.push(`Message cannot be resolved for result ${runIndex}:${resultIndex}.`);\n const rendered = (rawMessage ?? `Unresolved SARIF message ${result.message.id ?? \"\"}`).replace(/\\{(\\d+)\\}/g, (match, n) => result.message.arguments?.[Number(n)] ?? match);\n const locations: EvidenceLocation[] = [];\n for (const entry of [...(result.locations ?? []), ...(result.relatedLocations ?? [])]) {\n const ref = entry.physicalLocation?.artifactLocation;\n const uri = ref ? resolve(ref) : null;\n const file = uri ? evidencePath(uri, sourceRoot, true) : null;\n if (file) locations.push({ file, line: entry.physicalLocation?.region?.startLine, column: entry.physicalLocation?.region?.startColumn });\n else diagnostics.push(`Unresolved or out-of-checkout location for result ${runIndex}:${resultIndex}.`);\n }\n const severity = result.level ?? rule?.defaultConfiguration?.level ?? (kind === \"fail\" ? \"warning\" : \"none\");\n findings.push({ id: `${runIndex}:${resultIndex}`, ruleId: result.ruleId ?? rule?.id, ...messagePreview(rendered), severity: severity === \"none\" ? \"note\" : severity, state, locations });\n }\n }\n if (!report.runs.length) diagnostics.push(\"SARIF contains no analysis runs.\");\n if (executionFailed) diagnostics.push(\"The SARIF tool reported an unsuccessful analysis invocation.\");\n return { outcome: executionFailed || !report.runs.length || report.runs.some(r => !r.results) ? \"unavailable\" : active ? \"failed\" : \"passed\",\n findings, counts: { active, suppressed, absent, unresolved }, incomplete: diagnostics.length > 0,\n diagnostics, reportedCommits, reportedCommands, reportedTools, executed: executed && !executionFailed };\n}\n","import { runReviewCli } from \"../src/review/cli.js\";\n\nrunReviewCli(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (err) => {\n process.stderr.write(`mason-review error: ${err}\\n`);\n process.exit(2);\n }\n);\n"],"mappings":"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","names":["path","fs","path","execFile","promisify","fs","path","execFile","promisify","path","execFile","promisify","path","path","fs","path","fs","path","path","path","count","exec","promisify","execFile","exec","exec","promisify","execFile","exec","z","z","message","index","fs","path","z","path","z","fs","path","path","execFile","promisify","exec","index","path","z","z","message","z","index","z","z","schema","rule","z","path","index","exec","promisify","execFile","path","fs","path"]}
1
+ {"version":3,"sources":["../src/review/cli.ts","../src/review/review.ts","../src/drift/drift.ts","../src/snapshot/snapshot.ts","../src/utils/files.ts","../src/utils/paths.ts","../src/utils/storage.ts","../src/test-map.ts","../src/decisions/provenance.ts","../src/context/trust.ts","../src/decisions/decisions.ts","../src/context/lexical.ts","../src/decisions/drift.ts","../src/review/cochange.ts","../src/review/evidence.ts","../src/review/evidence/vitest.ts","../src/review/evidence/paths.ts","../src/review/evidence/types.ts","../src/review/evidence/sarif.ts","../src/review/evidence/check.ts","../bin/mason-review.ts"],"sourcesContent":["import path from \"node:path\";\nimport { stripVTControlCharacters } from \"node:util\";\nimport { computeReview, defaultBase } from \"./review.js\";\nimport type { ReviewReport } from \"./review.js\";\n\nexport const USAGE = `Usage: mason-review [--dir <path>] [--base <ref>] [--json] [--evidence <manifest>] [--require-evidence]\n\nReviews the current branch's diff against what git history and the Mason\ndecision store know:\n - co-change partners the diff forgot: files that historically change\n together with a changed file (>=60% of its commits, >=4 shared) but are\n absent from this diff\n - recorded decisions whose anchor files the diff touches (informational)\nDeterministic: no LLM call, no network – safe for CI.\n\nOptions:\n --dir <path> Project root (default: current directory)\n --base <ref> Base ref to diff against via merge-base (default: origin/HEAD,\n origin/main, origin/master, or main – first that resolves)\n --json Full report as JSON (additive-only schema)\n --evidence <manifest> Import a CI evidence manifest (repeatable; paths inside --dir)\n --require-evidence Require current, complete passing evidence; needs --evidence\n --help Show this help\n\nExit codes:\n 0 no missing co-change partners (touched decisions alone do not fail)\n 1 missing co-change partners found\n 2 error (base unresolvable, not a git repository, bad arguments)\n\nEvidence is advisory unless --require-evidence is set. With that flag, current\nfailed checks also exit 1; missing, skipped, stale, or incomplete evidence exits 2.\nNo check command from an imported report is executed.`;\n\nexport interface ReviewCliIo {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\ninterface ParsedArgs {\n dir: string;\n base: string | undefined;\n json: boolean;\n help: boolean;\n evidence: string[];\n requireEvidence: boolean;\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const parsed: ParsedArgs = {\n dir: process.cwd(),\n base: undefined,\n json: false,\n help: false,\n evidence: [], requireEvidence: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--json\") {\n parsed.json = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n parsed.help = true;\n } else if (arg === \"--dir\") {\n const value = argv[++i];\n if (!value) throw new Error(\"--dir requires a path argument\");\n parsed.dir = value;\n } else if (arg === \"--base\") {\n const value = argv[++i];\n if (!value) throw new Error(\"--base requires a ref argument\");\n parsed.base = value;\n } else if (arg === \"--evidence\") {\n const value = argv[++i];\n if (!value || value.startsWith(\"--\")) throw new Error(\"--evidence requires a manifest path\");\n parsed.evidence.push(value);\n } else if (arg === \"--require-evidence\") {\n parsed.requireEvidence = true;\n } else if (!arg.startsWith(\"-\") && parsed.dir === process.cwd()) {\n parsed.dir = arg;\n } else {\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n if (parsed.requireEvidence && !parsed.evidence.length) throw new Error(\"--require-evidence requires at least one --evidence manifest\");\n return parsed;\n}\n\nconst display = (value: string, limit = 500) => stripVTControlCharacters(value).replace(/[\\r\\n\\t]/g, \" \").slice(0, limit);\n\nfunction evidenceSummary(report: ReviewReport): string[] {\n const evidence = report.evidence;\n if (!evidence) return [];\n const lines = [`Imported CI evidence: ${evidence.status} (commit ${evidence.headHash.slice(0, 12)}; committed scope).`];\n for (const diagnostic of evidence.diagnostics) lines.push(` Evidence unavailable: ${display(diagnostic)}`);\n for (const check of evidence.checks) {\n lines.push(` [${check.kind}] ${display(check.id)}: ${check.outcome}, ${check.freshness} (${display(check.tool)})`);\n lines.push(` command: ${display(check.command)}; tested commit: ${check.commit ?? \"unknown\"}`);\n if (check.environment) {\n lines.push(` environment: ${display(check.tool)} ${display(check.environment.toolVersion)}`\n + (check.environment.runtime ? `; ${display(check.environment.runtime)}` : \"\")\n + (check.environment.platform ? `; ${display(check.environment.platform)}` : \"\"));\n if (check.environment.configuration?.length) lines.push(\" configuration: \" + check.environment.configuration.map(value => display(value)).join(\", \"));\n }\n lines.push(` source: ${display(check.source ?? check.manifest)}; report: ${display(check.report?.path ?? \"none\")}`);\n if (Object.keys(check.counts).length) lines.push(` counts: ${JSON.stringify(check.counts)}`);\n for (const diagnostic of check.diagnostics.slice(0, 5)) lines.push(` note: ${display(diagnostic)}`);\n for (const finding of check.findings.slice(0, 10)) {\n const locations = finding.locations.map(l => `${l.file}${l.line ? `:${l.line}` : \"\"}`).join(\", \") || \"no resolved file location\";\n lines.push(` [${finding.state}/${finding.severity}] ${display(finding.ruleId ?? finding.id)} ${display(locations)}: ${display(finding.message)}`);\n if (finding.relatedChangedFiles.length) lines.push(` changed files: ${finding.relatedChangedFiles.map(f => `${display(f.file)} (${f.relationship}${f.confidence ? `, ${f.confidence}` : \"\"})`).join(\", \")}`);\n for (const decision of finding.acceptedDecisions) lines.push(` related accepted decision: ${display(decision.id)}; owner ${display(decision.owner ?? \"unknown\")}; freshness ${decision.freshness}${decision.reviewRequired ? \"; needs review\" : \"\"}`);\n }\n if (check.totalFindings > 10 || check.truncated || check.diagnostics.length > 5) lines.push(` Output abbreviated (${check.totalFindings} findings); inspect --json and the original artifact for full evidence.`);\n }\n if (!evidence.workingTree.available) lines.push(\" Working-tree state unavailable; imported evidence only describes the recorded commit.\");\n else if (evidence.workingTree.changedFiles.length) lines.push(` ${evidence.workingTree.changedFiles.length} uncommitted paths are outside this evidence's scope.`);\n lines.push(\" Related decisions are associations, not proven violations. Passing imported checks do not establish complete coverage.\");\n return lines;\n}\n\nexport function formatReviewSummary(report: ReviewReport): string {\n const lines: string[] = [];\n lines.push(\n `Diff vs ${report.base} (merge-base ${report.mergeBase.slice(0, 7)}): ${report.changedFiles.length} changed file${report.changedFiles.length === 1 ? \"\" : \"s\"}.`\n );\n for (const diagnostic of report.diagnostics ?? []) lines.push(`Invalid decision record ${diagnostic.path}: ${diagnostic.message}`);\n if (report.truncated) {\n lines.push(\n `Large diff – co-change analysis limited to the first ${50} files.`\n );\n }\n if (!report.historyAvailable) {\n lines.push(\n \"Git history unavailable (shallow clone?) – co-change analysis skipped.\"\n );\n }\n\n if (report.missingPartners.length > 0) {\n lines.push(\"Possible forgotten co-change partners:\");\n for (const f of report.missingPartners) {\n lines.push(\n ` [missing-partner] ${f.changedFile} changed without ${f.missingPartner} – they changed together in ${Math.round(f.rate * 100)}% of ${f.changedFile}'s last ${f.fileCommits} commits (${f.sharedCommits} shared)`\n );\n }\n }\n\n if (report.touchedDecisions.length > 0) {\n lines.push(\"Recorded decisions touched by this diff (check approval and freshness before relying on them):\");\n for (const d of report.touchedDecisions) {\n lines.push(\n ` [decision] ${d.title} (${d.category}; ${d.approval ?? \"unreviewed\"}; owner ${d.owner ?? \"unknown\"}; freshness ${d.freshness ?? \"unknown\"}; via ${d.touchedFiles.join(\", \") || \"pending proposal\"})`\n );\n if (d.sources?.length) lines.push(` sources: ${d.sources.map(s => s.reference).join(\", \")}`);\n if (d.lastReview) lines.push(` last review: ${d.lastReview.reviewer} at ${d.lastReview.gitHash.slice(0, 7)}`);\n if (d.pendingProposal) {\n const p = d.pendingProposal;\n lines.push(` [proposed revision ${p.revision}] ${p.title} (owner ${p.owner ?? \"unknown\"}; freshness ${p.trust.freshness}; via ${p.touchedFiles.join(\", \") || \"no draft anchors touched\"}); accepted revision ${d.revision} remains operative`);\n }\n }\n }\n\n lines.push(\n report.missingPartners.length === 0\n ? \"No missing co-change partners.\"\n : `${report.missingPartners.length} possible omission${report.missingPartners.length === 1 ? \"\" : \"s\"}.`\n );\n lines.push(...evidenceSummary(report));\n return lines.join(\"\\n\");\n}\n\nexport async function runReviewCli(\n argv: string[],\n io: ReviewCliIo = {\n out: (line) => process.stdout.write(`${line}\\n`),\n err: (line) => process.stderr.write(`${line}\\n`),\n }\n): Promise<number> {\n let args: ParsedArgs;\n try {\n args = parseArgs(argv);\n } catch (error) {\n io.err(error instanceof Error ? error.message : String(error));\n io.err(USAGE);\n return 2;\n }\n\n if (args.help) {\n io.out(USAGE);\n return 0;\n }\n\n const rootDir = path.resolve(args.dir);\n const base = args.base ?? (await defaultBase(rootDir));\n if (!base) {\n io.err(\n `Could not find a base ref in ${rootDir} (tried origin/HEAD, origin/main, origin/master, main). Pass one with --base.`\n );\n return 2;\n }\n\n const report = await computeReview(rootDir, base, args.evidence.length ? { evidence: args.evidence } : {});\n if (!report) {\n io.err(\n `Could not resolve a merge base between ${base} and HEAD in ${rootDir} – not a git repository, unknown ref, or unrelated histories.`\n );\n return 2;\n }\n\n if (args.json) {\n io.out(JSON.stringify(report, null, 2));\n } else {\n io.out(formatReviewSummary(report));\n if (args.evidence.length && !args.requireEvidence) io.out(\"Imported evidence is advisory for exit codes; use --require-evidence to require current passing checks.\");\n }\n if (args.requireEvidence && report.evidence?.status !== \"passed\") return report.evidence?.status === \"failed\" ? 1 : 2;\n return report.missingPartners.length > 0 ? 1 : 0;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { getChangesWithStatus, touchedPaths } from \"../drift/drift.js\";\nimport { decisionProvenance, decisionKnowledge, effectiveDecision } from \"../decisions/provenance.js\";\nimport { loadDecisionStore } from \"../decisions/decisions.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\nimport { computeDecisionDrift } from \"../decisions/drift.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport type { StoreDiagnostic } from \"../utils/storage.js\";\nimport type { DecisionRecord } from \"../decisions/decisions.js\";\nimport { findMissingPartners } from \"./cochange.js\";\nimport type { CochangeFinding } from \"./cochange.js\";\nimport { collectReviewEvidence, type ReviewEvidence } from \"./evidence.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\n\nconst exec = promisify(execFile);\n\n/** Diffs larger than this are refactors; partner analysis would be noise. */\nconst MAX_ANALYZED_FILES = 50;\n\nexport interface TouchedDecision extends Partial<ReturnType<typeof decisionProvenance>> {\n id: string;\n title: string;\n body: string;\n category: string;\n anchors: string[];\n freshness?: Freshness;\n touchedFiles: string[];\n pendingProposal?: NonNullable<ReturnType<typeof decisionKnowledge>[\"pendingProposal\"]> & { touchedFiles: string[] };\n}\n\nexport interface ReviewReport {\n /** Additive-only schema. */\n version: 1;\n diagnostics?: StoreDiagnostic[];\n root: string;\n base: string;\n mergeBase: string;\n changedFiles: string[];\n /** Historical partners this diff leaves untouched — drive exit 1. */\n missingPartners: CochangeFinding[];\n /** Decisions whose anchors the diff touches — informational only. */\n touchedDecisions: TouchedDecision[];\n historyAvailable: boolean;\n truncated: boolean;\n /** Optional imported CI results. Does not change the legacy review exit codes. */\n evidence?: ReviewEvidence;\n}\n\nasync function resolveMergeBase(\n resolvedRoot: string,\n base: string,\n head: string\n): Promise<string | null> {\n try {\n const { stdout } = await exec(\"git\", [\"merge-base\", base, head], {\n cwd: resolvedRoot,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\n/** First base ref that resolves: origin/HEAD, origin/main, origin/master, main. */\nexport async function defaultBase(resolvedRoot: string): Promise<string | null> {\n for (const ref of [\"origin/HEAD\", \"origin/main\", \"origin/master\", \"main\"]) {\n try {\n await exec(\"git\", [\"rev-parse\", \"--verify\", \"--quiet\", ref], {\n cwd: resolvedRoot,\n });\n return ref;\n } catch {\n // Try the next candidate.\n }\n }\n return null;\n}\n\nfunction anchorsTouched(\n record: DecisionRecord,\n changedFiles: string[]\n): string[] {\n return matchingPaths(record.files, changedFiles);\n}\n\n/**\n * Review a diff against what git history and the decision store know:\n * co-change partners the diff forgot, and recorded constraints it touches.\n * Deterministic — no LLM, no network. Returns null when the base ref or\n * merge base cannot be resolved.\n */\nexport async function computeReview(\n rootDir: string,\n base: string,\n options: { evidence?: string[] } = {}\n): Promise<ReviewReport | null> {\n const resolvedRoot = path.resolve(rootDir);\n const head = await getCurrentGitHash(resolvedRoot);\n if (head === \"unknown\") return null;\n const mergeBase = await resolveMergeBase(resolvedRoot, base, head);\n if (!mergeBase) return null;\n\n const changes = await getChangesWithStatus(resolvedRoot, mergeBase, head);\n if (changes === null) return null;\n\n const changedFiles = touchedPaths(changes);\n\n const report: ReviewReport = {\n version: 1,\n root: resolvedRoot,\n base,\n mergeBase,\n changedFiles,\n missingPartners: [],\n touchedDecisions: [],\n historyAvailable: true,\n truncated: false,\n };\n const store = await loadDecisionStore(resolvedRoot);\n report.diagnostics = store.diagnostics;\n const decisionDrift = await computeDecisionDrift(resolvedRoot, store.records);\n if (options.evidence !== undefined) {\n report.evidence = await collectReviewEvidence(resolvedRoot, options.evidence, changedFiles, store.records, decisionDrift.freshness, head);\n if (store.diagnostics.length) {\n report.evidence.diagnostics.push(\"Invalid decision records make knowledge associations incomplete; consult review diagnostics.\");\n if (report.evidence.status === \"passed\") report.evidence.status = \"incomplete\";\n }\n }\n const finalize = async () => {\n if (report.evidence && await getCurrentGitHash(resolvedRoot) !== head) {\n report.evidence.diagnostics.push(\"HEAD changed during the review; rerun to obtain consistent change and knowledge associations.\");\n for (const check of report.evidence.checks) check.freshness = \"unknown\";\n report.evidence.summary.stale = 0;\n report.evidence.summary.unknown = report.evidence.checks.length;\n if (report.evidence.status !== \"unavailable\") report.evidence.status = \"incomplete\";\n }\n return report;\n };\n if (changedFiles.length === 0) return finalize();\n\n let analyzed = changedFiles;\n if (changedFiles.length > MAX_ANALYZED_FILES) {\n analyzed = changedFiles.slice(0, MAX_ANALYZED_FILES);\n report.truncated = true;\n }\n\n const partners = await findMissingPartners(\n resolvedRoot,\n analyzed,\n async (relPath) => {\n try {\n await fs.access(path.join(resolvedRoot, relPath));\n return true;\n } catch {\n return false;\n }\n },\n changedFiles\n );\n if (partners === null) {\n report.historyAvailable = false;\n } else {\n report.missingPartners = partners;\n }\n\n const decisions = store.records;\n for (const record of decisions) {\n if (record.status !== \"active\") continue;\n const effective = effectiveDecision(record);\n const touched = anchorsTouched(effective, changedFiles);\n const proposalTouched = effective !== record ? anchorsTouched(record, changedFiles) : [];\n if (touched.length > 0 || proposalTouched.length > 0) {\n const { pendingProposal, ...knowledge } = decisionKnowledge(record, decisionDrift.freshness?.[record.id] ?? \"unknown\", decisionDrift.pendingProposals?.[record.id]?.freshness ?? \"unknown\");\n report.touchedDecisions.push({\n ...knowledge,\n ...(pendingProposal ? { pendingProposal: { ...pendingProposal, touchedFiles: proposalTouched } } : {}),\n id: record.id,\n anchors: effective.files,\n freshness: decisionDrift.freshness?.[record.id] ?? \"unknown\",\n touchedFiles: touched,\n });\n }\n }\n\n return finalize();\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport {\n loadSnapshot,\n getCurrentGitHash,\n listSourceFiles,\n} from \"../snapshot/snapshot.js\";\nimport type { Snapshot } from \"../snapshot/snapshot.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\n\nconst exec = promisify(execFile);\n\n// Incremental refresh stops paying off once a large share of the map is\n// touched — but small absolute counts are always cheap to refresh in place,\n// so both thresholds must be exceeded before recommending a full rebuild.\nconst FULL_REBUILD_FRACTION = 0.4;\nconst FULL_REBUILD_MIN_CHANGED_MAPPED_FILES = 10;\n\nexport type ChangeStatus = \"added\" | \"modified\" | \"deleted\" | \"renamed\";\n\nexport interface FileChange {\n status: ChangeStatus;\n /** Current path (the new path for renames). */\n path: string;\n /** Pre-rename path, only present for renames. */\n previousPath?: string;\n}\n\nexport type DriftRecommendation = \"up-to-date\" | \"incremental\" | \"full-rebuild\";\n\nexport interface WorkingTreeReport {\n available: boolean;\n changedFiles: string[];\n untrackedFiles: string[];\n}\n\nexport interface DriftReport {\n /** Live entry state; committed drift alone continues to drive CLI exit codes. */\n featureFreshness?: Record<string, Freshness>;\n flowFreshness?: Record<string, Freshness>;\n workingTree?: WorkingTreeReport;\n verification?: { neverVerified: number; failed: string[] };\n stale: boolean;\n snapshotHash: string;\n headHash: string;\n /** Commits between the snapshot and HEAD; null when history is unavailable. */\n commitsBehind: number | null;\n /**\n * False when the snapshot commit is unreachable (shallow clone, rewritten\n * history) — staleFeatures/unmappedFiles/renames cannot be computed then.\n */\n historyAvailable: boolean;\n /** Current paths of every file changed since the snapshot. */\n changedFiles: string[];\n /** Stale feature name → the mapped files that changed under it. */\n staleFeatures: Record<string, string[]>;\n /** Stale flow name → the chain files that changed under it. */\n staleFlows: Record<string, string[]>;\n totalFeatures: number;\n totalFlows: number;\n /** New source files not referenced by any feature or flow. */\n unmappedFiles: string[];\n /** Files referenced by the map that no longer exist on disk. */\n ghostFiles: string[];\n renames: Array<{ from: string; to: string }>;\n recommendation: DriftRecommendation;\n}\n\nfunction parseChanges(output: string): FileChange[] {\n const fields = output.split(\"\\0\");\n const changes: FileChange[] = [];\n for (let i = 0; i < fields.length && fields[i];) {\n const code = fields[i++];\n const first = fields[i++];\n if (!first) break;\n const second = /^[RC]/.test(code) ? fields[i++] : undefined;\n const change: FileChange = second\n ? code.startsWith(\"R\") ? { status: \"renamed\", path: second, previousPath: first } : { status: \"added\", path: second }\n : { status: code === \"A\" ? \"added\" : code === \"D\" ? \"deleted\" : \"modified\", path: first };\n if (change.path.startsWith(\".mason/\") && (!change.previousPath || change.previousPath.startsWith(\".mason/\"))) continue;\n changes.push(change);\n }\n return changes;\n}\n\nexport function touchedPaths(changes: FileChange[]): string[] {\n return [...new Set(changes.flatMap(c => c.previousPath ? [c.previousPath, c.path] : [c.path]))].sort();\n}\n\nexport async function getChangesWithStatus(resolvedRoot: string, fromHash: string, toHash = \"HEAD\"): Promise<FileChange[] | null> {\n if (!fromHash || fromHash === \"unknown\" || fromHash.startsWith(\"-\") || !toHash || toHash === \"unknown\" || toHash.startsWith(\"-\")) return null;\n try {\n const { stdout } = await exec(\"git\", [\"diff\", \"--name-status\", \"-z\", \"-M\", fromHash, toHash, \"--\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 });\n return parseChanges(stdout);\n } catch { return null; }\n}\n\nexport async function getWorkingTree(resolvedRoot: string): Promise<WorkingTreeReport> {\n try {\n const [diff, untracked] = await Promise.all([\n exec(\"git\", [\"diff\", \"--name-status\", \"-z\", \"-M\", \"HEAD\", \"--\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),\n exec(\"git\", [\"ls-files\", \"-z\", \"--others\", \"--exclude-standard\"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),\n ]);\n const untrackedFiles = untracked.stdout.split(\"\\0\").filter(f => f && !f.startsWith(\".mason/\"));\n return { available: true, changedFiles: [...new Set([...touchedPaths(parseChanges(diff.stdout)), ...untrackedFiles])].sort(), untrackedFiles };\n } catch { return { available: false, changedFiles: [], untrackedFiles: [] }; }\n}\n\nasync function countCommitsBehind(\n resolvedRoot: string,\n fromHash: string\n): Promise<number | null> {\n if (!fromHash || fromHash === \"unknown\" || fromHash.startsWith(\"-\")) return null;\n try {\n const { stdout } = await exec(\n \"git\",\n [\"rev-list\", \"--count\", `${fromHash}..HEAD`],\n { cwd: resolvedRoot }\n );\n const count = Number.parseInt(stdout.trim(), 10);\n return Number.isNaN(count) ? null : count;\n } catch {\n return null;\n }\n}\n\nfunction collectMappedFiles(snapshot: Snapshot): Set<string> {\n const mappedFiles = new Set<string>();\n for (const feature of Object.values(snapshot.features)) {\n for (const f of feature.files) mappedFiles.add(f);\n for (const t of feature.tests ?? []) mappedFiles.add(t);\n }\n for (const flow of Object.values(snapshot.flows)) {\n for (const f of flow.chain) mappedFiles.add(f);\n }\n return mappedFiles;\n}\n\nasync function findGhostFiles(\n resolvedRoot: string,\n mappedFiles: Set<string>\n): Promise<string[]> {\n const ghosts: string[] = [];\n for (const file of mappedFiles) {\n try {\n await fs.access(path.join(resolvedRoot, file));\n } catch {\n ghosts.push(file);\n }\n }\n return ghosts.sort();\n}\n\n/**\n * Compare the concept map against HEAD and report feature-level drift.\n * Fully deterministic — git + filesystem only, no LLM involved.\n * Returns null when no snapshot exists.\n */\nexport async function computeDrift(rootDir: string): Promise<DriftReport | null> {\n const root = path.resolve(rootDir);\n const snapshot = await loadSnapshot(root);\n if (!snapshot) return null;\n const [headHash, workingTree] = await Promise.all([getCurrentGitHash(root), getWorkingTree(root)]);\n const hashFor = (entry: { refreshedHash?: string }) => entry.refreshedHash ?? snapshot.gitHash;\n const entries = [...Object.values(snapshot.features), ...Object.values(snapshot.flows)];\n const hashes = new Set([snapshot.gitHash, ...entries.map(hashFor)]);\n const changesByHash = new Map<string, FileChange[] | null>();\n await Promise.all([...hashes].map(async hash => {\n changesByHash.set(hash, hash === headHash && headHash !== \"unknown\" ? [] : await getChangesWithStatus(root, hash));\n }));\n const historyAvailable = headHash !== \"unknown\" && [...changesByHash.values()].every(changes => changes !== null);\n const mappedFiles = collectMappedFiles(snapshot);\n const report: DriftReport = {\n stale: !historyAvailable,\n snapshotHash: snapshot.gitHash, headHash,\n commitsBehind: 0, historyAvailable,\n changedFiles: [], staleFeatures: {}, staleFlows: {},\n totalFeatures: Object.keys(snapshot.features).length,\n totalFlows: Object.keys(snapshot.flows).length,\n unmappedFiles: [], ghostFiles: await findGhostFiles(root, mappedFiles), renames: [],\n recommendation: historyAvailable ? \"up-to-date\" : \"full-rebuild\",\n featureFreshness: {}, flowFreshness: {}, workingTree,\n verification: {\n neverVerified: entries.filter(e => !e.verifiedAt).length,\n failed: [...Object.entries(snapshot.features), ...Object.entries(snapshot.flows)].filter(([, e]) => e.verificationFailed).map(([name]) => name),\n },\n };\n const counts = await Promise.all([...hashes].map(hash => hash === headHash ? 0 : countCommitsBehind(root, hash)));\n const knownCounts = counts.filter((n): n is number => n !== null);\n report.commitsBehind = knownCounts.length ? Math.max(...knownCounts) : null;\n\n const check = (name: string, files: string[], hash: string, staleEntries: Record<string, string[]>, freshness: Record<string, Freshness>) => {\n const changes = changesByHash.get(hash);\n const committedHits = changes ? matchingPaths(files, touchedPaths(changes)) : [];\n if (committedHits.length) staleEntries[name] = committedHits;\n const localHits = matchingPaths(files, workingTree.changedFiles);\n freshness[name] = files.length === 0 || changes === null || changes === undefined || !workingTree.available ? \"unknown\"\n : committedHits.length || localHits.length || files.some(f => report.ghostFiles.includes(f)) ? \"changed\" : \"current\";\n };\n for (const [name, feature] of Object.entries(snapshot.features)) {\n check(name, [...feature.files, ...(feature.tests ?? [])], hashFor(feature), report.staleFeatures, report.featureFreshness!);\n }\n for (const [name, flow] of Object.entries(snapshot.flows)) {\n check(name, flow.chain, hashFor(flow), report.staleFlows, report.flowFreshness!);\n }\n\n const allChanges = [...changesByHash.values()].flatMap(changes => changes ?? []);\n report.changedFiles = [...new Set(allChanges.map(c => c.path))].sort();\n // Complete coverage, including omissions from a map saved at HEAD. Untracked\n // files remain in workingTree and never change the committed-drift exit code.\n const sourceFiles = new Set(await listSourceFiles(root));\n let committedFiles: Set<string> = new Set();\n try {\n const { stdout } = await exec(\"git\", [\"ls-tree\", \"-r\", \"--name-only\", \"-z\", \"HEAD\"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });\n committedFiles = new Set(stdout.split(\"\\0\").filter(Boolean));\n } catch { report.historyAvailable = false; report.stale = true; }\n report.unmappedFiles = [...sourceFiles].filter(f => committedFiles.has(f) && !mappedFiles.has(f)).sort();\n const renames = new Map<string, { from: string; to: string }>();\n for (const change of allChanges) {\n if (change.status === \"renamed\" && change.previousPath) renames.set(`${change.previousPath}\\0${change.path}`, { from: change.previousPath, to: change.path });\n }\n report.renames = [...renames.values()];\n const changedMapped = new Set([...Object.values(report.staleFeatures).flat(), ...Object.values(report.staleFlows).flat()]);\n // A locally deleted file is a live-edit warning, not committed map drift.\n const committedGhosts = report.ghostFiles.filter(f => !workingTree.changedFiles.includes(f));\n report.stale ||= changedMapped.size > 0 || report.unmappedFiles.length > 0 || committedGhosts.length > 0;\n if (!report.historyAvailable) report.recommendation = \"full-rebuild\";\n else if (!report.stale) report.recommendation = \"up-to-date\";\n else report.recommendation = changedMapped.size >= FULL_REBUILD_MIN_CHANGED_MAPPED_FILES && changedMapped.size / Math.max(1, mappedFiles.size) > FULL_REBUILD_FRACTION ? \"full-rebuild\" : \"incremental\";\n return report;\n}\n","import path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { createFileAccess } from \"../utils/files.js\";\nexport { SOURCE_GLOB, SOURCE_IGNORE } from \"../utils/files.js\";\nimport { readStoreJson, writeStoreJson, type StoreDiagnostic } from \"../utils/storage.js\";\nimport { z } from \"zod\";\nimport { normalizeRepoPath } from \"../utils/paths.js\";\nimport { buildTestMap } from \"../test-map.js\";\n\nconst exec = promisify(execFile);\n\nexport interface FeatureEntry {\n description: string;\n files: string[];\n tests?: string[];\n /**\n * Commit this entry was last verified against. Entries updated by an\n * incremental save carry HEAD here; untouched entries keep the hash the\n * map had before the save, so drift stays visible per entry. Absent means\n * \"as of the snapshot's top-level gitHash\".\n */\n refreshedHash?: string;\n /**\n * Whether this is a user-facing capability or internal infrastructure\n * (DI wiring, config loading, logging, provider/transport plumbing).\n * Capabilities are published to product-facing docs (Confluence);\n * infrastructure stays in the AI concept map only. Defaults to \"capability\"\n * when absent (older snapshots) — see normalizeFeatureType.\n */\n type?: \"capability\" | \"infrastructure\";\n /**\n * When an assistant last confirmed this entry's files actually implement\n * the claimed feature (verify_snapshot flow). Absent on older snapshots\n * and never-verified entries. Drift checks freshness against git; this\n * checks the map was CORRECT in the first place.\n */\n verifiedAt?: string;\n verifiedHash?: string;\n /** Set when verification judged the entry wrong — re-map it. */\n verificationFailed?: boolean;\n verificationNote?: string;\n}\n\nexport type FeatureType = \"capability\" | \"infrastructure\";\n\n/**\n * Coerce an arbitrary type value to a known classification. Anything that\n * isn't explicitly \"infrastructure\" defaults to \"capability\" — so older\n * snapshots and unclassified entries are treated as user-facing (published),\n * never silently hidden.\n */\nexport function normalizeFeatureType(value: unknown): FeatureType {\n return value === \"infrastructure\" ? \"infrastructure\" : \"capability\";\n}\n\nexport interface FlowEntry {\n description: string;\n chain: string[];\n /** See FeatureEntry.refreshedHash. */\n refreshedHash?: string;\n /** See FeatureEntry.verifiedAt / verificationFailed. */\n verifiedAt?: string;\n verifiedHash?: string;\n verificationFailed?: boolean;\n verificationNote?: string;\n}\n\nexport interface Snapshot {\n version: 2;\n createdAt: string;\n updatedAt: string;\n gitHash: string;\n features: Record<string, FeatureEntry>;\n flows: Record<string, FlowEntry>;\n}\n\nconst repoPath = z.string().refine(value => normalizeRepoPath(value) !== null, \"Expected a relative repository path\");\nconst verificationFields = {\n refreshedHash: z.string().optional(), verifiedAt: z.string().optional(),\n verifiedHash: z.string().optional(), verificationFailed: z.boolean().optional(),\n verificationNote: z.string().optional(),\n};\nexport const featureSchema = z.object({\n description: z.string(), files: z.array(repoPath), tests: z.array(repoPath).optional(),\n type: z.enum([\"capability\", \"infrastructure\"]).optional(), ...verificationFields,\n}).passthrough();\nexport const flowSchema = z.object({ description: z.string(), chain: z.array(repoPath), ...verificationFields }).passthrough();\nconst snapshotSchema = z.object({\n version: z.literal(2), createdAt: z.string(), updatedAt: z.string(), gitHash: z.string(),\n features: z.record(featureSchema), flows: z.record(flowSchema),\n}).passthrough();\n\nexport async function loadSnapshot(rootDir: string): Promise<Snapshot | null> {\n const parsed = await readStoreJson(rootDir, \".mason/snapshot.json\");\n if (parsed === null || (parsed as { version?: number }).version === 1) return null;\n const result = snapshotSchema.safeParse(parsed);\n if (!result.success) throw new Error(`Invalid Mason snapshot: ${result.error.message}`);\n return result.data;\n}\n\n/** Context and onboarding can use decisions even when the optional map is broken. */\nexport async function inspectSnapshot(rootDir: string): Promise<{\n status: \"available\" | \"missing\" | \"invalid\";\n snapshot: Snapshot | null;\n diagnostics: StoreDiagnostic[];\n}> {\n try {\n const raw = await readStoreJson(rootDir, \".mason/snapshot.json\");\n const snapshot = raw === null ? null : snapshotSchema.parse(raw);\n return { status: snapshot ? \"available\" : \"missing\", snapshot, diagnostics: [] };\n } catch (error) {\n return { status: \"invalid\", snapshot: null, diagnostics: [{\n path: \".mason/snapshot.json\", message: error instanceof Error ? error.message : String(error),\n }] };\n }\n}\n\nexport async function saveSnapshot(rootDir: string, snapshot: Snapshot): Promise<void> {\n await writeStoreJson(rootDir, \".mason/snapshot.json\", snapshotSchema.parse(snapshot));\n}\n\nexport async function getCurrentGitHash(rootDir: string): Promise<string> {\n try {\n const { stdout } = await exec(\"git\", [\"rev-parse\", \"HEAD\"], {\n cwd: rootDir,\n });\n return stdout.trim();\n } catch {\n return \"unknown\";\n }\n}\n\nexport const DEFAULT_BATCH_SIZE = 50;\nconst SKELETON_CHARS = 500;\nconst DEEP_SAMPLE_CHARS = 1500;\nconst DEEP_SAMPLES_PER_BATCH = 3;\n\nexport interface SnapshotBatch {\n offset: number;\n batchSize: number;\n nextOffset: number | null;\n totalFiles: number;\n skeletons: Array<{ path: string; content: string }>;\n samples: Array<{ path: string; content: string }>;\n testPairs: Array<{ test: string; source: string; confidence: string }>;\n}\n\nexport async function listSourceFiles(resolvedRoot: string): Promise<string[]> {\n return (await createFileAccess(resolvedRoot)).list();\n}\n\nexport async function prepareSnapshotBatch(\n rootDir: string,\n offset: number,\n batchSize: number = DEFAULT_BATCH_SIZE,\n scopeFiles?: string[]\n): Promise<SnapshotBatch> {\n const resolvedRoot = path.resolve(rootDir);\n const access = await createFileAccess(resolvedRoot);\n let allFiles = await access.list();\n if (scopeFiles) {\n // Intersect with the real source list: keeps ignore rules and path safety,\n // and silently drops scope entries that no longer exist on disk. An empty\n // scope stays empty — it must not fall back to walking the whole project.\n const scopeSet = new Set(scopeFiles);\n allFiles = allFiles.filter((f) => scopeSet.has(f));\n }\n const totalFiles = allFiles.length;\n const safeOffset = Math.max(0, Math.min(offset, totalFiles));\n const batchPaths = allFiles.slice(safeOffset, safeOffset + batchSize);\n\n const skeletons: Array<{ path: string; content: string }> = [];\n for (const filePath of batchPaths) {\n const full = await access.read(filePath);\n if (full) {\n skeletons.push({\n path: full.path,\n content: full.content.slice(0, SKELETON_CHARS),\n });\n }\n }\n\n // Pick a few files from this batch to read deeply for grounding. Spread\n // evenly across the batch so the deep samples represent the batch's range.\n const samples: Array<{ path: string; content: string }> = [];\n if (skeletons.length > 0) {\n const step = Math.max(1, Math.floor(skeletons.length / DEEP_SAMPLES_PER_BATCH));\n for (let i = 0; i < skeletons.length && samples.length < DEEP_SAMPLES_PER_BATCH; i += step) {\n const full = await access.read(skeletons[i].path);\n if (full) {\n samples.push({\n path: full.path,\n content: full.content.slice(0, DEEP_SAMPLE_CHARS),\n });\n }\n }\n }\n\n // Only include test pairs that involve files in this batch — keeps the\n // appendix relevant and small.\n const batchPathSet = new Set(batchPaths);\n const allTestPairs = (await buildTestMap(resolvedRoot)).paired;\n const testPairs = allTestPairs.filter(\n (p) => batchPathSet.has(p.test) || batchPathSet.has(p.source)\n );\n\n const nextOffset =\n safeOffset + batchSize >= totalFiles ? null : safeOffset + batchSize;\n\n return {\n offset: safeOffset,\n batchSize,\n nextOffset,\n totalFiles,\n skeletons,\n samples,\n testPairs,\n };\n}\n","import fs from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport path from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport fg from \"fast-glob\";\nimport { isWithinRoot, normalizeRepoPath } from \"./paths.js\";\n\nconst exec = promisify(execFile);\nexport const SOURCE_EXTENSIONS = [\"ts\", \"tsx\", \"js\", \"jsx\", \"mts\", \"cts\", \"mjs\", \"cjs\", \"vue\", \"svelte\", \"kt\", \"kts\", \"java\", \"py\", \"go\", \"rs\", \"swift\", \"rb\", \"cs\", \"cpp\", \"c\", \"h\", \"hpp\", \"dart\", \"php\"];\nexport const SOURCE_GLOB = `**/*.{${SOURCE_EXTENSIONS.join(\",\")}}`;\nexport const SOURCE_IGNORE = [\n \"**/node_modules/**\", \"**/dist/**\", \"**/build/**\", \"**/.gradle/**\",\n \"**/target/**\", \"**/.git/**\", \"**/.mason/**\", \"**/vendor/**\", \"**/__pycache__/**\",\n \"**/venv/**\", \"**/.venv/**\", \"**/*.min.*\", \"**/*.map\", \"**/*.lock\",\n \"**/generated/**\", \"**/*.generated.*\", \"**/R.java\", \"**/BuildConfig.java\",\n \"**/package-lock.json\", \"**/yarn.lock\", \"**/pnpm-lock.yaml\",\n];\nexport const MAX_SOURCE_BYTES = 1024 * 1024;\nexport interface ProjectConfig { patterns?: string[]; alwaysInclude?: string[]; ignore?: string[] }\nexport interface SourceFile { path: string; content: string; totalLines: number }\n\nexport function isSensitiveFile(file: string): boolean {\n return file.split(/[\\\\/]/).some(part =>\n /^(?:\\.env(?:\\..*)?|id_rsa.*|id_ed25519.*)$|\\.(?:pem|key|p12|pfx|jks|keystore)$|credentials\\.|secret|^local\\.properties$/i.test(part)\n );\n}\n\n/** Bound reads even if a file grows after stat. Only read regular files. */\nexport async function readBoundedFile(file: string, maxBytes: number): Promise<string | null> {\n // Do not block on a FIFO or follow a symlink substituted after resolution.\n const handle = await fs.open(file, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);\n try {\n const stat = await handle.stat();\n if (!stat.isFile() || stat.size > maxBytes) return null;\n const buffer = Buffer.alloc(Math.min(maxBytes + 1, stat.size + 1));\n let bytes = 0;\n while (bytes < buffer.length) {\n const result = await handle.read(buffer, bytes, buffer.length - bytes, null);\n if (result.bytesRead === 0) break;\n bytes += result.bytesRead;\n }\n return bytes === buffer.length ? null : buffer.subarray(0, bytes).toString(\"utf8\");\n } finally { await handle.close(); }\n}\n\nexport async function loadProjectConfig(root: string): Promise<ProjectConfig> {\n try {\n const canonicalRoot = await fs.realpath(root);\n const configPath = await fs.realpath(path.join(root, \".mason/config.json\"));\n if (!isWithinRoot(canonicalRoot, configPath)) throw new Error(\"Project configuration resolves outside the repository\");\n const raw = await readBoundedFile(configPath, 64 * 1024);\n if (raw === null) throw new Error(\"Project configuration is not a regular file or exceeds 64 KiB\");\n const value = JSON.parse(raw);\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw new Error(\"Expected a configuration object\");\n const config: ProjectConfig = {};\n for (const key of [\"patterns\", \"alwaysInclude\", \"ignore\"] as const) {\n if (value[key] === undefined) continue;\n if (!Array.isArray(value[key]) || !value[key].every((s: unknown) => typeof s === \"string\")) {\n throw new Error(`Configuration ${key} must be an array of strings`);\n }\n config[key] = value[key];\n }\n return config;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {};\n throw new Error(`Cannot apply project file policy: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n\n/** Scoped to one operation, so a later tool call sees newly edited files/ignores. */\nexport async function createFileAccess(rootDir: string) {\n const root = path.resolve(rootDir);\n const canonicalRoot = await fs.realpath(root).catch(() => root);\n const config = await loadProjectConfig(root);\n const ignore = [...SOURCE_IGNORE, ...(config.ignore ?? [])];\n let gitFiles: Set<string> | null = null;\n try {\n const { stdout } = await exec(\"git\", [\"ls-files\", \"-z\", \"--cached\", \"--others\", \"--exclude-standard\"], { cwd: root, maxBuffer: 50 * 1024 * 1024 });\n gitFiles = new Set(stdout.split(\"\\0\").filter(Boolean));\n } catch {\n // File-system projects are supported. Fail closed if this IS a Git repo.\n let inGit = false;\n try { await exec(\"git\", [\"rev-parse\", \"--git-dir\"], { cwd: root }); inGit = true; } catch { /* no Git */ }\n if (inGit) throw new Error(\"Cannot enumerate Git files safely\");\n }\n\n async function resolve(file: string): Promise<string | null> {\n const relative = normalizeRepoPath(file);\n if (!relative || isSensitiveFile(relative) || (gitFiles && !gitFiles.has(relative))) return null;\n const candidate = path.join(root, relative);\n try {\n const real = await fs.realpath(candidate);\n if (!isWithinRoot(canonicalRoot, real) || isSensitiveFile(path.relative(canonicalRoot, real))) return null;\n const stat = await fs.stat(real);\n if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES) return null;\n // A symlink must not bypass the target's ignore policy either.\n if (gitFiles && !gitFiles.has(path.relative(canonicalRoot, real).split(path.sep).join(\"/\"))) return null;\n return real;\n } catch { return null; }\n }\n\n async function list(patterns: string | string[] = SOURCE_GLOB, options: { deep?: number; dot?: boolean } = {}): Promise<string[]> {\n const found = await fg(patterns, { cwd: root, ignore, followSymbolicLinks: false, ...options });\n const safe = await Promise.all(found.map(async f => (await resolve(f)) ? f : null));\n return safe.filter((f): f is string => f !== null).sort();\n }\n\n async function read(file: string): Promise<SourceFile | null> {\n const relative = normalizeRepoPath(file);\n if (!relative) return null;\n const real = await resolve(relative);\n if (!real) return null;\n // Apply the same glob exclusions to explicit reads and symlink targets.\n for (const rel of new Set([relative, path.relative(canonicalRoot, real).split(path.sep).join(\"/\")])) {\n if (!(await fg(fg.escapePath(rel), { cwd: root, ignore, dot: true })).length) return null;\n }\n try {\n const content = await readBoundedFile(real, MAX_SOURCE_BYTES);\n return content === null ? null : { path: relative, content, totalLines: content.split(\"\\n\").length };\n } catch { return null; }\n }\n return { root, config, list, read };\n}\n","import path from \"node:path\";\n\n/** One canonical representation for stored paths and decision anchors. */\nexport function normalizeRepoPath(value: string): string | null {\n const slash = value.replace(/\\\\/g, \"/\");\n if (!slash || slash.includes(\"\\0\") || path.posix.isAbsolute(slash) || /^[A-Za-z]:/.test(slash)) return null;\n if (slash.split(\"/\").includes(\"..\")) return null;\n const normalized = path.posix.normalize(slash).replace(/\\/$/, \"\");\n return normalized === \".\" ? null : normalized;\n}\n\nexport function sanitizeRepoPaths(files: string[]): string[] {\n return [...new Set(files.map(normalizeRepoPath).filter((p): p is string => p !== null))];\n}\n\nexport function isWithinRoot(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);\n}\n\nexport function anchorMatches(anchor: string, file: string): boolean {\n const a = normalizeRepoPath(anchor);\n const f = normalizeRepoPath(file);\n return a !== null && f !== null && (a === f || f.startsWith(`${a}/`));\n}\n\nexport function matchingPaths(anchors: string[], files: Iterable<string>): string[] {\n return [...new Set(files)].filter(file => anchors.some(anchor => anchorMatches(anchor, file)));\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { normalizeRepoPath } from \"./paths.js\";\nimport { readBoundedFile } from \"./files.js\";\n\nexport interface StoreDiagnostic { path: string; message: string }\n\n/** Metadata paths may not contain symlinks, including their parent directories. */\nexport async function storePath(root: string, relative: string, createParents = false): Promise<string> {\n const normalized = normalizeRepoPath(relative);\n if (!normalized) throw new Error(`Invalid store path: ${relative}`);\n let current = await fs.realpath(root);\n const parts = normalized.split(\"/\");\n for (let i = 0; i < parts.length; i++) {\n current = path.join(current, parts[i]);\n let stat;\n try { stat = await fs.lstat(current); } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n if (createParents && i < parts.length - 1) {\n try { await fs.mkdir(current); } catch (mkdirError) {\n if ((mkdirError as NodeJS.ErrnoException).code !== \"EEXIST\") throw mkdirError;\n }\n stat = await fs.lstat(current);\n }\n }\n if (stat?.isSymbolicLink()) throw new Error(`Symlink in store path: ${relative}`);\n }\n return current;\n}\n\nexport async function readStoreJson(root: string, relative: string): Promise<unknown | null> {\n try {\n const file = await storePath(root, relative);\n const raw = await readBoundedFile(file, 10 * 1024 * 1024);\n if (raw === null) throw new Error(\"file is not regular or exceeds 10 MiB\");\n const parsed: unknown = JSON.parse(raw);\n if (parsed === null) throw new Error(\"expected a JSON object, received null\");\n return parsed;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw new Error(`Invalid Mason store ${relative}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });\n }\n}\n\nexport async function writeStoreJson(root: string, relative: string, value: unknown): Promise<void> {\n const payload = JSON.stringify(value, null, 2) + \"\\n\";\n if (Buffer.byteLength(payload) > 10 * 1024 * 1024) {\n throw new Error(`Mason store ${relative} exceeds 10 MiB`);\n }\n const file = await storePath(root, relative, true);\n const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${randomUUID()}.tmp`);\n try {\n const handle = await fs.open(temporary, \"wx\", 0o600);\n try { await handle.writeFile(payload, \"utf8\"); await handle.sync(); }\n finally { await handle.close(); }\n await fs.rename(temporary, file);\n } finally { await fs.rm(temporary, { force: true }); }\n}\n","import path from \"node:path\";\nimport { createFileAccess } from \"./utils/files.js\";\n\nexport interface TestPair {\n test: string;\n source: string;\n confidence: string;\n}\n\nexport interface TestMapResult {\n totalTestFiles: number;\n paired: TestPair[];\n unmatched: string[];\n}\n\nexport async function buildTestMap(dir: string): Promise<TestMapResult> {\n const rootDir = path.resolve(dir);\n const access = await createFileAccess(rootDir);\n\n // Find all test files\n const testPatterns = [\n \"**/*.test.*\", \"**/*.spec.*\",\n \"**/*Test.kt\", \"**/*Test.java\", \"**/*Tests.kt\", \"**/*Tests.java\",\n \"**/test_*.py\", \"**/*_test.py\",\n \"**/*_test.go\",\n \"**/*Tests.swift\", \"**/*Test.swift\",\n \"**/*_test.rs\",\n ];\n const testFiles = await access.list(testPatterns);\n\n // Find all source files\n const sourceFiles = await access.list();\n\n // Build source file index by base name (without extension)\n const sourceByBaseName = new Map<string, string[]>();\n for (const file of sourceFiles) {\n if (testFiles.includes(file)) continue; // Skip test files\n const baseName = path.basename(file).replace(/\\.[^.]+$/, \"\");\n const existing = sourceByBaseName.get(baseName) ?? [];\n existing.push(file);\n sourceByBaseName.set(baseName, existing);\n }\n\n // Match test files to source files by name\n const paired: TestPair[] = [];\n const unmatched: string[] = [];\n\n for (const testFile of testFiles) {\n const testBaseName = path.basename(testFile).replace(/\\.[^.]+$/, \"\");\n\n // Strip test suffixes/prefixes to get the source name\n const sourceName = testBaseName\n .replace(/Test$|Tests$|Spec$|\\.test$|\\.spec$/, \"\")\n .replace(/^test_|_test$/, \"\");\n\n if (!sourceName) {\n unmatched.push(testFile);\n continue;\n }\n\n const candidates = sourceByBaseName.get(sourceName);\n if (candidates && candidates.length > 0) {\n // If multiple candidates, prefer one in a similar directory path\n const testDir = path.dirname(testFile);\n const bestMatch = candidates.reduce((best, candidate) => {\n const candidateDir = path.dirname(candidate);\n const bestDir = path.dirname(best);\n const candidateOverlap = commonSegments(testDir, candidateDir);\n const bestOverlap = commonSegments(testDir, bestDir);\n return candidateOverlap > bestOverlap ? candidate : best;\n });\n\n paired.push({\n test: testFile,\n source: bestMatch,\n confidence: candidates.length === 1 ? \"exact\" : \"best-guess\",\n });\n } else {\n unmatched.push(testFile);\n }\n }\n\n return { totalTestFiles: testFiles.length, paired, unmatched };\n}\n\nfunction commonSegments(pathA: string, pathB: string): number {\n const segsA = pathA.split(\"/\");\n const segsB = pathB.split(\"/\");\n let count = 0;\n for (let i = 0; i < Math.min(segsA.length, segsB.length); i++) {\n if (segsA[i] === segsB[i]) count++;\n else break;\n }\n return count;\n}\n","import { z } from \"zod\";\nimport { normalizeRepoPath } from \"../utils/paths.js\";\nimport { assessTrust, type Freshness } from \"../context/trust.js\";\n\nconst text = (max: number) => z.string().trim().min(1).max(max);\nexport const decisionSourceSchema = z.object({\n kind: z.enum([\"pull_request\", \"issue\", \"incident\", \"discussion\", \"document\", \"other\"]),\n reference: text(1000),\n note: text(500).optional(),\n}).strict();\nexport type DecisionSource = z.infer<typeof decisionSourceSchema>;\nexport const attributionSchema = z.object({\n owner: text(200).nullable().optional(),\n sources: z.array(decisionSourceSchema).max(20).optional(),\n actor: text(200).optional(),\n});\nconst contentSchema = z.object({\n title: z.string().min(1), body: z.string().min(1),\n category: z.enum([\"decision\", \"gotcha\", \"deprecation\", \"convention\"]),\n files: z.array(z.string().refine(f => normalizeRepoPath(f) !== null)),\n owner: text(200).optional(), sources: z.array(decisionSourceSchema).max(20),\n});\nconst approvalSchema = z.enum([\"unreviewed\", \"proposed\", \"accepted\"]);\nconst statusSchema = z.enum([\"active\", \"superseded\", \"retired\"]);\nexport const reviewEvidenceSchema = z.object({\n baseHash: z.string(), headHash: z.string(), historyAvailable: z.boolean(),\n changedFiles: z.array(z.string()), localChanges: z.array(z.string()),\n});\nconst eventSchema = z.object({\n kind: z.enum([\"imported\", \"created\", \"revised\", \"accepted\", \"reaffirmed\", \"retired\", \"superseded\"]),\n at: z.string().datetime(), actor: text(200).optional(), note: text(1500).optional(),\n revision: z.number().int().positive(), content: contentSchema,\n approval: approvalSchema, status: statusSchema, refreshedHash: z.string(),\n evidence: reviewEvidenceSchema.optional(),\n});\nexport type DecisionEvent = z.infer<typeof eventSchema>;\nexport type DecisionApproval = z.infer<typeof approvalSchema>;\nexport type DecisionContent = z.infer<typeof contentSchema>;\n\nconst legacySchema = z.object({\n version: z.literal(1), id: z.string().regex(/^[a-zA-Z0-9_-]+$/),\n title: z.string().min(1), body: z.string().min(1),\n category: contentSchema.shape.category, files: contentSchema.shape.files,\n createdAt: z.string(), updatedAt: z.string(), refreshedHash: z.string(),\n status: z.enum([\"active\", \"superseded\"]), supersededBy: z.string().optional(),\n}).passthrough();\nconst currentSchema = legacySchema.extend({\n version: z.literal(2), status: statusSchema,\n approval: approvalSchema, revision: z.number().int().positive(),\n owner: text(200).optional(), sources: z.array(decisionSourceSchema).max(20),\n history: z.array(eventSchema).min(1),\n}).superRefine((record, ctx) => {\n const invalid = (message: string) => ctx.addIssue({ code: \"custom\", message });\n const same = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b);\n let previous: DecisionEvent | undefined;\n for (const event of record.history) {\n if (!previous) {\n if (![\"created\", \"imported\"].includes(event.kind) || event.revision !== 1) invalid(\"History must begin with creation or legacy import at revision 1\");\n if (event.approval !== (event.kind === \"created\" ? \"proposed\" : \"unreviewed\")) invalid(\"Initial records cannot claim acceptance\");\n } else {\n if ([\"created\", \"imported\"].includes(event.kind)) invalid(\"History cannot restart\");\n if (previous.status !== \"active\") invalid(\"Archived decisions cannot be changed\");\n if (event.revision !== previous.revision + (event.kind === \"revised\" ? 1 : 0)) invalid(\"Invalid revision sequence\");\n if (event.kind !== \"revised\" && !same(event.content, previous.content)) invalid(\"A review cannot silently revise decision content\");\n if (event.kind === \"reaffirmed\" && previous.approval !== \"accepted\") invalid(\"Only accepted decisions can be reaffirmed\");\n if (event.kind === \"accepted\" && previous.approval === \"accepted\") invalid(\"Use reaffirmation for an accepted decision\");\n const approval = event.kind === \"revised\" ? \"proposed\" : [\"accepted\", \"reaffirmed\"].includes(event.kind) ? \"accepted\" : previous.approval;\n if (event.approval !== approval) invalid(\"Approval disagrees with review history\");\n if (![\"accepted\", \"reaffirmed\"].includes(event.kind) && event.refreshedHash !== previous.refreshedHash) invalid(\"Only a review can refresh the evidence baseline\");\n }\n if (event.kind !== \"imported\" && event.status !== (event.kind === \"retired\" ? \"retired\" : event.kind === \"superseded\" ? \"superseded\" : \"active\")) invalid(\"Lifecycle disagrees with history\");\n if ([\"accepted\", \"reaffirmed\", \"retired\"].includes(event.kind) && (!event.actor || !event.note || !event.evidence)) invalid(\"Reviews require a named reviewer, reason, and code evidence\");\n if ([\"accepted\", \"reaffirmed\"].includes(event.kind)) {\n if (!event.content.owner || !event.content.sources.length) invalid(\"Accepted decisions require an owner and source\");\n if (!event.evidence || !/^[a-f0-9]{40,64}$/.test(event.evidence.headHash) || event.refreshedHash !== event.evidence.headHash || event.evidence.localChanges.length) invalid(\"Acceptance requires a committed evidence baseline\");\n }\n previous = event;\n }\n if (!previous || !same(previous.content, decisionContent(record)) || previous.approval !== record.approval || previous.status !== record.status || previous.revision !== record.revision || previous.refreshedHash !== record.refreshedHash) invalid(\"Decision does not match the final history event\");\n});\n\nexport const decisionSchema = z.union([legacySchema, currentSchema]);\nexport type DecisionRecord = z.infer<typeof decisionSchema>;\nexport type ReviewedDecisionRecord = z.infer<typeof currentSchema>;\n\nexport function decisionContent(record: Pick<DecisionRecord, \"title\" | \"body\" | \"category\" | \"files\"> & { owner?: unknown; sources?: unknown }): DecisionContent {\n return { title: record.title, body: record.body, category: record.category, files: record.files,\n ...(typeof record.owner === \"string\" ? { owner: record.owner } : {}),\n sources: Array.isArray(record.sources) ? record.sources as DecisionSource[] : [],\n };\n}\n\n/** Reading legacy records never upgrades their approval or rewrites their files. */\nexport function decisionApproval(record: DecisionRecord): DecisionApproval {\n return record.version === 1 ? \"unreviewed\" : record.approval;\n}\n\n/** The last accepted revision remains operative while a replacement is drafted.\n * This is a read-only projection; writes and review tokens use the complete record.\n * Archived records never regain authority from their history.\n */\nexport function effectiveDecision(record: DecisionRecord): DecisionRecord {\n if (record.version !== 2 || record.status !== \"active\" || record.approval !== \"proposed\") return record;\n let index = record.history.length - 1;\n while (index >= 0 && ![\"accepted\", \"reaffirmed\"].includes(record.history[index].kind)) index--;\n if (index < 0) return record;\n const event = record.history[index];\n return { ...record, ...event.content, owner: event.content.owner, approval: \"accepted\", revision: event.revision,\n refreshedHash: event.refreshedHash, updatedAt: event.at, history: record.history.slice(0, index + 1) };\n}\n\n/** Anchors relevant to either the operative knowledge or its pending proposal. */\nexport function decisionAnchors(record: DecisionRecord): string[] {\n return [...new Set([...effectiveDecision(record).files, ...record.files])];\n}\n\nexport function importLegacy(record: DecisionRecord, now: string): ReviewedDecisionRecord {\n if (record.version === 2) return record;\n // Ignore unrecognized legacy fields: they are not evidence of authorship or approval.\n const content = decisionContent({ title: record.title, body: record.body, category: record.category, files: record.files });\n return { id: record.id, createdAt: record.createdAt, updatedAt: record.updatedAt, status: record.status, refreshedHash: record.refreshedHash, supersededBy: record.supersededBy, ...content, version: 2, approval: \"unreviewed\", revision: 1,\n history: [{ kind: \"imported\", at: now, revision: 1, content, approval: \"unreviewed\", status: record.status, refreshedHash: record.refreshedHash,\n note: \"Imported a legacy record. Prior authorship and review history are unknown.\" }],\n };\n}\n\nexport function decisionProvenance(record: DecisionRecord, freshness: Freshness = \"unknown\") {\n const approval = decisionApproval(record);\n const review = record.version === 2 ? [...record.history].reverse().find(e => [\"accepted\", \"reaffirmed\"].includes(e.kind) && e.revision === record.revision) : undefined;\n return {\n approval, revision: record.version === 2 ? record.revision : 0,\n owner: record.version === 2 ? record.owner ?? null : null,\n sources: record.version === 2 ? record.sources : [],\n guidance: record.status !== \"active\" ? \"historical\" : approval === \"accepted\" ? \"constraint\" : approval === \"proposed\" ? \"proposal\" : \"unreviewed\",\n reviewRequired: record.status === \"active\" && (approval !== \"accepted\" || freshness !== \"current\"),\n lastReview: review ? { reviewer: review.actor!, at: review.at, note: review.note!, gitHash: review.refreshedHash } : null,\n };\n}\n\nexport function decisionTrust(record: DecisionRecord, freshness: Freshness) {\n const review = decisionProvenance(record, freshness).lastReview;\n return assessTrust(review ? { verifiedAt: review.at, verifiedHash: review.gitHash } : {}, freshness);\n}\n\nfunction revisionKnowledge(record: DecisionRecord, freshness: Freshness) {\n return { ...decisionContent(record), ...decisionProvenance(record, freshness), trust: decisionTrust(record, freshness) };\n}\n\n/** Readers show accepted content first and label the unaccepted draft separately. */\nexport function decisionKnowledge(record: DecisionRecord, freshness: Freshness = \"unknown\", proposalFreshness: Freshness = \"unknown\") {\n const effective = effectiveDecision(record);\n return { ...revisionKnowledge(effective, freshness),\n ...(effective !== record ? { pendingProposal: revisionKnowledge(record, proposalFreshness) } : {}) };\n}\n\nexport function compactDecisionKnowledge(...args: Parameters<typeof decisionKnowledge>) {\n const { body, pendingProposal, ...summary } = decisionKnowledge(...args);\n if (!pendingProposal) return summary;\n const { body: proposalBody, ...proposal } = pendingProposal;\n return { ...summary, pendingProposal: proposal };\n}\n\nexport const DECISION_GUIDANCE = \"Accepted decisions are recorded team constraints, subject to freshness checks. A pendingProposal is an unaccepted replacement; the accepted revision remains operative until explicit acceptance or retirement. Proposals are suggestions; legacy unreviewed records need confirmation. Use review_decision to inspect provenance and record an authorized review; identities and sources are recorded assertions, not authenticated proof.\";\n","export type Freshness = \"current\" | \"changed\" | \"unknown\";\nexport interface TrustState {\n freshness: Freshness;\n verification: \"unverified\" | \"passed\" | \"failed\";\n verifiedAt?: string;\n verifiedHash?: string;\n reasons: string[];\n}\n\nexport function assessTrust(entry: { verifiedAt?: string; verifiedHash?: string; verificationFailed?: boolean; verificationNote?: string }, freshness: Freshness): TrustState {\n const verification = entry.verificationFailed ? \"failed\" : entry.verifiedAt ? \"passed\" : \"unverified\";\n const reasons: string[] = [];\n if (freshness === \"unknown\") reasons.push(\"Anchors, history, or working-tree evidence are unavailable; verify before relying on this entry.\");\n if (freshness === \"changed\") reasons.push(\"Anchored files changed; verify against current code before relying on this entry.\");\n if (verification === \"failed\") reasons.push(`Verification failed: ${entry.verificationNote ?? \"re-map this entry before relying on it\"}`);\n if (verification === \"unverified\") reasons.push(\"No correctness verification has been recorded.\");\n return { freshness, verification, verifiedAt: entry.verifiedAt, verifiedHash: entry.verifiedHash, reasons };\n}\n\nexport function trustHint(states: TrustState[]): string {\n const parts: string[] = [];\n if (states.some(s => s.verification === \"failed\")) parts.push(\"Verification failed for returned entries; do not rely on those descriptions until corrected.\");\n if (states.some(s => s.freshness === \"unknown\")) parts.push(\"Freshness is unknown for some returned entries; inspect their files before relying on them.\");\n if (states.some(s => s.freshness === \"changed\")) parts.push(\"Some returned entries have changed files, including possible local edits; verify against the current code.\");\n if (!parts.length) parts.push(\"No changes detected in the returned anchors. This does not prove the descriptions are correct.\");\n if (states.some(s => s.verification === \"unverified\")) parts.push(\"Some entries have never been verified; read their evidence or use verify_snapshot for map descriptions.\");\n return parts.join(\" \");\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { z } from \"zod\";\nimport { readStoreJson, writeStoreJson, storePath, type StoreDiagnostic } from \"../utils/storage.js\";\nimport { sanitizeRepoPaths } from \"../utils/paths.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { jaccard, tokenSet } from \"../context/lexical.js\";\nimport { attributionSchema, decisionSchema, decisionContent, decisionApproval, effectiveDecision, importLegacy, type DecisionSource, type DecisionRecord, type ReviewedDecisionRecord } from \"./provenance.js\";\nexport type { DecisionRecord } from \"./provenance.js\";\n\nexport type DecisionCategory =\n | \"decision\"\n | \"gotcha\"\n | \"deprecation\"\n | \"convention\";\nexport type DecisionStatus = \"active\" | \"superseded\" | \"retired\";\n\nexport const TITLE_MAX_CHARS = 80;\nexport const BODY_RECOMMENDED_CHARS = 1500;\nexport const BODY_MAX_CHARS = 2500;\nexport const MAX_ACTIVE_DECISIONS = 150;\n\n// Share validation with MCP so rejected tool calls include the actual length.\nconst boundedText = (field: string, max: number, hint: string) => z.string({\n errorMap: (issue, ctx) => ({ message: issue.code === \"too_big\"\n ? `${field} has ${ctx.data.length} characters; maximum is ${max} (${ctx.data.length - max} over). ${hint}`\n : ctx.defaultError }),\n}).trim().min(1, `${field} must be non-empty`).max(max);\n\nexport const decisionTitleSchema = boundedText(\"title\", TITLE_MAX_CHARS, \"Tighten it to a specific headline.\");\nexport const decisionBodySchema = boundedText(\"body\", BODY_MAX_CHARS,\n `Aim for ${BODY_RECOMMENDED_CHARS} characters or fewer. Preserve the rule, reason, and exceptions; put supporting references in sources.`);\n\nconst DUPLICATE_JACCARD = 0.5;\nconst DUPLICATE_JACCARD_WITH_SHARED_FILE = 0.35;\n\nexport async function loadDecisionStore(rootDir: string): Promise<{ records: DecisionRecord[]; diagnostics: StoreDiagnostic[] }> {\n const records: DecisionRecord[] = [];\n const diagnostics: StoreDiagnostic[] = [];\n let entries: string[];\n try { entries = await fs.readdir(await storePath(rootDir, \".mason/decisions\")); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") diagnostics.push({ path: \".mason/decisions\", message: String(error) });\n return { records, diagnostics };\n }\n for (const entry of entries.sort()) {\n if (!entry.endsWith(\".json\")) continue;\n const relative = `.mason/decisions/${entry}`;\n try {\n const record = decisionSchema.parse(await readStoreJson(rootDir, relative));\n if (entry !== `${record.id}.json`) throw new Error(\"Record id does not match its filename\");\n records.push(record);\n } catch (error) { diagnostics.push({ path: relative, message: error instanceof Error ? error.message : String(error) }); }\n }\n return { records, diagnostics };\n}\n\nexport async function loadDecisions(rootDir: string): Promise<DecisionRecord[]> {\n return (await loadDecisionStore(rootDir)).records;\n}\n\nexport async function saveDecisionRecord(rootDir: string, record: DecisionRecord): Promise<void> {\n const validated = decisionSchema.parse(record);\n await writeStoreJson(rootDir, `.mason/decisions/${validated.id}.json`, validated);\n}\n\n/**\n * Deterministic, human-readable id: base slug ≤60 chars, ending at a word\n * boundary when possible. A single longer word is cut to fit.\n * A slug collision with a DIFFERENT record appends a 6-hex content suffix.\n */\nexport function decisionIdFor(\n title: string,\n body: string,\n existingIds: Set<string>\n): string {\n const fullSlug = title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n let slug = fullSlug.slice(0, 60);\n if (fullSlug.length > 60 && fullSlug[60] !== \"-\") {\n const boundary = slug.lastIndexOf(\"-\");\n if (boundary > 0) slug = slug.slice(0, boundary);\n }\n slug = slug.replace(/-+$/, \"\") || \"decision\";\n if (!existingIds.has(slug)) return slug;\n const suffix = createHash(\"sha1\")\n .update(title + body)\n .digest(\"hex\")\n .slice(0, 6);\n return `${slug}-${suffix}`;\n}\n\nexport function findNearDuplicate(\n candidate: { title: string; body: string; files: string[] },\n existing: DecisionRecord[]\n): { record: DecisionRecord; similarity: number } | null {\n const candidateTokens = tokenSet(`${candidate.title} ${candidate.body}`);\n const candidateFiles = new Set(candidate.files);\n let best: { record: DecisionRecord; similarity: number } | null = null;\n\n for (const record of existing) {\n if (record.status !== \"active\") continue;\n const similarity = jaccard(\n candidateTokens,\n tokenSet(`${record.title} ${record.body}`)\n );\n const sharesFile = record.files.some((f) => candidateFiles.has(f));\n const threshold = sharesFile\n ? DUPLICATE_JACCARD_WITH_SHARED_FILE\n : DUPLICATE_JACCARD;\n if (similarity >= threshold && (!best || similarity > best.similarity)) {\n best = { record, similarity };\n }\n }\n return best;\n}\n\nexport interface UpsertDecisionInput {\n title: string;\n body: string;\n category: DecisionCategory;\n files?: string[];\n owner?: string | null;\n sources?: DecisionSource[];\n /** Only supply a known identity; never infer authorship from Git configuration. */\n actor?: string;\n /** Existing id to revise. Unchanged content is a no-op; use review_decision to reaffirm. */\n id?: string;\n /** Id of a decision this one replaces; the old record is kept, marked superseded. */\n supersedes?: string;\n /** Save even when a near-duplicate was detected. */\n force?: boolean;\n}\n\nexport type UpsertDecisionResult =\n | {\n status: \"created\" | \"updated\" | \"unchanged\" | \"superseded_and_created\";\n id: string;\n totalActive: number;\n warnings: string[];\n approval?: \"unreviewed\" | \"proposed\" | \"accepted\";\n hint?: string;\n pruneCandidates?: string[];\n }\n | { status: \"duplicate_suspected\"; existing: DecisionRecord; hint: string }\n | { status: \"error\"; error: string };\n\n/** Serialize tool writes so prepared reviews cannot overwrite another decision edit. */\nexport async function withDecisionWrite<T>(root: string, operation: () => Promise<T>): Promise<T | { status: \"error\"; error: string }> {\n const lockPath = await storePath(root, \".mason/decisions/.write-lock\", true);\n let lock;\n try { lock = await fs.open(lockPath, \"wx\", 0o600); }\n catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"EEXIST\") return { status: \"error\", error: \"Decision store is locked by another write. Retry after it finishes; an abandoned .mason/decisions/.write-lock must be removed only after confirming no writer is running.\" };\n throw error;\n }\n try { return await operation(); }\n finally { await lock.close(); await fs.unlink(lockPath); }\n}\n\nexport async function upsertDecision(rootDir: string, input: UpsertDecisionInput): Promise<UpsertDecisionResult> {\n const parsedTitle = decisionTitleSchema.safeParse(input.title), parsedBody = decisionBodySchema.safeParse(input.body);\n if (!parsedTitle.success) return { status: \"error\", error: parsedTitle.error.issues[0].message };\n if (!parsedBody.success) return { status: \"error\", error: parsedBody.error.issues[0].message };\n const title = parsedTitle.data, body = parsedBody.data;\n const attribution = attributionSchema.safeParse(input);\n if (!attribution.success) return { status: \"error\", error: attribution.error.message };\n if (input.id && input.supersedes) return { status: \"error\", error: \"Use either id to revise or supersedes to replace a record, not both.\" };\n return withDecisionWrite(rootDir, async () => {\n const store = await loadDecisionStore(rootDir);\n if (store.diagnostics.length) return { status: \"error\", error: \"Repair malformed decision records before saving: \" + store.diagnostics.map(d => d.path).join(\", \") };\n const existing = store.records, byId = new Map(existing.map(r => [r.id, r]));\n const now = new Date().toISOString(), head = await getCurrentGitHash(rootDir);\n const warnings: string[] = [];\n if (body.length > BODY_RECOMMENDED_CHARS) warnings.push(`body has ${body.length} characters, above the recommended ${BODY_RECOMMENDED_CHARS}; matching context and hooks include it in full. Keep the rule, reason, and exceptions concise; use sources for supporting references.`);\n const files = sanitizeRepoPaths(input.files ?? []);\n if (input.files && files.length < input.files.length) warnings.push(\"some anchor paths were outside the repo or duplicated and were dropped\");\n for (const file of files) {\n try { await fs.access(path.join(rootDir, file)); }\n catch { warnings.push(`anchor file does not exist on disk: ${file}`); }\n }\n const hint = \"Saved locally for review and commit. Proposals are not accepted constraints; an existing accepted revision remains operative while its replacement is proposed. Use review_decision to inspect evidence and record an authorized acceptance or reaffirmation.\";\n if (input.id) {\n const original = byId.get(input.id);\n if (!original) return { status: \"error\", error: `no decision with id \"${input.id}\"` };\n if (original.status !== \"active\") return { status: \"error\", error: \"Archived records cannot be revised; create a new proposal.\" };\n const record = importLegacy(original, now);\n const content = decisionContent({ ...record, title, body, category: input.category,\n files: input.files !== undefined ? files : record.files,\n owner: attribution.data.owner === undefined ? record.owner : attribution.data.owner ?? undefined,\n sources: attribution.data.sources ?? record.sources,\n });\n if (JSON.stringify(content) === JSON.stringify(decisionContent(record))) {\n return { status: \"unchanged\", id: record.id, totalActive: existing.filter(r => r.status === \"active\").length, approval: decisionApproval(original), warnings,\n hint: \"Unchanged content; no review or freshness stamp was written. Use review_decision for explicit re-verification.\" };\n }\n const revision = record.revision + 1;\n const updated: ReviewedDecisionRecord = { ...record, ...content, owner: content.owner, updatedAt: now, revision, approval: \"proposed\",\n history: [...record.history, { kind: \"revised\", at: now, actor: attribution.data.actor, revision, content, approval: \"proposed\", status: \"active\", refreshedHash: record.refreshedHash }],\n };\n await saveDecisionRecord(rootDir, updated);\n return { status: \"updated\", id: record.id, totalActive: existing.filter(r => r.status === \"active\").length, approval: \"proposed\", warnings, hint };\n }\n const old = input.supersedes ? byId.get(input.supersedes) : undefined;\n if (input.supersedes && !old) return { status: \"error\", error: `no decision with id \"${input.supersedes}\" to supersede` };\n if (old && (old.status !== \"active\" || decisionApproval(effectiveDecision(old)) === \"accepted\")) {\n return { status: \"error\", error: \"A proposal cannot supersede an accepted or archived record. Create and review the replacement separately, then explicitly retire the old decision with review_decision.\" };\n }\n if (!input.force) {\n const duplicate = findNearDuplicate({ title, body, files }, existing);\n if (duplicate) return { status: \"duplicate_suspected\", existing: duplicate.record, hint: `A similar decision exists (\"${duplicate.record.title}\"). Call save_decision with id=\"${duplicate.record.id}\" to revise it, or force:true if distinct.` };\n }\n const id = decisionIdFor(title, body, new Set(byId.keys()));\n if (byId.has(id)) return { status: \"error\", error: `Decision id collision: ${id}. Choose a distinct title or revise the existing record.` };\n const content = decisionContent({ title, body, category: input.category, files, owner: attribution.data.owner ?? undefined, sources: attribution.data.sources ?? [] });\n const record: ReviewedDecisionRecord = { ...content, version: 2, id, createdAt: now, updatedAt: now, refreshedHash: head,\n status: \"active\", approval: \"proposed\", revision: 1,\n history: [{ kind: \"created\", at: now, actor: attribution.data.actor, revision: 1, content, approval: \"proposed\", status: \"active\", refreshedHash: head }],\n };\n // Write the replacement first: a failed second write leaves both records\n // available instead of removing the original before its replacement exists.\n await saveDecisionRecord(rootDir, record);\n if (old) {\n const imported = importLegacy(old, now);\n await saveDecisionRecord(rootDir, { ...imported, status: \"superseded\", supersededBy: id, updatedAt: now,\n history: [...imported.history, { kind: \"superseded\", at: now, actor: attribution.data.actor, note: `Replaced by proposal ${id}`,\n revision: imported.revision, content: decisionContent(imported), approval: imported.approval, status: \"superseded\", refreshedHash: imported.refreshedHash }],\n });\n }\n const totalActive = existing.filter(r => r.status === \"active\").length + (old ? 0 : 1);\n const result: UpsertDecisionResult = { status: old ? \"superseded_and_created\" : \"created\", id, totalActive, approval: \"proposed\", warnings, hint };\n if (totalActive > MAX_ACTIVE_DECISIONS) {\n result.pruneCandidates = existing.filter(r => r.status !== \"active\").map(r => r.id).slice(0, 10);\n warnings.push(`${totalActive} active decisions exceeds the soft cap of ${MAX_ACTIVE_DECISIONS} — consider a cleanup PR (archived records first)`);\n }\n return result;\n });\n}\n","import path from \"node:path\";\n\n// Question/filler words that carry no signal about which entry a task\n// touches. Domain words (\"auth\", \"drift\") are never in this list.\nconst STOPWORDS = new Set([\n \"the\", \"a\", \"an\", \"and\", \"or\", \"of\", \"to\", \"in\", \"on\", \"for\", \"with\",\n \"how\", \"does\", \"do\", \"is\", \"are\", \"was\", \"what\", \"where\", \"which\", \"why\",\n \"when\", \"who\", \"i\", \"we\", \"my\", \"our\", \"you\", \"your\", \"it\", \"its\", \"this\",\n \"that\", \"these\", \"those\", \"can\", \"could\", \"should\", \"would\", \"will\",\n \"want\", \"need\", \"please\", \"about\", \"into\", \"from\", \"when\", \"there\", \"any\",\n \"all\", \"some\", \"not\", \"but\", \"also\", \"just\", \"like\", \"get\", \"make\", \"use\",\n \"new\", \"work\", \"works\", \"working\", \"implement\", \"implemented\", \"change\",\n \"changed\", \"file\", \"files\", \"code\",\n]);\n\n/** Split camelCase/PascalCase/kebab/snake/path into lowercase word tokens. */\nexport function tokenize(text: string): string[] {\n return text\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((t) => t.length > 2 && !STOPWORDS.has(t));\n}\n\n/** Crude singular/plural folding so \"flows\" matches \"flow\" etc. */\nexport function stem(token: string): string {\n return token.length > 3 && token.endsWith(\"s\") ? token.slice(0, -1) : token;\n}\n\nexport function tokenSet(text: string): Set<string> {\n return new Set(tokenize(text).map(stem));\n}\n\nexport interface Scorable {\n name: string;\n description: string;\n files: string[];\n}\n\n/**\n * Lexical relevance of one entry to the task. Name hits are the strongest\n * signal, then description, then file-path words. Each distinct task token\n * counts once at its best weight, so a token appearing everywhere doesn't\n * triple-count.\n */\nexport function scoreEntry(taskTokens: Set<string>, entry: Scorable): number {\n const nameTokens = tokenSet(entry.name);\n const descTokens = tokenSet(entry.description);\n const fileTokens = tokenSet(entry.files.map((f) => path.basename(f)).join(\" \"));\n\n let score = 0;\n for (const token of taskTokens) {\n if (nameTokens.has(token)) score += 3;\n else if (descTokens.has(token)) score += 1;\n else if (fileTokens.has(token)) score += 1;\n }\n return score;\n}\n\n/** Jaccard similarity of two token sets: |∩| / |∪|, 0 when both empty. */\nexport function jaccard(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 0;\n let intersection = 0;\n for (const token of a) if (b.has(token)) intersection++;\n return intersection / (a.size + b.size - intersection);\n}\n","import path from \"node:path\";\nimport { getChangesWithStatus, getWorkingTree, touchedPaths } from \"../drift/drift.js\";\nimport { matchingPaths } from \"../utils/paths.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport type { StoreDiagnostic } from \"../utils/storage.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { loadDecisionStore } from \"./decisions.js\";\nimport type { DecisionRecord } from \"./decisions.js\";\nimport { effectiveDecision } from \"./provenance.js\";\n\n/**\n * Deliberately separate from DriftReport: mason-drift's exit codes and\n * --json shape are a CI contract, and `stale` there means MAP staleness.\n * Decision staleness is additive on top.\n */\nexport interface DecisionDriftReport {\n historyAvailable: boolean;\n freshness?: Record<string, Freshness>;\n diagnostics?: StoreDiagnostic[];\n totalDecisions: number;\n /** Decision id → anchor files changed since the record's refreshedHash. */\n staleDecisions: Record<string, string[]>;\n /** Draft anchors have their own freshness; they cannot replace accepted anchors. */\n pendingProposals?: Record<string, { freshness: Freshness; changedFiles: string[] }>;\n}\n\n/**\n * Flag active decisions whose anchor files changed since the record was\n * last verified. Anchorless decisions have unknown freshness and do not\n * contribute to committed drift.\n * Deterministic — git only, no LLM.\n */\nexport async function computeDecisionDrift(\n rootDir: string,\n decisions?: DecisionRecord[]\n): Promise<DecisionDriftReport> {\n const resolvedRoot = path.resolve(rootDir);\n const store = decisions ? { records: decisions, diagnostics: [] } : await loadDecisionStore(resolvedRoot);\n const report: DecisionDriftReport = { historyAvailable: true, totalDecisions: store.records.length, staleDecisions: {}, freshness: {}, diagnostics: store.diagnostics };\n const [head, workingTree] = await Promise.all([getCurrentGitHash(resolvedRoot), getWorkingTree(resolvedRoot)]);\n const changesByHash = new Map<string, string[] | null>();\n const inspect = async (record: DecisionRecord): Promise<{ freshness: Freshness; changedFiles: string[] }> => {\n if (record.files.length === 0) return { freshness: \"unknown\", changedFiles: [] };\n let touched = changesByHash.get(record.refreshedHash);\n if (touched === undefined) {\n const changes = record.refreshedHash === head && head !== \"unknown\" ? [] : await getChangesWithStatus(resolvedRoot, record.refreshedHash);\n touched = changes === null ? null : touchedPaths(changes);\n changesByHash.set(record.refreshedHash, touched);\n }\n if (touched === null) report.historyAvailable = false;\n const hits = touched ? matchingPaths(record.files, touched) : [];\n const localHits = matchingPaths(record.files, workingTree.changedFiles);\n return { freshness: touched === null || !workingTree.available ? \"unknown\" : hits.length || localHits.length ? \"changed\" : \"current\", changedFiles: hits };\n };\n for (const record of store.records) {\n if (record.status !== \"active\") continue;\n const effective = effectiveDecision(record);\n const state = await inspect(effective);\n report.freshness![record.id] = state.freshness;\n if (state.changedFiles.length) report.staleDecisions[record.id] = state.changedFiles;\n if (effective !== record) (report.pendingProposals ??= {})[record.id] = await inspect(record);\n }\n return report;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst exec = promisify(execFile);\n\n/**\n * History window for the co-change matrix. One capped git log for the whole\n * repo — unlike impact.ts's per-target walk, review analyzes many files at\n * once and needs a single pass.\n */\nconst HISTORY_COMMITS = 1500;\n\n/** Below this many commits for a file, a co-change rate is noise. */\nconst MIN_FILE_COMMITS = 5;\n/** A partner must share at least this many commits to count. */\nconst MIN_SHARED_COMMITS = 4;\n/** ...and appear in at least this fraction of the changed file's commits. */\nconst MIN_COCHANGE_RATE = 0.6;\n/** Commits touching more files than this are refactors, not signal. */\nconst MAX_COMMIT_FILES = 30;\n\nexport interface CochangeFinding {\n changedFile: string;\n missingPartner: string;\n sharedCommits: number;\n fileCommits: number;\n /** sharedCommits / fileCommits, rounded to 2 places. */\n rate: number;\n}\n\ninterface CochangeMatrix {\n commitsByFile: Map<string, Set<number>>;\n totalCommits: number;\n}\n\nasync function buildMatrix(resolvedRoot: string): Promise<CochangeMatrix | null> {\n try {\n const { stdout: shallow } = await exec(\"git\", [\"rev-parse\", \"--is-shallow-repository\"], { cwd: resolvedRoot });\n if (shallow.trim() === \"true\") return null;\n const { stdout } = await exec(\n \"git\",\n [\"log\", `-n${HISTORY_COMMITS}`, \"--format=%x01\", \"--name-only\", \"-M\"],\n { cwd: resolvedRoot, maxBuffer: 100 * 1024 * 1024 }\n );\n const commitsByFile = new Map<string, Set<number>>();\n const blocks = stdout.split(\"\\x01\");\n let index = 0;\n for (const block of blocks) {\n const files = block\n .split(\"\\n\")\n .map((l) => l.trim())\n .filter((l) => l.length > 0 && !l.startsWith(\".mason/\"));\n if (files.length === 0 || files.length > MAX_COMMIT_FILES) continue;\n for (const file of files) {\n let set = commitsByFile.get(file);\n if (!set) {\n set = new Set();\n commitsByFile.set(file, set);\n }\n set.add(index);\n }\n index++;\n }\n return { commitsByFile, totalCommits: index };\n } catch {\n return null;\n }\n}\n\n/**\n * For each changed file, find its historical co-change partners that this\n * diff leaves untouched: files that appeared in >= MIN_COCHANGE_RATE of the\n * changed file's commits (within the window) but are absent from the diff.\n * Deterministic — pure git history, no LLM. Returns null when history is\n * unavailable.\n */\nexport async function findMissingPartners(\n resolvedRoot: string,\n changedFiles: string[],\n existsOnDisk: (relPath: string) => Promise<boolean>,\n allChangedFiles: string[] = changedFiles\n): Promise<CochangeFinding[] | null> {\n const matrix = await buildMatrix(resolvedRoot);\n if (!matrix) return null;\n\n const changedSet = new Set(allChangedFiles);\n const findings: CochangeFinding[] = [];\n\n for (const changedFile of changedFiles) {\n const fileCommits = matrix.commitsByFile.get(changedFile);\n if (!fileCommits || fileCommits.size < MIN_FILE_COMMITS) continue;\n\n for (const [partner, partnerCommits] of matrix.commitsByFile) {\n if (partner === changedFile || changedSet.has(partner)) continue;\n let shared = 0;\n for (const c of fileCommits) {\n if (partnerCommits.has(c)) shared++;\n }\n if (shared < MIN_SHARED_COMMITS) continue;\n const rate = shared / fileCommits.size;\n if (rate < MIN_COCHANGE_RATE) continue;\n if (!(await existsOnDisk(partner))) continue;\n findings.push({\n changedFile,\n missingPartner: partner,\n sharedCommits: shared,\n fileCommits: fileCommits.size,\n rate: Math.round(rate * 100) / 100,\n });\n }\n }\n\n findings.sort((a, b) => b.rate - a.rate || b.sharedCommits - a.sharedCommits);\n return findings;\n}\n","import path from \"node:path\";\nimport { z } from \"zod\";\nimport { readStoreJson } from \"../utils/storage.js\";\nimport { normalizeRepoPath, matchingPaths } from \"../utils/paths.js\";\nimport { getCurrentGitHash } from \"../snapshot/snapshot.js\";\nimport { getWorkingTree } from \"../drift/drift.js\";\nimport { buildTestMap, type TestPair } from \"../test-map.js\";\nimport { decisionApproval, decisionProvenance, effectiveDecision, type DecisionRecord } from \"../decisions/provenance.js\";\nimport type { Freshness } from \"../context/trust.js\";\nimport { parseVitest } from \"./evidence/vitest.js\";\nimport { parseSarif } from \"./evidence/sarif.js\";\nimport { parseCheck } from \"./evidence/check.js\";\nimport { MAX_FINDINGS, type CheckOutcome, type RawFinding, type ParsedEvidence } from \"./evidence/types.js\";\n\nconst checkSchema = z.object({\n id: z.string().min(1).max(100), kind: z.enum([\"tests\", \"static-analysis\", \"security\", \"complexity\", \"duplication\", \"documentation\"]),\n tool: z.string().min(1).max(200), command: z.string().min(1).max(2000),\n commit: z.string().regex(/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/).nullable().optional(),\n workingTreeClean: z.boolean().optional(),\n source: z.string().max(2000).optional(), sourceRoot: z.string().min(1).max(4000).optional(),\n status: z.enum([\"completed\", \"skipped\", \"unavailable\"]).default(\"completed\"), reason: z.string().min(1).max(2000).optional(),\n exitCode: z.number().int().nullable().optional(),\n environment: z.object({ toolVersion: z.string().min(1).max(200),\n runtime: z.string().min(1).max(200).optional(), platform: z.string().min(1).max(200).optional(),\n configuration: z.array(z.string().min(1).max(4000)).max(100).optional() }).optional(),\n report: z.object({ format: z.enum([\"vitest-json\", \"sarif\", \"mason-check-json\"]), path: z.string().min(1).max(4000) }).optional(),\n});\ntype CheckInput = z.infer<typeof checkSchema>;\nexport interface LinkedFinding extends RawFinding {\n relatedChangedFiles: Array<{ file: string; relationship: \"direct\" | \"paired-test\"; confidence?: string }>;\n acceptedDecisions: Array<{ id: string; title: string; owner: string | null; freshness: Freshness; reviewRequired: boolean; viaFiles: string[] }>;\n totalAcceptedDecisions: number;\n}\nexport interface EvidenceCheck {\n id: string; kind: CheckInput[\"kind\"]; tool: string; command: string; commit: string | null;\n workingTreeClean: boolean | null;\n source: string | null; manifest: string; report: CheckInput[\"report\"] | null;\n outcome: CheckOutcome; freshness: \"current\" | \"stale\" | \"unknown\";\n findings: LinkedFinding[]; totalFindings: number; counts: Record<string, number>;\n incomplete: boolean; diagnostics: string[]; truncated: boolean;\n reportedCommands?: string[]; reportedTools?: string[];\n environment?: CheckInput[\"environment\"];\n}\nexport interface ReviewEvidence {\n version: 1; scope: \"committed\"; headHash: string;\n status: \"passed\" | \"failed\" | \"incomplete\" | \"unavailable\";\n checks: EvidenceCheck[]; diagnostics: string[];\n summary: { passed: number; failed: number; skipped: number; unavailable: number; stale: number; unknown: number };\n workingTree: Awaited<ReturnType<typeof getWorkingTree>>;\n hint: string;\n}\n\nfunction relativeArtifact(root: string, file: string): string {\n const relative = path.isAbsolute(file) ? path.relative(root, file) : file;\n const normalized = normalizeRepoPath(relative);\n if (!normalized) throw new Error(`Evidence artifact must be inside the repository: ${file}`);\n return normalized;\n}\n\nfunction linkFinding(finding: RawFinding, changed: Set<string>, pairs: TestPair[], decisions: DecisionRecord[], freshness: Record<string, Freshness>): LinkedFinding {\n const located = [...new Set(finding.locations.map(l => l.file))];\n const paired = pairs.filter(pair => located.includes(pair.test));\n const relatedChangedFiles: LinkedFinding[\"relatedChangedFiles\"] = located.filter(file => changed.has(file)).map(file => ({ file, relationship: \"direct\" }));\n for (const pair of paired) {\n if (changed.has(pair.source) && !relatedChangedFiles.some(f => f.file === pair.source)) relatedChangedFiles.push({ file: pair.source, relationship: \"paired-test\", confidence: pair.confidence });\n }\n const allFiles = [...new Set([...located, ...paired.map(pair => pair.source)])];\n const acceptedDecisions = decisions.map(effectiveDecision).filter(d => d.status === \"active\" && decisionApproval(d) === \"accepted\")\n .map(d => ({ d, viaFiles: matchingPaths(d.files, allFiles) })).filter(match => match.viaFiles.length)\n .map(({ d, viaFiles }) => {\n const state = freshness[d.id] ?? \"unknown\", provenance = decisionProvenance(d, state);\n return { id: d.id, title: d.title, owner: provenance.owner, freshness: state, reviewRequired: provenance.reviewRequired, viaFiles };\n });\n return { ...finding, relatedChangedFiles, acceptedDecisions: acceptedDecisions.slice(0, 5), totalAcceptedDecisions: acceptedDecisions.length };\n}\n\n/** Read-only imports. Commands, URLs, and result locations are never executed or fetched. */\nexport async function collectReviewEvidence(root: string, manifests: string[], changedFiles: string[], decisions: DecisionRecord[], decisionFreshness: Record<string, Freshness> = {}, reviewedHead?: string): Promise<ReviewEvidence> {\n const [headHash, workingTree] = await Promise.all([reviewedHead ?? getCurrentGitHash(root), getWorkingTree(root)]);\n const output: ReviewEvidence = {\n version: 1, scope: \"committed\", headHash, status: \"unavailable\", checks: [], diagnostics: [], workingTree,\n summary: { passed: 0, failed: 0, skipped: 0, unavailable: 0, stale: 0, unknown: 0 },\n hint: \"Evidence describes the recorded check runs for a commit, not uncommitted edits or complete test coverage. Commands and CI provenance are imported assertions, not authenticated execution. File and test-pair associations identify relevant decisions; they do not prove a decision was violated. Missing checks must be declared in the manifest to be reported.\",\n };\n const seen = new Set<string>(), changed = new Set(changedFiles);\n let pairs: TestPair[] | undefined;\n if (manifests.length > 10) output.diagnostics.push(\"Only the first 10 evidence manifests were imported.\");\n for (const supplied of manifests.slice(0, 10)) {\n let manifest: string, raw: { version: 1; checks: unknown[] };\n try {\n manifest = relativeArtifact(root, supplied);\n raw = z.object({ version: z.literal(1), checks: z.array(z.unknown()) }).parse(await readStoreJson(root, manifest));\n } catch (error) { output.diagnostics.push(`${supplied}: ${String(error)}`); continue; }\n if (!raw.checks.length) output.diagnostics.push(`${manifest}: no checks declared.`);\n for (const [index, item] of raw.checks.entries()) {\n if (output.checks.length >= 50) { output.diagnostics.push(\"Only the first 50 checks were imported.\"); break; }\n const input = checkSchema.safeParse(item);\n if (!input.success) { output.diagnostics.push(`${manifest} check ${index}: ${input.error.message}`); continue; }\n const check = input.data;\n if (seen.has(check.id)) { output.diagnostics.push(`Duplicate check id ${check.id}; give different runs distinct ids.`); continue; }\n seen.add(check.id);\n const result: EvidenceCheck = {\n id: check.id, kind: check.kind, tool: check.tool, command: check.command,\n commit: check.commit?.toLowerCase() ?? null, workingTreeClean: check.workingTreeClean ?? null, source: check.source ?? null, manifest, report: check.report ?? null,\n outcome: \"unavailable\", freshness: \"unknown\", findings: [], totalFindings: 0, counts: {}, incomplete: false, diagnostics: [], truncated: false,\n ...(check.environment ? { environment: check.environment } : {}),\n };\n output.checks.push(result);\n if (check.workingTreeClean !== true) result.diagnostics.push(\"The check's working tree was dirty or not recorded; its results cannot be attributed to the claimed commit alone.\");\n else if (result.commit && headHash !== \"unknown\") result.freshness = result.commit === headHash.toLowerCase() ? \"current\" : \"stale\";\n else result.diagnostics.push(\"The tested commit or reviewed HEAD is unknown.\");\n if (check.status !== \"completed\") {\n result.outcome = check.status;\n result.diagnostics.push(check.reason ?? \"No reason was recorded for this skipped or unavailable check.\");\n continue;\n }\n try {\n if (!check.report) throw new Error(\"Completed check has no report artifact.\");\n if (check.report.format !== \"mason-check-json\" && (check.kind === \"tests\") !== (check.report.format === \"vitest-json\")) throw new Error(\"Test checks require vitest-json or mason-check-json; analysis checks require sarif or mason-check-json.\");\n const file = relativeArtifact(root, check.report.path);\n const report = await readStoreJson(root, file);\n if (report === null) throw new Error(`Report artifact is missing: ${file}`);\n const sourceRoot = check.sourceRoot ?? root;\n if (!path.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\\\/]/.test(sourceRoot)) throw new Error(\"sourceRoot must identify the absolute checkout root on the check runner.\");\n const parsed: ParsedEvidence = check.report.format === \"vitest-json\" ? parseVitest(report, sourceRoot)\n : check.report.format === \"mason-check-json\" ? parseCheck(report, sourceRoot) : parseSarif(report, sourceRoot);\n result.outcome = parsed.outcome; result.counts = parsed.counts; result.incomplete = parsed.incomplete;\n result.diagnostics.push(...parsed.diagnostics);\n result.reportedCommands = parsed.reportedCommands; result.reportedTools = parsed.reportedTools;\n if (parsed.reportedCommits?.some(commit => !result.commit || commit.toLowerCase() !== result.commit)) {\n result.freshness = \"unknown\"; result.incomplete = true;\n result.diagnostics.push(\"Report revision metadata conflicts with, or cannot be tied to, the manifest's tested commit.\");\n }\n if (check.exitCode == null && !parsed.executed) {\n result.incomplete = true; result.diagnostics.push(\"Neither an exit code nor successful analysis invocation was recorded; completion cannot be confirmed.\");\n }\n if (check.exitCode != null && check.exitCode !== 0 && result.outcome === \"passed\") {\n result.outcome = \"failed\"; result.diagnostics.push(`Check command exited ${check.exitCode} despite a report with no active failures.`);\n }\n if (check.kind === \"tests\" && pairs === undefined) {\n try { pairs = (await buildTestMap(root)).paired; }\n catch (error) { pairs = []; output.diagnostics.push(`Test pairing unavailable: ${String(error)}`); }\n }\n result.totalFindings = parsed.findings.length;\n // Prioritize findings on changed files while retaining overall outcomes and counts.\n const testPairs = check.kind === \"tests\" ? pairs ?? [] : [];\n const relevant = new Set([...changed, ...testPairs.filter(p => changed.has(p.source)).map(p => p.test)]);\n const touchesChange = (f: RawFinding) => f.locations.some(l => relevant.has(l.file));\n parsed.findings.sort((a, b) => Number(b.state === \"active\") - Number(a.state === \"active\") || Number(touchesChange(b)) - Number(touchesChange(a)));\n result.findings = parsed.findings.slice(0, MAX_FINDINGS).map(f => linkFinding(f, changed, testPairs, decisions, decisionFreshness));\n result.truncated = parsed.findings.length > MAX_FINDINGS || result.findings.some(f => f.truncated || f.totalAcceptedDecisions > f.acceptedDecisions.length);\n } catch (error) {\n result.outcome = \"unavailable\"; result.incomplete = true; result.diagnostics.push(String(error));\n }\n }\n }\n if (!output.checks.length) output.diagnostics.push(\"No readable checks were imported.\");\n for (const check of output.checks) {\n output.summary[check.outcome]++;\n if (check.freshness !== \"current\") output.summary[check.freshness]++;\n }\n if (output.checks.some(c => c.outcome === \"failed\" && c.freshness === \"current\")) output.status = \"failed\";\n else if (!output.checks.length || output.checks.every(c => c.outcome === \"unavailable\")) output.status = \"unavailable\";\n else if (output.diagnostics.length || output.checks.some(c => c.outcome !== \"passed\" || c.freshness !== \"current\" || c.incomplete)) output.status = \"incomplete\";\n else output.status = \"passed\";\n return output;\n}\n\nexport function summarizeEvidence(evidence: ReviewEvidence) {\n const previews = (values: string[], limit: number) => values.slice(0, limit).map(value => value.slice(0, 2000));\n const checks = evidence.checks.slice(0, 10).map(check => {\n const findings = check.findings.slice(0, 5).map(finding => ({ ...finding,\n ruleId: finding.ruleId?.slice(0, 200),\n locations: finding.locations.slice(0, 5), totalLocations: finding.locations.length,\n relatedChangedFiles: finding.relatedChangedFiles.slice(0, 5), totalRelatedChangedFiles: finding.relatedChangedFiles.length,\n acceptedDecisions: finding.acceptedDecisions.map(decision => ({ ...decision, viaFiles: decision.viaFiles.slice(0, 5) })),\n truncated: finding.truncated || finding.locations.length > 5 || finding.relatedChangedFiles.length > 5 ||\n (finding.ruleId?.length ?? 0) > 200 || finding.acceptedDecisions.some(d => d.viaFiles.length > 5),\n }));\n return { ...check, findings, reportedCommands: check.reportedCommands ? previews(check.reportedCommands, 5) : undefined,\n reportedTools: check.reportedTools ? previews(check.reportedTools, 5) : undefined,\n diagnostics: previews(check.diagnostics, 10),\n truncated: check.truncated || check.findings.length > 5 || findings.some(f => f.truncated) || check.diagnostics.length > 10 ||\n check.diagnostics.some(d => d.length > 2000) || [check.reportedCommands ?? [], check.reportedTools ?? []].some(values => values.length > 5 || values.some(v => v.length > 2000)),\n };\n });\n return { ...evidence, checks, diagnostics: previews(evidence.diagnostics, 20),\n truncated: evidence.checks.length > 10 || evidence.diagnostics.length > 20 || evidence.diagnostics.some(d => d.length > 2000) || checks.some(c => c.truncated),\n };\n}\n","import { z } from \"zod\";\nimport { evidencePath } from \"./paths.js\";\nimport { messagePreview, type ParsedEvidence, type RawFinding } from \"./types.js\";\n\nconst count = z.number().int().nonnegative();\nconst schema = z.object({\n success: z.boolean(), numTotalTests: count, numPassedTests: count, numFailedTests: count,\n numPendingTests: count, numTodoTests: count, numFailedTestSuites: count,\n testResults: z.array(z.object({\n name: z.string().min(1), status: z.enum([\"passed\", \"failed\"]), message: z.string().optional(),\n assertionResults: z.array(z.object({\n fullName: z.string(), status: z.enum([\"passed\", \"failed\", \"pending\", \"skipped\", \"todo\", \"disabled\"]),\n failureMessages: z.array(z.string()).nullable().optional(),\n location: z.object({ line: count, column: count }).nullable().optional(),\n })),\n })),\n});\n\n/** Vitest JSON reporter output; summary and assertion counts must agree. */\nexport function parseVitest(raw: unknown, sourceRoot: string): ParsedEvidence {\n const report = schema.parse(raw);\n const findings: RawFinding[] = [], diagnostics: string[] = [];\n let passed = 0, failed = 0, skipped = 0;\n for (const [index, suite] of report.testResults.entries()) {\n const file = evidencePath(suite.name, sourceRoot);\n if (!file) diagnostics.push(`Test path is outside the declared checkout or invalid: ${suite.name}`);\n let suiteFailures = 0;\n for (const [testIndex, test] of suite.assertionResults.entries()) {\n if (test.status === \"passed\") passed++;\n else if (test.status === \"failed\") {\n failed++; suiteFailures++;\n findings.push({ id: `${index}:${testIndex}`, ...messagePreview([test.fullName, ...(test.failureMessages ?? [])].join(\"\\n\")),\n severity: \"error\", state: \"active\", locations: file ? [{ file, ...(test.location ? { line: test.location.line, column: test.location.column } : {}) }] : [] });\n } else skipped++;\n }\n if (suite.status === \"failed\" && !suiteFailures) {\n findings.push({ id: `${index}:suite`, ...messagePreview(suite.message || `Test suite failed: ${suite.name}`), severity: \"error\", state: \"active\", locations: file ? [{ file }] : [] });\n }\n }\n if (passed !== report.numPassedTests || failed !== report.numFailedTests || skipped !== report.numPendingTests + report.numTodoTests || passed + failed + skipped !== report.numTotalTests) {\n throw new Error(\"Vitest summary counts disagree with its assertion results\");\n }\n const hasFailures = failed > 0 || report.numFailedTestSuites > 0 || report.testResults.some(s => s.status === \"failed\");\n if (report.success && hasFailures) throw new Error(\"Vitest success conflicts with failed tests or suites\");\n const outcome = hasFailures || !report.success ? \"failed\" : !report.numTotalTests ? \"unavailable\" : !passed ? \"skipped\" : \"passed\";\n if (!report.numTotalTests) diagnostics.push(\"No tests executed; an empty report is not passing test evidence.\");\n if (skipped) diagnostics.push(`${skipped} tests were skipped, pending, disabled, or todo.`);\n return { outcome, findings, counts: { total: report.numTotalTests, passed, failed, skipped, failedSuites: report.numFailedTestSuites },\n incomplete: skipped > 0 || diagnostics.length > 0, diagnostics };\n}\n","import { normalizeRepoPath } from \"../../utils/paths.js\";\n\n/** Map reported paths from the runner's checkout; never read source via a report URI. */\nexport function evidencePath(value: string, sourceRoot: string, uri = false): string | null {\n if (value.length > 4000) return null;\n let file = value;\n try {\n if (uri) {\n if (file.startsWith(\"file:\")) {\n const url = new URL(file);\n if (url.hostname && url.hostname !== \"localhost\") return null;\n file = decodeURIComponent(url.pathname).replace(/^\\/([A-Za-z]:\\/)/, \"$1\");\n } else {\n if (/^[a-z][a-z0-9+.-]*:/i.test(file)) return null;\n file = decodeURIComponent(file);\n }\n }\n } catch { return null; }\n file = file.replace(/\\\\/g, \"/\");\n const root = sourceRoot.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n if (file.startsWith(\"/\") || /^[A-Za-z]:/.test(file)) {\n if (!file.startsWith(root + \"/\")) return null;\n file = file.slice(root.length + 1);\n }\n return normalizeRepoPath(file);\n}\n","export type CheckOutcome = \"passed\" | \"failed\" | \"skipped\" | \"unavailable\";\nexport interface EvidenceLocation { file: string; line?: number; column?: number }\nexport interface RawFinding {\n id: string;\n message: string;\n severity: \"error\" | \"warning\" | \"note\";\n state: \"active\" | \"suppressed\" | \"absent\" | \"informational\";\n locations: EvidenceLocation[];\n ruleId?: string;\n truncated?: boolean;\n}\nexport interface ParsedEvidence {\n outcome: CheckOutcome;\n findings: RawFinding[];\n counts: Record<string, number>;\n incomplete: boolean;\n diagnostics: string[];\n reportedCommits?: string[];\n reportedCommands?: string[];\n reportedTools?: string[];\n executed?: boolean;\n}\nexport const MAX_FINDINGS = 200;\nexport function messagePreview(message: string) {\n return { message: message.slice(0, 4000), ...(message.length > 4000 ? { truncated: true } : {}) };\n}\n","import { z } from \"zod\";\nimport { evidencePath } from \"./paths.js\";\nimport { messagePreview, type ParsedEvidence, type RawFinding, type EvidenceLocation } from \"./types.js\";\n\nconst index = z.number().int().nonnegative();\nconst artifact = z.object({ uri: z.string().optional(), uriBaseId: z.string().optional(), index: index.optional() });\nconst message = z.object({ text: z.string().optional(), markdown: z.string().optional(), id: z.string().optional(), arguments: z.array(z.string()).optional() });\nconst level = z.enum([\"error\", \"warning\", \"note\", \"none\"]);\nconst location = z.object({ physicalLocation: z.object({ artifactLocation: artifact.optional(), region: z.object({ startLine: index.optional(), startColumn: index.optional() }).optional() }).optional() });\nconst schema = z.object({\n version: z.literal(\"2.1.0\"), runs: z.array(z.object({\n tool: z.object({ driver: z.object({ name: z.string().min(1), rules: z.array(z.object({ id: z.string(), defaultConfiguration: z.object({ level: level.optional() }).optional(), messageStrings: z.record(message).optional() })).optional(), globalMessageStrings: z.record(message).optional() }) }),\n invocations: z.array(z.object({ executionSuccessful: z.boolean(), commandLine: z.string().optional(), toolExecutionNotifications: z.array(z.object({ level: level.optional(), message })).optional() })).optional(),\n versionControlProvenance: z.array(z.object({ revisionId: z.string().optional() })).optional(),\n originalUriBaseIds: z.record(artifact).optional(), artifacts: z.array(z.object({ location: artifact.optional() })).optional(),\n results: z.array(z.object({\n ruleId: z.string().optional(), ruleIndex: index.optional(), message, level: level.optional(),\n kind: z.enum([\"fail\", \"pass\", \"open\", \"informational\", \"notApplicable\", \"review\"]).optional(),\n baselineState: z.enum([\"new\", \"unchanged\", \"updated\", \"absent\"]).optional(),\n suppressions: z.array(z.object({ kind: z.enum([\"inSource\", \"external\"]), status: z.enum([\"accepted\", \"underReview\", \"rejected\"]).optional() })).nullable().optional(),\n locations: z.array(location).optional(), relatedLocations: z.array(location).optional(),\n })).optional(),\n })),\n});\n\nexport function parseSarif(raw: unknown, sourceRoot: string): ParsedEvidence {\n const report = schema.parse(raw), findings: RawFinding[] = [], diagnostics: string[] = [];\n let active = 0, suppressed = 0, absent = 0, unresolved = 0;\n let executed = report.runs.length > 0, executionFailed = false;\n const reportedCommits: string[] = [], reportedCommands: string[] = [], reportedTools: string[] = [];\n for (const [runIndex, run] of report.runs.entries()) {\n reportedTools.push(run.tool.driver.name);\n reportedCommits.push(...(run.versionControlProvenance ?? []).flatMap(v => v.revisionId ? [v.revisionId] : []));\n if (!run.invocations?.length) executed = false;\n for (const invocation of run.invocations ?? []) {\n if (invocation.commandLine) reportedCommands.push(invocation.commandLine);\n if (!invocation.executionSuccessful) executionFailed = true;\n for (const notification of invocation.toolExecutionNotifications ?? []) {\n diagnostics.push(notification.message.text ?? notification.message.markdown ?? \"SARIF tool execution notification\");\n if (notification.level === \"error\") executionFailed = true;\n }\n }\n if (!run.results) { diagnostics.push(`Run ${runIndex} omits results; analysis output is unavailable.`); executed = false; }\n const resolve = (ref: z.infer<typeof artifact>, seen = new Set<string>()): string | null => {\n if (!ref.uri && ref.index !== undefined) {\n const key = `artifact:${ref.index}`;\n if (seen.has(key)) return null;\n const entry = run.artifacts?.[ref.index]?.location;\n return entry ? resolve(entry, new Set([...seen, key])) : null;\n }\n if (!ref.uri) return null;\n if (!ref.uriBaseId) return ref.uri;\n if (seen.has(ref.uriBaseId)) return null;\n const base = run.originalUriBaseIds?.[ref.uriBaseId];\n if (!base) return null;\n const prefix = resolve(base, new Set([...seen, ref.uriBaseId]));\n if (!prefix) return null;\n // Base URIs use concatenation, preserving traversal for the path validator.\n return /^[a-z][a-z0-9+.-]*:/i.test(ref.uri) ? ref.uri : prefix + ref.uri;\n };\n for (const [resultIndex, result] of (run.results ?? []).entries()) {\n const kind = result.kind ?? \"fail\";\n const isSuppressed = result.suppressions?.some(s => s.status === \"accepted\");\n if (result.suppressions?.some(s => !s.status || s.status === \"underReview\")) {\n diagnostics.push(`Suppression state unresolved for result ${runIndex}:${resultIndex}.`); unresolved++;\n }\n const state = result.baselineState === \"absent\" ? \"absent\" : isSuppressed ? \"suppressed\" : kind === \"fail\" ? \"active\" : \"informational\";\n if (state === \"active\") active++;\n if (state === \"absent\") absent++;\n if (state === \"suppressed\") suppressed++;\n if ([\"open\", \"review\"].includes(kind) && state === \"informational\") { unresolved++; diagnostics.push(`Result ${runIndex}:${resultIndex} needs further analysis or review.`); }\n if (kind === \"pass\" || kind === \"notApplicable\") continue;\n const rule = result.ruleIndex !== undefined ? run.tool.driver.rules?.[result.ruleIndex] : run.tool.driver.rules?.find(rule => rule.id === result.ruleId);\n const template = result.message.id ? rule?.messageStrings?.[result.message.id] ?? run.tool.driver.globalMessageStrings?.[result.message.id] : undefined;\n const rawMessage = result.message.text ?? result.message.markdown ?? template?.text ?? template?.markdown;\n if (!rawMessage) diagnostics.push(`Message cannot be resolved for result ${runIndex}:${resultIndex}.`);\n const rendered = (rawMessage ?? `Unresolved SARIF message ${result.message.id ?? \"\"}`).replace(/\\{(\\d+)\\}/g, (match, n) => result.message.arguments?.[Number(n)] ?? match);\n const locations: EvidenceLocation[] = [];\n for (const entry of [...(result.locations ?? []), ...(result.relatedLocations ?? [])]) {\n const ref = entry.physicalLocation?.artifactLocation;\n const uri = ref ? resolve(ref) : null;\n const file = uri ? evidencePath(uri, sourceRoot, true) : null;\n if (file) locations.push({ file, line: entry.physicalLocation?.region?.startLine, column: entry.physicalLocation?.region?.startColumn });\n else diagnostics.push(`Unresolved or out-of-checkout location for result ${runIndex}:${resultIndex}.`);\n }\n const severity = result.level ?? rule?.defaultConfiguration?.level ?? (kind === \"fail\" ? \"warning\" : \"none\");\n findings.push({ id: `${runIndex}:${resultIndex}`, ruleId: result.ruleId ?? rule?.id, ...messagePreview(rendered), severity: severity === \"none\" ? \"note\" : severity, state, locations });\n }\n }\n if (!report.runs.length) diagnostics.push(\"SARIF contains no analysis runs.\");\n if (executionFailed) diagnostics.push(\"The SARIF tool reported an unsuccessful analysis invocation.\");\n return { outcome: executionFailed || !report.runs.length || report.runs.some(r => !r.results) ? \"unavailable\" : active ? \"failed\" : \"passed\",\n findings, counts: { active, suppressed, absent, unresolved }, incomplete: diagnostics.length > 0,\n diagnostics, reportedCommits, reportedCommands, reportedTools, executed: executed && !executionFailed };\n}\n","import { z } from \"zod\";\nimport { evidencePath } from \"./paths.js\";\nimport { messagePreview, type ParsedEvidence, type RawFinding } from \"./types.js\";\n\nconst schema = z.object({\n version: z.literal(1),\n commit: z.string().regex(/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/).optional(),\n results: z.array(z.object({\n name: z.string().min(1).max(1000), status: z.enum([\"passed\", \"failed\", \"skipped\"]),\n message: z.string().max(100000).optional(),\n locations: z.array(z.object({ file: z.string().min(1).max(4000),\n line: z.number().int().positive().optional(), column: z.number().int().positive().optional() })).max(100).default([]),\n })).max(100000),\n});\n\n/** Adapter boundary for native validators. Derive outcomes from individual results;\n * a manifest still has to establish command completion and commit attribution. */\nexport function parseCheck(raw: unknown, sourceRoot: string): ParsedEvidence {\n const report = schema.parse(raw);\n const diagnostics: string[] = [], findings: RawFinding[] = [];\n const counts = { total: report.results.length, passed: 0, failed: 0, skipped: 0 };\n for (const [index, result] of report.results.entries()) {\n counts[result.status]++;\n const locations = result.locations.flatMap(location => {\n const file = evidencePath(location.file, sourceRoot);\n if (!file) { diagnostics.push(`Check location is outside the declared checkout or invalid: ${location.file}`); return []; }\n return [{ ...location, file }];\n });\n if (result.status === \"failed\") findings.push({ id: String(index),\n ...messagePreview([result.name, result.message].filter(Boolean).join(\"\\n\")), severity: \"error\", state: \"active\", locations });\n }\n if (!counts.total) diagnostics.push(\"No check results were recorded; an empty report is not passing evidence.\");\n if (counts.skipped) diagnostics.push(`${counts.skipped} checks were skipped; verification is incomplete.`);\n return { outcome: counts.failed ? \"failed\" : !counts.total ? \"unavailable\" : !counts.passed ? \"skipped\" : \"passed\",\n counts, findings, incomplete: diagnostics.length > 0, diagnostics,\n ...(report.commit ? { reportedCommits: [report.commit] } : {}) };\n}\n","import { runReviewCli } from \"../src/review/cli.js\";\n\nrunReviewCli(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (err) => {\n process.stderr.write(`mason-review error: ${err}\\n`);\n process.exit(2);\n }\n);\n"],"mappings":"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","names":["path","fs","path","execFile","promisify","fs","path","execFile","promisify","path","execFile","promisify","path","path","fs","path","fs","path","path","path","count","exec","promisify","execFile","exec","exec","promisify","execFile","exec","z","z","message","index","fs","path","z","path","z","fs","path","path","execFile","promisify","exec","index","path","z","z","message","z","index","z","z","schema","rule","z","schema","z","index","location","z","path","index","exec","promisify","execFile","path","fs","path"]}