import type { Spec } from "@slowcook-ai/core"; /** * 0.14.0-α.6+ — content-level validators for parsed specs. Runs AFTER * Zod shape-validation, BEFORE writing to disk. Catches LLM-output * truncation that shape-validation misses (e.g. `var(--tint-in` is a * valid string but a corrupted token). * * Detects + repairs in place when the fix is unambiguous; drops + logs * otherwise. Returns a list of human-readable findings so the caller * can surface them in the PR body or run logs. * * Caught on rewo story-016 (2026-04-26): LLM emit ended a 12-token list * mid-entry with `var(--tint-in`. Spec passed Zod, the corrupt token * sat in tokens_to_reuse and downstream brew/testgen would see it as * a real (but missing) project token. */ export interface SpecValidationFinding { /** Dotted path to the field, e.g. "proposals.ui_layout.tokens_to_reuse[12]". */ path: string; /** What we noticed. */ message: string; /** Action taken: "dropped" (entry removed), "repaired" (auto-fixed), "flagged" (kept as-is, needs-review). */ action: "dropped" | "repaired" | "flagged"; } /** Mutates `spec` in place; returns findings for caller to surface. */ export declare function validateAndRepairSpec(spec: Spec): SpecValidationFinding[]; /** * 0.19.x+ — catch hallucinated entity.field references in the spec. * * Refine sometimes invents fields that don't exist on the consumer's * actual entities (e.g. story-005 in delgoosh referenced * `user.timezone.label` but Timezone has only `name`/`offset`/`offsetStr`). * Brew + testgen downstream silently grounded against the wrong field, * leading to a runtime error that took a human to spot. * * This lint parses `.brewing/repo-knowledge/auto/backend-entities.md`, * walks every string-typed field of the spec, and for each * `lowercaseName.fieldName` pair where `lowercaseName` matches a known * entity, checks whether `fieldName` is in that entity's field set. * Misses are flagged as `"flagged"` (kept as-is — the spec text isn't * auto-repairable since we don't know what the author meant). * * Chained references like `user.timezone.label` are decomposed into * pairs (`user.timezone`, `timezone.label`); each pair is checked * independently. Relation traversal works because relation field * values are themselves listed in the entity catalog with the * other-entity name as their type. * * Exported for testing. */ export declare function parseEntityCatalog(md: string): Map>; export declare function validateEntityFieldReferences(spec: Spec, entityCatalogMd: string): SpecValidationFinding[]; /** * 0.19.x+ — check whether the mock files refine listed in * `components_to_reuse` actually render the spec's data fields. * * Refine derives `components_to_reuse` from spec prose mentions of * `src/components/...` paths (proposals-synth.ts:198). It doesn't * verify the mock at that path actually mentions the fields the * spec cares about. A reuse listing of the WRONG mock misleads * brew into lifting unrelated UI. * * Concrete repro (delgoosh story-005): * spec.invariants reference user.firstName / user.lastName / * user.email / userLocation.city / userLocation.country / etc. * refine's components_to_reuse listed mock/src/app/patient/profile/page.tsx * which actually renders therapy PREFERENCES (topics/approach/gender/belief) * — none of the spec's fields appear in that mock at all. * * Heuristic: extract the set of unique field names mentioned in the * spec's load-bearing sections (RHS of every dotted reference like * `user.firstName`). For each `components_to_reuse` entry that names * a real path, count how many of those field names appear in the * file body. If overlap is < 25% of the spec's field set AND the * file body is non-trivial (>500 chars — empty mocks aren't false * positives), flag the entry. * * Action is "flagged" — the spec text isn't auto-repairable; the * author needs to either drop the reuse listing or rebuild the * mock at that path. Surfaced in run logs alongside other findings. * * Exported for testing. */ export declare function validateComponentReuseShape(spec: Spec, mockReader: (path: string) => string | null): SpecValidationFinding[]; /** * 0.19.4-α+ (sc#151 finding 3) — flag every `routes.paths[].file` whose * destination path is ALREADY OCCUPIED by an existing file in the consumer * repo. Refine sometimes proposes a route at e.g. `/patient/chat` because * the spec uses it as the natural noun, but the consumer repo already * hosts a different feature at that path (AI chat vs peer chat in the * delgoosh dogfood). Brew would have to either silently overwrite the * live page or pick a different path on its own — neither is a clean * handoff. * * Action is "flagged" (not "repaired") — the resolution is upstream: * the spec author renames the route OR the existing file relocates * before the spec merges. * * `fileExists` is a reader so the function stays pure + testable. * Callers pass `(p) => existsSync(join(repoRoot, p))`. */ export declare function validateRouteCollisions(spec: Spec, fileExists: (path: string) => boolean): SpecValidationFinding[]; //# sourceMappingURL=spec-validate.d.ts.map