/** * Han's two foundational rules, condensed into injectable contracts so every * worker and the validator apply the same primitives. Canonical sources are * vendored in `references/evidence-rule.md` and `references/yagni-rule.md`. * * - evidence-rule: trust classes, the web corroboration gate, no-evidence labeling. * - yagni-rule: the inclusion gate + the `## Deferred (YAGNI)` defer pattern. */ export type Contract = 'evidence' | 'yagni'; /** Applied when PRODUCING a judgment (research, investigation, analysis, plan, draft). */ export const EVIDENCE_PRODUCE = [ 'EVIDENCE DISCIPLINE (Han evidence-rule). Make every claim that drives a conclusion traceable:', '- Number evidence items (E1, E2… / sources A1, A2…); each carries a SOURCE and a TRUST CLASS — codebase (file:line; the trusted current-state anchor), web (URL + retrieval date; outside the trust boundary), or provided (operator-supplied; interested-party scrutiny).', '- Codebase evidence is authoritative on what the system does today; a single file:line citation stands on its own.', '- A WEB claim that bears on the conclusion with no independent corroboration is marked [single-source] and CANNOT be the sole basis for the conclusion. When sources conflict, surface both — never silently pick one.', '- A claim with NO evidence at any tier is LABELED as such, its decision DEFERRED, and a concrete reopen trigger named — never quietly downgraded to "weak evidence".', '- Cross-reference the evidence IDs each conclusion rests on.', ].join('\n'); /** Applied when REVIEWING a judgment (the adversarial gate). */ export const EVIDENCE_REVIEW = [ 'EVIDENCE REVIEW (Han evidence-rule): for every committed claim, check that — its trust class is named or inferable; single-source web claims are marked and do not stand alone as the basis for a conclusion; no-evidence claims are labeled and deferred with a trigger (not treated as weak evidence); and source-vs-source contradictions are surfaced rather than silently resolved.', ].join('\n'); /** Applied when PRODUCING a committable artifact (spec, plan, standard, ADR, runbook, tests). */ export const YAGNI_PRODUCE = [ 'YAGNI (Han yagni-rule). Every item you commit must cite at least one piece of evidence it is needed NOW: a user-described need, a named in-scope dependency, an existing code path/contract that breaks without it, an applicable regulation, or a real incident/alert/measured metric.', '- If no such evidence applies, do NOT commit the item — record it under a `## Deferred (YAGNI)` section with the concrete trigger that would reopen it (omit the section entirely if nothing is deferred).', '- When evidence justifies an item, prefer the strictly simpler version that satisfies the same evidence (a function over a class, one implementation over an interface, a literal over a config knob).', '- Treat "might need / at scale / best practice", symmetry-for-completeness, single-implementation interfaces, and speculative config/observability as YAGNI candidates that must be affirmatively justified.', ].join('\n'); /** Applied when REVIEWING for YAGNI (the adversarial gate). */ export const YAGNI_REVIEW = [ 'YAGNI REVIEW (Han yagni-rule): run the evidence-of-need test on every committed item; raise a "YAGNI candidate" finding for any item with no cited evidence-of-need, or where a strictly simpler version satisfies the same evidence. Named anti-patterns (speculative flexibility, scale-without-pressure, single-impl interfaces, runbooks/alerts/SLOs without signal) force a finding regardless of severity.', ].join('\n'); /** Build the producing-side contract block for a set of contracts. */ export function produceContract(contracts: Contract[]): string { const parts: string[] = []; if (contracts.includes('evidence')) parts.push(EVIDENCE_PRODUCE); if (contracts.includes('yagni')) parts.push(YAGNI_PRODUCE); return parts.length ? '\n\n' + parts.join('\n\n') : ''; } /** Build the reviewing-side contract block (for the validator charter). */ export function reviewContract(contracts: Contract[]): string { const parts: string[] = []; if (contracts.includes('evidence')) parts.push(EVIDENCE_REVIEW); if (contracts.includes('yagni')) parts.push(YAGNI_REVIEW); return parts.length ? '\n\n' + parts.join('\n\n') : ''; }