import type { LoadResult } from "../loader/load-model.js"; import { type ModelGraph } from "../loader/model-graph.js"; import type { Violation } from "./types.js"; /** Schema-parse failures collected during loadModel become blocking violations. */ export declare function checkSchema(load: LoadResult): Violation[]; /** * Advisory: a file-per-node file's name (minus extension) must equal the id of * the single node it holds (Decision 004 技术点 3 — promised for Phase 1, * delivered here in A7). Only single-node files are checked; array files that * group many nodes under a section name (loops/*.yaml) carry the section, not * an id, and are correctly exempt (see LoadResult.singleNodeFiles). Warning, * not error: a mismatch is a naming-hygiene slip a human should fix, not a * reason to fail a build (the model still loads correctly). */ export declare function checkFilenameMatchesId(load: LoadResult): Violation[]; /** Duplicate ids collected during loadModel become blocking violations. */ export declare function checkIdUniqueness(load: LoadResult): Violation[]; /** * Every anchor string a graph references, deduped — the exact input * `resolveAnchorPresence` needs. Exported so `conformance` resolves the SAME * anchor set `check` does instead of deriving its own (Proposal 016 T6). */ export declare function collectAnchorStrings(graph: ModelGraph): string[]; /** Blocking: every anchor must be syntactically well-formed (file#symbol or table[.column]). */ export declare function checkAnchorFormat(graph: ModelGraph): Violation[]; /** * Blocking: every cross-node reference (Flow.traverses, Junction.between, * Loop.parent, etc.) must resolve to an actual node of the expected kind * in the loaded graph. This is pure set-membership over an already-loaded * graph — no I/O, no AST — so it stays within T0's cost budget despite * catching what would otherwise be a silent dangling/typo'd reference * (e.g. a Flow.traverses entry that matches the LoopId regex shape but * names a Loop that was never actually defined). */ export declare function checkReferentialIntegrity(graph: ModelGraph): Violation[]; /** * Blocking: neither `Loop.parent` nor `Flow.references` may form a * cycle. These are the only two same-kind reference fields in the schema. * * Cross-kind edges are NOT cycle-checked, and since Proposal 016 T4 that is a * deliberate choice rather than a structural impossibility: `Junction.between` * now accepts flow ids, so `Flow.crosses -> Junction -> Flow(between)` closes a * two-kind ring. That ring is exactly what a correctly modeled flow-level * handoff looks like — C1 crosses J-x, and J-x names C1 as one of its * endpoints — so reporting it would fail every model that uses the new * expressiveness. Every REMAINING cross-kind edge (Flow.traverses/guarded_by, * Junction.between->loop, Loop.scenarios, Feature.contains, every `scenarios` * field) still runs into a kind carrying no reference field pointing back * (Scenario has no node-reference outputs at all; Loop's only outputs are * `parent` and `scenarios`; Feature's only output is `contains`), so no other * cross-kind ring exists today. This is a claim about today's schema shape, not * a structural guarantee: adding any new node-reference field (same-kind OR * cross-kind) invalidates it and requires re-deriving both which edges can now * close a ring and, for each new ring, whether it is a defect or legitimate * modeling. */ export declare function checkGraphAcyclic(graph: ModelGraph): Violation[]; /** * Rule 1 of the `shape` contract (Proposal 012 §2.2): a flow declared * `composed` must not carry `anchors`. * * ERROR, not warning, and deliberately so — unlike `flow-scenario-ignored`, * which stays advisory because the model there is well-formed and the grading * RULE may be what needs to change. Here the two statements contradict each * other: `composed` means "I hold no implementation of my own; grade my parts * instead", and anchors say the opposite. The two readings produce opposite * grading (excluded vs graded `met`), so silently picking one is the engine * guessing again — the entire thing `shape` exists to stop. * * This does NOT block incremental adoption: `shape` is optional, so a model * that never declares it can never trip this check. Only a flow that * explicitly claims `composed` AND carries anchors does, and the fix is one * word. An error is affordable precisely because it is unreachable by accident. */ export declare function checkFlowShapeConsistency(graph: ModelGraph): Violation[]; /** * A composition-only flow (no own `anchors`, composes other model nodes) is * deliberately kept OUT of conformance grading — its constituent loops are * already graded, and grading it too would double-count their green. The * consequence is that any `scenarios` such a flow declares are never evaluated: * they neither lift the flow's verdict (it has none) nor guard its loops (which * only see their own `scenarios`). * * Left silent, that is a trap: the author attaches a real, verified GWT at the * flow level, `check` passes, and conformance still reports the traversed loops * as `unguarded (no scenario)`. The loop report is not itself wrong — a loop * with no own scenarios has always said that — but the flow-level attachment * creates a NEW way to believe you have closed a gap you have not. So say it. * * WARNING, not error: the model is not malformed, and the fix may well be to * change the grading rule rather than the model. Whether own-scenarios should * opt a flow INTO grading (symmetrically with own-anchors) is the open question * tracked in the Flow-first-class alignment issue; until that is decided this * check refuses to let the case pass unnoticed. */ export declare function checkFlowScenarioIgnored(graph: ModelGraph): Violation[]; /** * Advisory by default: does the anchored file exist under `repoRoot`, and does * that file still declare the anchored symbol? * * Two tiers, deliberately different severities: * * - FILE missing → `severity` (warning, or error under `strict`). A target * repo's HEAD legitimately moves past the commit a model was authored * against; treat it as "investigate: mis-encoded vs. code moved on". * - SYMBOL missing → always a warning, never promoted by `strict`. The file * is right and only the name is stale: that is a nudge, not a stop-the-line * event, and the lookup behind it is text-level (see symbol.ts) so it is the * tier likeliest to be imprecise. Promoting it under `strict` would turn a * repo's first upgrade into a red gate over bookkeeping. * * WHAT NEITHER TIER CATCHES, and why the loop-mechanism check exists: an * anchor can point at a file that exists, name a symbol that exists, and still * describe behaviour that has moved away. Splitting a god-file typically * leaves a one-line delegating wrapper behind (`return this.sandbox.start(id)`) * — file present, symbol present, timer gone. Both tiers here stay green. See * `checkLoopMechanism`. */ export declare function checkAnchorExistence(graph: ModelGraph, repoRoot: string, options?: { strict?: boolean | undefined; }): Promise; /** * The text-anchor half of `verified_by` (schema `TestTextAnchor`): does the * quoted test title still appear in the file that claims to hold it? * * Two tiers with different severities, drawn exactly where * `checkAnchorExistence` draws them — the notation an author picked must never * change how strict the gate is: * * - FILE missing → `severity` (error under `strict`). A path that resolves to * nothing is a hard fact with no false-negative risk, in either anchor form. * Leaving this a warning would mean rewriting one entry from `path#symbol` * to `{file, text}` quietly excused a missing test file from the gate. * - TEXT not found → ALWAYS a warning, never promoted, same as `crux`. Here * the evidence is text matching, whose false-negative rate on a legitimate * reword must stay cheap; this form exists precisely so an author can name a * test honestly instead of underscoring its title into a symbol that was * never in the file, and punishing that with a red build would undo it. The * report card consumes the same result (conformance stops counting a * scenario whose test anchor went stale), which is where the consequence * belongs: gate lenient, score honest. * * `anchor-crux` rather than a new check name, deliberately: it is the same * mechanism on a different field, and a reader who has muted or triaged * "crux text moved" wants this in the same bucket. */ export declare function checkVerifiedByText(graph: ModelGraph, repoRoot: string, options?: { strict?: boolean | undefined; }): Promise; //# sourceMappingURL=checks.d.ts.map