Validators¶
The framework runs validators at two boundaries: against the architect's Squib before any ICP fires, and against the generated source after IntegrateModule.
Pre-ICP validators (run on the Squib)¶
Any of these firing triggers an architect retry with the violations appended to the prompt; a second failure aborts the run with an actionable error message.
| Validator | Catches |
|---|---|
ArchitectureSpec.validate() |
Every depends references a known class; every Module::Type is resolvable; no cycles. |
validate_cross_module_dependencies |
Every Module::Type reference exists in the target module's EXPORTS. |
validate_architecture_against_spec |
Every declared domain_conventions tag appears as an INVARIANTS line; every data_classification.field_ref exists in some Entity / ValueObject. |
validate_http_conventions |
HTTP headers typed as dict[str, str]; body as bytes/str; status codes as int. (See Author HTTP conventions.) |
validate_contract_fidelity |
Consumer entities carry producer's contract field names verbatim, with case-tolerant cross-language matching. |
Post-generation validators (run on the source)¶
Run after every ICP completes, after IntegrateModule writes the project files, and before eval_report.json is finalized.
| Validator | Catches |
|---|---|
DependencyRule |
Inner layers never import outer layers (Domain ↛ Infrastructure, etc.), and domain/application production source importing any third-party module/SDK — those pure layers may import only the language standard library + first-party code (test code exempt). |
DependencyInjectionRule |
An orchestrator (UseCase / Facade) that declares no fields while its module provides a port it must inject; the architect is re-asked to make the injected collaborator explicit. Surfaced as dependency_injection_violations. |
PythonGranularityRule + per-language equivalents |
One class per file, ≤3 methods/class, ≤2 args/method, ≤80 lines/file. |
PatternConformance |
Class structure matches its assigned pattern's required participants. |
SOLIDChecker |
Single Responsibility, Open/Closed, Liskov, Interface Segregation, Dependency Inversion. |
Violations are surfaced as counts in eval_report.json (e.g., architecture_violations, cross_module_dependency_violations, dependency_injection_violations, spec_conformance_violations).
Compile gate + test faithfulness¶
Before the generated test suite runs, two deterministic gates run with their own repair loops:
- Compile gate. Typed targets are compiled/typechecked first — TypeScript with
npx tsc --noEmit, Java withmvn test-compile; dynamically-typed targets (Python) have no compile step and skip the gate. On failure the offending source classes are regenerated, and test files that assumed wrong signatures are regenerated against the real (authoritative) source. Remaining failures are counted incompile_errors. - Test faithfulness. The framework projects a deterministic set of test obligations from the acceptance criteria + invariants and checks that generated tests actually discharge them — calling the method AND making the required assertion kind (raises / equals / field-holds / call-only). Obligations no test discharges are counted in
test_obligation_gaps, and a repair loop drives that toward zero. Validation invariants (e.g. "value must not be empty") get their construction-raises tests emitted deterministically rather than LLM-generated.
See also¶
- Squib grammar — what's being validated pre-ICP.
- Verify a run — how to read the violation counts in
eval_report.json.