Skip to content

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 with mvn 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 in compile_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