/** * Deterministic derivers for contract-pipeline artifacts. * * S1 of the contract-authoring determinism design * (`spec/contract-authoring-determinism-design.md`): the contract pipeline * historically had the LLM author every structured artifact and the backend * only validate it afterward. For the artifacts whose *structure* is a pure * function of an upstream artifact, that is wasted generation and a weak-model * failure surface ("emit a large, schema-conforming, internally-consistent JSON * artifact from scratch with correct ids and cross-refs"). This module owns * those derivations so the tool produces the structure and the model is left * only the irreducible judgment. * * `deriveObligationLedger` is the flagship: the obligation ledger is a 1:1 * restructuring of the finalized module contracts — every module invariant and * failure mode becomes an obligation, and every module gets a * contract-conformance obligation — so no judgment is lost by generating it in * code. Construction goes through the shared `buildObligationLedger` so the * cycle check, version stamp, and envelope stay single-sourced with the rest of * the codebase (the non-negotiable "derivers and validators share one source — * no parallel logic"). */ import { type ObligationLedger } from "audit-tools/shared"; import { isTestablePhaseObligation } from "../validation/contractPipelineGates.js"; /** Options accepted by the derivers (created_at injected for deterministic tests). */ export interface DeriveOptions { /** Overrides the generated ISO-8601 timestamp (for deterministic snapshots). */ created_at?: string; } /** * Derive the obligation ledger deterministically from the finalized module * contracts. Pure function of its input (modulo the `created_at` stamp): the * same contracts always yield the same obligations in the same order, so the * artifact hash / staleness DAG stays well-behaved. * * Mapping (the inverse of the obligation-ledger consumers' expectations): * - one **structural** obligation per module ("implement this module per its * finalized contract") — guarantees the ledger is never empty and every * module has something the implementation DAG must cover, without inventing * a paired-test burden (structural is not a testable kind); * - one **invariant** obligation per declared module invariant (testable); * - one **behavioral** obligation per declared module failure mode (testable). * * `depends_on` is left empty: the validated module-contract shape declares no * inter-obligation ordering, so an honest derivation asserts none (and the * ledger is acyclic by construction — `buildObligationLedger` cannot throw). */ export declare function deriveObligationLedger(finalizedModuleContracts: unknown, options?: DeriveOptions): ObligationLedger; /** * Derive `finalized_module_contracts` deterministically from the drafted * `module_contracts` and the `seam_reconciliation_report`. Pure function of its * inputs (modulo the `created_at` stamp): the same drafts + seam report always * yield the same finalized contracts in draft order, so the artifact hash / * staleness DAG stays well-behaved. * * Each finalized entry copies the draft's interface fields verbatim (already * validated `string[]` / string shapes, so no coercion is needed) and PRESERVES * `neighbor_needs` for the ordering derivation, then sets `seam_adjustments` to * the `agreed_interface`(s) of the seams that touch the module. A draft entry * that is not an object is passed through unchanged (the downstream validator * reports it). */ export declare function deriveFinalizedModuleContracts(draftedModuleContracts: unknown, seamReconciliationReport: unknown, options?: DeriveOptions): { contract_version: string; goal_id: string; module_contracts: unknown[]; created_at: string; }; /** * Shared obligation-membership predicates — the single source for which * obligations each downstream scaffold covers. * * `isTestablePhaseObligation` (imported above) is now single-sourced in * `../validation/contractPipelineGates.ts` (MNT-e10b9d9b: this file's former * local TESTABLE_KINDS set and that file's TESTABLE_OBLIGATION_KINDS were * "kept in parity by hand" and had already diverged — fail-open here, * fail-closed there, on an identical unrecognized-kind input). Re-exported * here so every existing importer of derive.js keeps working unchanged. * * `isDagPhaseObligation`: every obligation is covered by the implementation DAG, * so this is always true. It exists so both scaffolds derive their membership * from a named predicate rather than an inline ad-hoc filter. */ export { isTestablePhaseObligation }; export declare function isDagPhaseObligation(_kind: string): boolean; export interface TestValidatorPlanScaffold { test_specs: Array<{ obligation_id: string; name: string; kind: string; /** * The change's scope anchors (touched symbols / file) the negative assertion * must name to pass the CE-006 negative-scoping gate. Derived here so the * host sees them IN the skeleton instead of discovering them only after a * write is rejected (D1). Advisory context — the host reads them, the gate * enforces them; an empty array means no change-scope constraint applies. */ scope_anchors: string[]; assertions: string[]; }>; } /** * A prior round's authored test spec, keyed by obligation_id, used to diff-carry * unchanged assertions across a re-emit (C3). Carries the identity signals * (`name` + `scope_anchors`) the carry decision is gated on plus the assertions. */ export interface PriorTestSpec { name: string; scope_anchors: string[]; assertions: string[]; } /** * Build the test-plan skeleton: one spec per *testable* (invariant/behavioral) * obligation, with `obligation_id`/`name`/`kind`/`scope_anchors` filled and * `assertions` left blank for the model. The model fills only the assertions * (each spec needs a paired positive + negative assertion per the OBL-CO-01 * gate, and the negative must name one of `scope_anchors` per CE-006). * * C3 diff-carry: when `priorByObligation` carries a prior round's authored spec * for an obligation whose premise is UNCHANGED (same `name` + same * `scope_anchors`), its assertions are pre-filled instead of left blank, so an * unchanged obligation is not re-authored from scratch every repair round. A * changed premise (renamed/re-scoped obligation) carries nothing — the host * re-authors it (fail-safe toward re-author, never toward stale carry). */ export declare function buildTestValidatorPlanScaffold(ledger: ObligationLedger | undefined, priorByObligation?: Record): TestValidatorPlanScaffold; export interface ImplementationDagScaffoldNode { id: string; title: string; description: string; satisfies_obligations: string[]; addresses_counterexamples: string[]; /** * Advisory conceptual-critique item ids this node addresses (B3). The * conceptual-design critique's `advisory`-severity items have no obligation or * counterexample to attach to, so without a structural slot the host smuggles * them into prose or test assertions. This carrier gives each one a first-class * home: the host records which advisory items a node's implementation honours. * Blank in the skeleton (the host fills it); advisory, so it is not gated. */ addressed_critique_items: string[]; depends_on: string[]; verification_obligation_ids: string[]; targeted_commands: string[]; status: string; } /** An advisory conceptual-critique item the host should account for in the DAG. */ export interface AdvisoryCritiqueItem { id: string; description: string; } /** * Advisory-severity items from a conceptual_design_critique payload (defensive * read). Blocking items drive the design-repair loop and are consumed there; * advisory items survive past the critique gate and need a structural home in * the implementation DAG — this surfaces them so the skeleton can list them (B3). */ export declare function advisoryCritiqueItems(critique: unknown): AdvisoryCritiqueItem[]; export interface ImplementationDagScaffold { nodes: ImplementationDagScaffoldNode[]; edges: never[]; } /** Accepted counterexample ids from a judge_report payload (defensive read). */ export declare function acceptedCounterexampleIds(judgeReport: unknown): string[]; /** * Build the implementation-DAG skeleton: ONE node per finalized *module* * (grouping all that module's obligations), blank title/description/ * targeted_commands for the model, and accepted counterexamples attached so * coverage holds by construction. Grouping by module means a 1-module change * derives 1 node instead of N obligation-nodes the host then has to merge (B2); * obligations with no module home (counterexample/critique-sourced) fall back * to one node each. Advisory: the model fills the blanks and may further * merge/split nodes as long as coverage is preserved. * * `depends_on` is DERIVED, not left for the host: when `finalizedContracts` is * supplied, each module node depends on the nodes of the modules it needs first * (producer/consumer `artifact:` matching over `inputs`/`outputs`, unioned * with `neighbor_needs` — the same module-dependency DAG `phase_cut` uses). This * makes cross-node ordering tool-enforced instead of a thing the host must * remember to hand-add. Edges are oriented by phase ordinal so the result is * acyclic by construction: only an edge to a strictly-earlier-phase module is * kept, which drops the back-edge of any dependency cycle (fail-toward-later, * mirroring `derivePhaseCut`). The `edges` array stays empty — node `depends_on` * is the ordering the block promotion reads. */ export declare function buildImplementationDagScaffold(ledger: ObligationLedger | undefined, acceptedCeIds: string[], finalizedContracts?: unknown): ImplementationDagScaffold; //# sourceMappingURL=derive.d.ts.map