import { z } from "zod"; /** * IDs are re-used verbatim from the source research documents so that the * drift test (test/drift.test.ts) can diff model IDs against IDs extracted * straight out of the PR tables, with no hand-maintained translation layer. */ export declare const LoopId: z.ZodString; export type LoopId = z.infer; export declare const FlowId: z.ZodString; export type FlowId = z.infer; export declare const FeatureId: z.ZodString; export type FeatureId = z.infer; export declare const JunctionId: z.ZodString; export type JunctionId = z.infer; export declare const ScenarioId: z.ZodString; export type ScenarioId = z.infer; /** * Max length of `Evidence.note`. `note` exists only to help a reader * *locate* the anchored evidence (a line range, a function name, a test-name * fragment) — NOT to narrate causal reasoning or historical background. * The cap is a mechanical backstop for that intent: prose explanations run * long, pointers stay short. Kept as a named const so the schema test and * any future review tooling reference the same number. */ export declare const EVIDENCE_NOTE_MAX = 200; /** * Max lines in a `Crux.text` fragment (Proposal 013 B2, aligned with Graft's * MAX_CRUX_LINES). A crux captures a SHORT behavioural snippet — enough to * identify the concern, not to reproduce the implementation. */ export declare const CRUX_MAX_LINES = 12; /** * Max characters in a `Crux.text` fragment. Works alongside CRUX_MAX_LINES * as an absolute cap — 12 very long lines could still be unwieldy. */ export declare const CRUX_MAX_CHARS = 1200; /** * A crux text anchor (Proposal 013 B2): a verbatim code snippet pinned to * an existing anchor, capturing specific behaviour that `path#symbol` is too * coarse to express. `text` is the source of truth — the exact code fragment; * line numbers are never stored because they rot on every edit. * * The `anchor` field MUST reference one of the owning node's `anchors` entries * (a crux is a refinement of an existing anchor, not a third anchor form). */ export declare const Crux: z.ZodObject<{ anchor: z.ZodString; text: z.ZodEffects, string, string>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; text: string; note?: string | undefined; }, { anchor: string; text: string; note?: string | undefined; }>; export type Crux = z.infer; /** * Evidence is embedded inside Junction (evidence: Evidence[]) rather than * a standalone top-level file — it only makes sense bound to the claim it * proves. Scenario does NOT carry Evidence directly: its `verified_by` * field holds plain test/E2E anchor strings instead, since GWT→test * binding is a simpler 1:many mapping than Junction's need for typed, * multi-kind evidence. * * `kind` taxonomy: * - Runtime/code evidence: test / durable_event / e2e / metric / trace / * log / code — an anchor that resolves to a projection or observation of * the running system. * - Intent/planning evidence (Proposal 006 A1): `spec` points at a * requirement/design statement (a spec section, an ADR line), `issue` * points at a tracked work item (a GitHub issue/PR reference). These let * a junction cite "this handoff is deliberately deferred, see #NNNN" or * "the poller's settled≠done semantics is specified here" without dressing * a planning pointer up as a runtime observation. Because they are the * easiest kind to smuggle prose into, `note` on these is held to the same * anchor-only, pointer-not-narrative discipline as every other kind (see * `EVIDENCE_NOTE_MAX`); reviewers of any content PR treat a `spec`/`issue` * note that argues causation or recounts history as a defect. */ export declare const Evidence: z.ZodObject<{ id: z.ZodString; kind: z.ZodEnum<["test", "durable_event", "e2e", "metric", "trace", "log", "code", "spec", "issue"]>; anchor: z.ZodString; source: z.ZodOptional; transport: z.ZodOptional>; binding: z.ZodOptional; }, "strip", z.ZodTypeAny, { image_revision: "required" | "optional"; }, { image_revision: "required" | "optional"; }>>; confidence: z.ZodOptional>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }>; export type Evidence = z.infer; /** * Loop covers both ordinary top-level loops (L1, N19, ...) and the * "(内嵌)" embedded submachines (L1a/L1b/L3a/L20a) that share a parent's * boundary but carry their own state. Dormant/unwired loops like N8 * ("M2 休眠") have owner: null and dormant: true instead of being dropped. */ export declare const Loop: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"loop">; title: z.ZodString; boundary: z.ZodString; owner: z.ZodNullable; section: z.ZodOptional; parent: z.ZodOptional; embedded: z.ZodOptional; dormant: z.ZodOptional; status: z.ZodDefault>; anchors: z.ZodDefault>; /** * What DRIVES this loop forward, declared so it can be checked against the * code rather than taken on faith: "poller" (a timer), "queue" (a consumer). * * OPTIONAL, and absent means unchecked — existing models keep validating * untouched. Declaring it opts the loop into `checkLoopMechanism`, which * asserts a matching fact actually exists in the files this loop anchors. * That is the one tier able to catch behaviour that MOVED while the anchor * kept pointing at a surviving wrapper (a god-file split relocates the * `setInterval` into a new service file; every other check stays green). * * Adopt it in batches, on loops whose anchors have been eyeballed — a * mechanism claim on an un-reviewed anchor is just a warning waiting to * happen, and a check that greets you with dozens of them gets muted. */ mechanism: z.ZodOptional, "many">>; /** * pg-boss queue names this loop CONSUMES (Proposal 006 C2 root-fix). A queue is * defined at its producer/enqueue site (e.g. a shared `services.ts` registry) * but its lifecycle belongs to the consuming loop, which may live in a * different file. Declaring the names here lets reconciliation register a queue * fact by NAME — so a producer-registry definition is not a false "unregistered" * just because its file carries no anchor. This is an explicit modeling * assertion ("this loop consumes order:process"), verified against the * consumer's queue handler; it is NOT a way to silence facts (that would be a * dormant loop) and NOT a synthetic node (a registry file is not a loop). */ consumes_queues: z.ZodDefault>; scenarios: z.ZodDefault>; crux: z.ZodOptional, string, string>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; text: string; note?: string | undefined; }, { anchor: string; text: string; note?: string | undefined; }>, "many">>; notes: z.ZodOptional; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "loop"; title: string; boundary: string; owner: string | null; anchors: string[]; consumes_queues: string[]; scenarios: string[]; section?: string | undefined; parent?: string | undefined; embedded?: boolean | undefined; dormant?: boolean | undefined; mechanism?: ("poller" | "queue")[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; notes?: string | undefined; }, { id: string; kind: "loop"; title: string; boundary: string; owner: string | null; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; section?: string | undefined; parent?: string | undefined; embedded?: boolean | undefined; dormant?: boolean | undefined; anchors?: string[] | undefined; mechanism?: ("poller" | "queue")[] | undefined; consumes_queues?: string[] | undefined; scenarios?: string[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; notes?: string | undefined; }>; export type Loop = z.infer; /** * Flow = composite flow (C1..C9). `traverses` is the ordered loop sequence; * `guarded_by` holds watchdog loops (e.g. C1's L9) that don't sit in the * primary sequence but cover it; `references` holds sub-flow composition * (e.g. C1 references C2/C3 as expandable sub-chains). */ export declare const Flow: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"flow">; title: z.ZodString; traverses: z.ZodDefault>; guarded_by: z.ZodDefault>; crosses: z.ZodDefault>; references: z.ZodDefault>; /** * Code symbols this flow's implementation is pinned to (`path#symbol`), same * shape as `Loop.anchors`. ORTHOGONAL to `traverses`/`references`: those * compose other MODEL nodes (which loops/sub-flows the journey runs through), * while `anchors` binds the flow to real CODE — the escape hatch for a * flow-shaped repo (a CLI, a one-shot pipeline) whose journeys are not made of * background loops and would otherwise carry no code binding at all. A flow * that composes loops needs no anchors (its parts are anchored); a flow that * composes nothing relies on these to be checkable. Conformance grades a flow * on these when present (Proposal — Flow first-class / F1). */ anchors: z.ZodDefault>; /** * GWT scenarios that guard this flow's journey, `verified_by` pointing at real * tests — same mechanism as `Loop.scenarios` (F2b). A code-anchored flow with * no verified scenario is `partial`, not `met`: anchored ≠ tested. Only meaningful * for a GRADED flow (one with own anchors); a composition-only flow is graded * through its constituent loops, which carry their own scenarios. */ scenarios: z.ZodDefault>; crux: z.ZodOptional, string, string>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; text: string; note?: string | undefined; }, { anchor: string; text: string; note?: string | undefined; }>, "many">>; /** * Which KIND of flow this is (Proposal 012 §2.2) — the field that stops the * engine from guessing: * * - `composed`: a derived view. Its journey is made of other model nodes and * it holds no implementation of its own; those nodes carry the anchors and * are graded individually. * - `anchored`: it holds implementation itself (`anchors`) — the escape hatch * for a flow-shaped repo (a CLI, a one-shot pipeline) whose journeys are not * made of background loops. MAY also compose: an anchored flow's own anchors * are its own contribution, distinct from the parts it composes, so that is * not double-counting. * * OPTIONAL for backward compatibility: when omitted, `flowShape()` derives it * from whether `anchors` is non-empty. That derivation lives in exactly ONE * place so consumers never re-derive it (the mistake this field exists to * end); declaring it explicitly is preferred, and lets `check` catch a * `composed` flow that carries anchors. */ shape: z.ZodOptional>; risk_notes: z.ZodOptional; /** * Optional plain-language, developer-facing one-liner: what this journey does, * in words a newcomer understands ("发一条消息 → 系统跑完 → 回复送达"). Distinct * from `title` (a label) and `risk_notes` (risk commentary). Authored in the * model — the source of truth — so the `overview` projection stays model-driven * rather than carrying hardcoded per-flow prose in the renderer. */ summary: z.ZodOptional; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "flow"; title: string; anchors: string[]; scenarios: string[]; traverses: string[]; guarded_by: string[]; crosses: string[]; references: string[]; shape?: "composed" | "anchored" | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; risk_notes?: string | undefined; summary?: string | undefined; }, { id: string; kind: "flow"; title: string; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; shape?: "composed" | "anchored" | undefined; anchors?: string[] | undefined; scenarios?: string[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; traverses?: string[] | undefined; guarded_by?: string[] | undefined; crosses?: string[] | undefined; references?: string[] | undefined; risk_notes?: string | undefined; summary?: string | undefined; }>; export type Flow = z.infer; /** * Does this flow's journey COMPOSE other model nodes, rather than binding to * code itself? Exhaustive over every composition field on `Flow` — keep it in * sync when one is added, the same discipline `collectReferences` in * src/validate/checks.ts is held to. * * Defined here, beside the schema, because two layers must agree on it and a * second copy is how they drift: conformance uses it to decide whether a flow * is graded at all, and `checkFlowScenarioIgnored` uses it to warn about the * scenarios that decision silently drops. If those two ever disagree, the * warning fires on the wrong flows — or worse, stays silent on the right ones. */ export declare function flowComposes(flow: Flow): boolean; /** * The flow's shape, declared or derived — **the only place the derivation is * allowed to happen** (Proposal 012 §2.2 / T1). * * Before this existed, every consumer re-derived "is this flow anchored?" from * `anchors.length` on its own, and the ones that forgot to (graph, overview, * evidence, inspect, reconcile, diff) each became a bug. A single predicate * means a consumer either asks the question correctly or does not ask it. * * Derivation for an undeclared flow is deliberately the weakest possible rule — * "has anchors ⇒ anchored" — so it can never disagree with what an author who * DID declare `shape` meant. `checkFlowShapeConsistency` catches the one * combination where a declaration and the anchors contradict each other. */ export declare function flowShape(flow: Flow): "composed" | "anchored"; /** * Is this flow graded by conformance on its own merits? * * Three cases, and the excluded one is the point: * 1. `anchored` → graded on its own anchors, EVEN IF it also composes. * 2. `composed` but composes NOTHING → graded, and will be a `no-anchor` gap: * a journey bound to neither code nor other nodes is an unbacked claim. * 3. `composed` AND composes something → NOT graded. Its implementation IS * the nodes it composes, which are graded already; grading it too would * double-count their green and move the headline. Counted in * `flowsExcluded` so the exclusion is visible, never silent. */ export declare function isGradedFlow(flow: Flow): boolean; export declare const Junction: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"junction">; title: z.ZodOptional; risk_class: z.ZodEnum<["handoff", "idempotency", "projection", "failure_propagation", "watchdog"]>; /** * The two (or more) sides this junction sits between. Loop↔Loop was the only * expressible shape until Flow became a first-class, code-anchored node * (Proposal 012): a handoff can just as easily sit between a flow and a loop, * or between two flows, and until Proposal 016 T4 the only way to write one * down was to demote the finding to a `debt` entry — losing the `risk_class`, * the `evidence` and the `scenarios` that are what make a junction actionable * (two findings lost that way in the 0.8.0 external evaluation, D3). * * `LoopId` and `FlowId` match disjoint id shapes, so which kind an endpoint * names is always recoverable from the string alone — see * `junctionEndpointKind`, the one place that derivation is allowed to happen. */ between: z.ZodArray, "many">; scenarios: z.ZodDefault>; evidence: z.ZodDefault; anchor: z.ZodString; source: z.ZodOptional; transport: z.ZodOptional>; binding: z.ZodOptional; }, "strip", z.ZodTypeAny, { image_revision: "required" | "optional"; }, { image_revision: "required" | "optional"; }>>; confidence: z.ZodOptional>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }>, "many">>; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "junction"; scenarios: string[]; risk_class: "handoff" | "idempotency" | "projection" | "failure_propagation" | "watchdog"; between: string[]; evidence: { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }[]; title?: string | undefined; }, { id: string; kind: "junction"; risk_class: "handoff" | "idempotency" | "projection" | "failure_propagation" | "watchdog"; between: string[]; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; title?: string | undefined; scenarios?: string[] | undefined; evidence?: { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }[] | undefined; }>; export type Junction = z.infer; /** * Which kind a `Junction.between` endpoint names — the **only place that * derivation is allowed to happen**, the same discipline `flowShape` is held to * and for the same reason: every consumer that re-derives it on its own is a * bug waiting to be written. * * Total by construction. The schema accepts an endpoint only if it matched * `LoopId` (`L1` / `L1a` / `N32`) or `FlowId` (`C42`), and those two regexes are * disjoint, so "not flow-shaped" means "loop-shaped". * * A consumer holding a loaded graph should still prefer looking the id up * (`getNode`) — that is the ground truth. This answers the question for a * DANGLING endpoint too, which is what lets `check` report a missing `C99` as * "not a defined flow" instead of "not a defined loop". */ export declare function junctionEndpointKind(id: string): "loop" | "flow"; /** * Selector for effective-constraints propagation (Decision record 004, * 技术点 2): decides which nodes an Invariant-flavored Scenario applies * to automatically, without hand-listing the scenario id in every * relevant node's `scenarios` array. Resolved at query time by * src/query/effective-constraints.ts, never materialized — see that * module for match semantics (owner_match is substring containment with * optional `*` wildcard, NOT prefix-anchored or POSIX glob). */ export declare const AppliesTo: z.ZodObject<{ nodes: z.ZodDefault>; owner_match: z.ZodOptional; }, "strip", z.ZodTypeAny, { nodes: string[]; owner_match?: string | undefined; }, { nodes?: string[] | undefined; owner_match?: string | undefined; }>; export type AppliesTo = z.infer; /** * A test anchor written as TEXT instead of `path#symbol`. * * WHY THIS EXISTS. A JS/TS test's identity is usually a STRING, not a symbol: * `it('claimAsRunning transitions QUEUED -> RUNNING and returns the job')`. * The `path#symbol` form's symbol segment is `[\w.]+`, so an author with a * real test title has exactly two options, and both are bad: skip * `verified_by` (the behaviour reads as unguarded), or underscore the title * into `#claimAsRunning_transitions_QUEUED_to_RUNNING…` — a symbol that * appears nowhere in the file, so the anchor is stale the day it is written. * Measured on a real target: 5 of 5 test anchors on the model's only `met` * node were underscored titles, every one of them a phantom. * * The mechanism is NOT new — it is `crux`'s (Proposal 013 B2): two-tier * matching (exact substring, then whitespace-normalized) against the file's * text, always a warning, never promoted by `--strict-anchors`. See crux.ts. */ export declare const TestTextAnchor: z.ZodObject<{ file: z.ZodString; text: z.ZodString; }, "strip", z.ZodTypeAny, { text: string; file: string; }, { text: string; file: string; }>; export type TestTextAnchor = z.infer; export declare const Scenario: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"scenario">; given: z.ZodString; when: z.ZodString; then: z.ZodString; level: z.ZodEnum<["unit", "focused-integration", "contract", "integration", "e2e", "operational"]>; /** `path#symbol` test anchors. Text-form entries are moved out — see below. */ verified_by: z.ZodDefault>; /** * NORMALIZED LANDING FIELD, not a second thing for authors to remember. * Authors write both anchor forms inline in ONE `verified_by` list: * * verified_by: * - test/unit/job.spec.ts#JobRepository # symbol form * - {file: test/e2e/chain.spec.ts, text: "resumes a stranded chain"} * * and `loadModel` moves the object entries here before validation (see * `splitVerifiedBy` in loader/load-model.ts). Kept as a separate field * rather than widening `verified_by`'s element type because the two forms * are checked by different mechanisms and because a union element type * would force every display/query consumer of `verified_by` to branch — * `crux` sits beside `anchors` for the same reason. Read both together via * `scenarioTestAnchorLabels` / `scenarioHasTestEvidence`; a bare * `verified_by.length` under-reports a text-anchored scenario. */ verified_by_text: z.ZodDefault, "many">>; applies_to: z.ZodOptional>; owner_match: z.ZodOptional; }, "strip", z.ZodTypeAny, { nodes: string[]; owner_match?: string | undefined; }, { nodes?: string[] | undefined; owner_match?: string | undefined; }>>; }, "strip", z.ZodTypeAny, { then: string; id: string; kind: "scenario"; given: string; when: string; level: "e2e" | "unit" | "focused-integration" | "contract" | "integration" | "operational"; verified_by: string[]; verified_by_text: { text: string; file: string; }[]; applies_to?: { nodes: string[]; owner_match?: string | undefined; } | undefined; }, { then: string; id: string; kind: "scenario"; given: string; when: string; level: "e2e" | "unit" | "focused-integration" | "contract" | "integration" | "operational"; verified_by?: string[] | undefined; verified_by_text?: { text: string; file: string; }[] | undefined; applies_to?: { nodes?: string[] | undefined; owner_match?: string | undefined; } | undefined; }>; export type Scenario = z.infer; /** Human-readable form of a text anchor, for reports and diff identity. */ export declare function testTextAnchorLabel(a: TestTextAnchor): string; /** * Every test anchor a scenario carries, in display form — the honest answer to * "what does this scenario point at?" across BOTH anchor forms. Use this * anywhere `verified_by` was previously read directly for display or counting. */ export declare function scenarioTestAnchorLabels(s: Scenario): string[]; /** Does this scenario point at any test at all (either anchor form)? */ export declare function scenarioHasTestEvidence(s: Scenario): boolean; export declare const Feature: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"feature">; title: z.ZodString; contains: z.ZodDefault>; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "feature"; title: string; contains: string[]; }, { id: string; kind: "feature"; title: string; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; contains?: string[] | undefined; }>; export type Feature = z.infer; /** * DebtEntry is deliberately a different shape from Loop: the 6 * dead-state-machine tables and 2 deferred loops from the seed baseline describe * something that LOOKS like a loop (has a status column / was scoped as * a loop) but fails the "independent advance mechanism" test — they are * baseline debt, not behavior to model as Loop nodes. */ export declare const DebtId: z.ZodString; export type DebtId = z.infer; export declare const DebtEntry: z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"debt">; category: z.ZodEnum<["dead_state_machine", "deferred", "other"]>; subject: z.ZodString; claim: z.ZodOptional; reality: z.ZodString; owner: z.ZodOptional; removal_condition: z.ZodOptional; }, "strip", z.ZodTypeAny, { id: string; kind: "debt"; category: "dead_state_machine" | "deferred" | "other"; subject: string; reality: string; owner?: string | undefined; claim?: string | undefined; removal_condition?: string | undefined; }, { id: string; kind: "debt"; category: "dead_state_machine" | "deferred" | "other"; subject: string; reality: string; owner?: string | undefined; claim?: string | undefined; removal_condition?: string | undefined; }>; export type DebtEntry = z.infer; export declare const ModelNode: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"feature">; title: z.ZodString; contains: z.ZodDefault>; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "feature"; title: string; contains: string[]; }, { id: string; kind: "feature"; title: string; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; contains?: string[] | undefined; }>, z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"flow">; title: z.ZodString; traverses: z.ZodDefault>; guarded_by: z.ZodDefault>; crosses: z.ZodDefault>; references: z.ZodDefault>; /** * Code symbols this flow's implementation is pinned to (`path#symbol`), same * shape as `Loop.anchors`. ORTHOGONAL to `traverses`/`references`: those * compose other MODEL nodes (which loops/sub-flows the journey runs through), * while `anchors` binds the flow to real CODE — the escape hatch for a * flow-shaped repo (a CLI, a one-shot pipeline) whose journeys are not made of * background loops and would otherwise carry no code binding at all. A flow * that composes loops needs no anchors (its parts are anchored); a flow that * composes nothing relies on these to be checkable. Conformance grades a flow * on these when present (Proposal — Flow first-class / F1). */ anchors: z.ZodDefault>; /** * GWT scenarios that guard this flow's journey, `verified_by` pointing at real * tests — same mechanism as `Loop.scenarios` (F2b). A code-anchored flow with * no verified scenario is `partial`, not `met`: anchored ≠ tested. Only meaningful * for a GRADED flow (one with own anchors); a composition-only flow is graded * through its constituent loops, which carry their own scenarios. */ scenarios: z.ZodDefault>; crux: z.ZodOptional, string, string>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; text: string; note?: string | undefined; }, { anchor: string; text: string; note?: string | undefined; }>, "many">>; /** * Which KIND of flow this is (Proposal 012 §2.2) — the field that stops the * engine from guessing: * * - `composed`: a derived view. Its journey is made of other model nodes and * it holds no implementation of its own; those nodes carry the anchors and * are graded individually. * - `anchored`: it holds implementation itself (`anchors`) — the escape hatch * for a flow-shaped repo (a CLI, a one-shot pipeline) whose journeys are not * made of background loops. MAY also compose: an anchored flow's own anchors * are its own contribution, distinct from the parts it composes, so that is * not double-counting. * * OPTIONAL for backward compatibility: when omitted, `flowShape()` derives it * from whether `anchors` is non-empty. That derivation lives in exactly ONE * place so consumers never re-derive it (the mistake this field exists to * end); declaring it explicitly is preferred, and lets `check` catch a * `composed` flow that carries anchors. */ shape: z.ZodOptional>; risk_notes: z.ZodOptional; /** * Optional plain-language, developer-facing one-liner: what this journey does, * in words a newcomer understands ("发一条消息 → 系统跑完 → 回复送达"). Distinct * from `title` (a label) and `risk_notes` (risk commentary). Authored in the * model — the source of truth — so the `overview` projection stays model-driven * rather than carrying hardcoded per-flow prose in the renderer. */ summary: z.ZodOptional; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "flow"; title: string; anchors: string[]; scenarios: string[]; traverses: string[]; guarded_by: string[]; crosses: string[]; references: string[]; shape?: "composed" | "anchored" | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; risk_notes?: string | undefined; summary?: string | undefined; }, { id: string; kind: "flow"; title: string; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; shape?: "composed" | "anchored" | undefined; anchors?: string[] | undefined; scenarios?: string[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; traverses?: string[] | undefined; guarded_by?: string[] | undefined; crosses?: string[] | undefined; references?: string[] | undefined; risk_notes?: string | undefined; summary?: string | undefined; }>, z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"loop">; title: z.ZodString; boundary: z.ZodString; owner: z.ZodNullable; section: z.ZodOptional; parent: z.ZodOptional; embedded: z.ZodOptional; dormant: z.ZodOptional; status: z.ZodDefault>; anchors: z.ZodDefault>; /** * What DRIVES this loop forward, declared so it can be checked against the * code rather than taken on faith: "poller" (a timer), "queue" (a consumer). * * OPTIONAL, and absent means unchecked — existing models keep validating * untouched. Declaring it opts the loop into `checkLoopMechanism`, which * asserts a matching fact actually exists in the files this loop anchors. * That is the one tier able to catch behaviour that MOVED while the anchor * kept pointing at a surviving wrapper (a god-file split relocates the * `setInterval` into a new service file; every other check stays green). * * Adopt it in batches, on loops whose anchors have been eyeballed — a * mechanism claim on an un-reviewed anchor is just a warning waiting to * happen, and a check that greets you with dozens of them gets muted. */ mechanism: z.ZodOptional, "many">>; /** * pg-boss queue names this loop CONSUMES (Proposal 006 C2 root-fix). A queue is * defined at its producer/enqueue site (e.g. a shared `services.ts` registry) * but its lifecycle belongs to the consuming loop, which may live in a * different file. Declaring the names here lets reconciliation register a queue * fact by NAME — so a producer-registry definition is not a false "unregistered" * just because its file carries no anchor. This is an explicit modeling * assertion ("this loop consumes order:process"), verified against the * consumer's queue handler; it is NOT a way to silence facts (that would be a * dormant loop) and NOT a synthetic node (a registry file is not a loop). */ consumes_queues: z.ZodDefault>; scenarios: z.ZodDefault>; crux: z.ZodOptional, string, string>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; text: string; note?: string | undefined; }, { anchor: string; text: string; note?: string | undefined; }>, "many">>; notes: z.ZodOptional; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "loop"; title: string; boundary: string; owner: string | null; anchors: string[]; consumes_queues: string[]; scenarios: string[]; section?: string | undefined; parent?: string | undefined; embedded?: boolean | undefined; dormant?: boolean | undefined; mechanism?: ("poller" | "queue")[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; notes?: string | undefined; }, { id: string; kind: "loop"; title: string; boundary: string; owner: string | null; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; section?: string | undefined; parent?: string | undefined; embedded?: boolean | undefined; dormant?: boolean | undefined; anchors?: string[] | undefined; mechanism?: ("poller" | "queue")[] | undefined; consumes_queues?: string[] | undefined; scenarios?: string[] | undefined; crux?: { anchor: string; text: string; note?: string | undefined; }[] | undefined; notes?: string | undefined; }>, z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"junction">; title: z.ZodOptional; risk_class: z.ZodEnum<["handoff", "idempotency", "projection", "failure_propagation", "watchdog"]>; /** * The two (or more) sides this junction sits between. Loop↔Loop was the only * expressible shape until Flow became a first-class, code-anchored node * (Proposal 012): a handoff can just as easily sit between a flow and a loop, * or between two flows, and until Proposal 016 T4 the only way to write one * down was to demote the finding to a `debt` entry — losing the `risk_class`, * the `evidence` and the `scenarios` that are what make a junction actionable * (two findings lost that way in the 0.8.0 external evaluation, D3). * * `LoopId` and `FlowId` match disjoint id shapes, so which kind an endpoint * names is always recoverable from the string alone — see * `junctionEndpointKind`, the one place that derivation is allowed to happen. */ between: z.ZodArray, "many">; scenarios: z.ZodDefault>; evidence: z.ZodDefault; anchor: z.ZodString; source: z.ZodOptional; transport: z.ZodOptional>; binding: z.ZodOptional; }, "strip", z.ZodTypeAny, { image_revision: "required" | "optional"; }, { image_revision: "required" | "optional"; }>>; confidence: z.ZodOptional>; note: z.ZodOptional; }, "strip", z.ZodTypeAny, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }, { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }>, "many">>; status: z.ZodDefault>; }, "strip", z.ZodTypeAny, { status: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated"; id: string; kind: "junction"; scenarios: string[]; risk_class: "handoff" | "idempotency" | "projection" | "failure_propagation" | "watchdog"; between: string[]; evidence: { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }[]; title?: string | undefined; }, { id: string; kind: "junction"; risk_class: "handoff" | "idempotency" | "projection" | "failure_propagation" | "watchdog"; between: string[]; status?: "conformant" | "unimplemented" | "unverified" | "drifted" | "unregistered" | "deprecated" | undefined; title?: string | undefined; scenarios?: string[] | undefined; evidence?: { anchor: string; id: string; kind: "code" | "test" | "durable_event" | "e2e" | "metric" | "trace" | "log" | "spec" | "issue"; note?: string | undefined; source?: string | undefined; transport?: "durable_event" | "direct" | "relay" | undefined; binding?: { image_revision: "required" | "optional"; } | undefined; confidence?: "high" | "medium" | "low" | undefined; }[] | undefined; }>, z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"scenario">; given: z.ZodString; when: z.ZodString; then: z.ZodString; level: z.ZodEnum<["unit", "focused-integration", "contract", "integration", "e2e", "operational"]>; /** `path#symbol` test anchors. Text-form entries are moved out — see below. */ verified_by: z.ZodDefault>; /** * NORMALIZED LANDING FIELD, not a second thing for authors to remember. * Authors write both anchor forms inline in ONE `verified_by` list: * * verified_by: * - test/unit/job.spec.ts#JobRepository # symbol form * - {file: test/e2e/chain.spec.ts, text: "resumes a stranded chain"} * * and `loadModel` moves the object entries here before validation (see * `splitVerifiedBy` in loader/load-model.ts). Kept as a separate field * rather than widening `verified_by`'s element type because the two forms * are checked by different mechanisms and because a union element type * would force every display/query consumer of `verified_by` to branch — * `crux` sits beside `anchors` for the same reason. Read both together via * `scenarioTestAnchorLabels` / `scenarioHasTestEvidence`; a bare * `verified_by.length` under-reports a text-anchored scenario. */ verified_by_text: z.ZodDefault, "many">>; applies_to: z.ZodOptional>; owner_match: z.ZodOptional; }, "strip", z.ZodTypeAny, { nodes: string[]; owner_match?: string | undefined; }, { nodes?: string[] | undefined; owner_match?: string | undefined; }>>; }, "strip", z.ZodTypeAny, { then: string; id: string; kind: "scenario"; given: string; when: string; level: "e2e" | "unit" | "focused-integration" | "contract" | "integration" | "operational"; verified_by: string[]; verified_by_text: { text: string; file: string; }[]; applies_to?: { nodes: string[]; owner_match?: string | undefined; } | undefined; }, { then: string; id: string; kind: "scenario"; given: string; when: string; level: "e2e" | "unit" | "focused-integration" | "contract" | "integration" | "operational"; verified_by?: string[] | undefined; verified_by_text?: { text: string; file: string; }[] | undefined; applies_to?: { nodes?: string[] | undefined; owner_match?: string | undefined; } | undefined; }>, z.ZodObject<{ id: z.ZodString; kind: z.ZodLiteral<"debt">; category: z.ZodEnum<["dead_state_machine", "deferred", "other"]>; subject: z.ZodString; claim: z.ZodOptional; reality: z.ZodString; owner: z.ZodOptional; removal_condition: z.ZodOptional; }, "strip", z.ZodTypeAny, { id: string; kind: "debt"; category: "dead_state_machine" | "deferred" | "other"; subject: string; reality: string; owner?: string | undefined; claim?: string | undefined; removal_condition?: string | undefined; }, { id: string; kind: "debt"; category: "dead_state_machine" | "deferred" | "other"; subject: string; reality: string; owner?: string | undefined; claim?: string | undefined; removal_condition?: string | undefined; }>]>; export type ModelNode = z.infer; //# sourceMappingURL=model.d.ts.map