Skip to content

[DRAFT] Run conformance tests as one whole-suite invocation per module - #253

Draft
pedjaradenkovic wants to merge 7 commits into
feature/improve-conformance-testingfrom
feature/conformance-single-run-suite
Draft

[DRAFT] Run conformance tests as one whole-suite invocation per module#253
pedjaradenkovic wants to merge 7 commits into
feature/improve-conformance-testingfrom
feature/conformance-single-run-suite

Conversation

@pedjaradenkovic

Copy link
Copy Markdown
Contributor

Summary

Iteration 2 of the conformance-testing improvement plan (see CONFORMANCE_TESTING_IMPROVEMENT_PLAN.md on this branch): conformance tests execute as one script invocation per module instead of one per functionality, with shared setup files allowed at the module suite root. Per-FRID subfolders and the test-script contract ("run all tests under $2") are preserved.

Stacked on #252 (Iteration 1); pairs with Codeplain-ai/plain2code_rest_api#123 (backend). Deployment order: backend first (its changes are gated by request flags/fields, so old clients are unaffected).

Changes

  • Loop-capable runners (test_scripts/run_conformance_tests_{golang,cypress}.{sh,ps1}): handle $2 being a folder of suites — degenerate single-suite case preserves today's behavior byte-for-byte; loop case runs each non-hidden suite subfolder with === conformance suite: <name> === headers, reports all failures, exits with the first failure's code. Cypress's npm install/build/app-start now runs once per invocation instead of once per suite.
  • Whole-suite execution: RunConformanceTests passes the module suite folder (own module) or the required module's copied suite root. The current-FRID run covers all prior FRIDs, so the regression walk collapses to one run per required module (plus an own-suite re-run when code changed during fixing). ~100 lines of FRID-walk machinery removed.
  • Failure attribution (render_machine/failure_attribution.py): failed runs are attributed to FRIDs by matching suite folder names against the output; the running context is pointed at the earliest implicated FRID, so the existing fix loop, memory keying, and conflict detection work unchanged. Failure evidence sent to the fix flow is scoped to that FRID (other implicated FRIDs appear as a summary note only, preserving the multi-FRID diagnostic signal). A conservative migration guard fails fast with a regeneration hint on layout-level failures (pre-flip projects, non-recursive custom scripts).
  • Shared setup + two-tier guard: render output paths are module-root-relative (tests in the FRID's subfolder, shared helpers allowed at the root); responses are validated before storing — files in other functionalities' subfolders are rejected (one retry, then error), existing shared root files may only be extended by inserting lines (difflib opcode check).
  • Summarization step dropped: the per-FRID summarize_finished_conformance_tests LLM call is removed — its only consumer was the plan-stage dedup section, which now receives the actual test files (A/B renders showed identical dedup quality). Saves one LLM call per functionality. The folder_name map in conformance_tests.json stays (attribution and fix routing depend on it).

Testing

  • 322 unit tests green (24 new across attribution, folder resolution, and the two-tier guard) + black/isort/flake8/mypy.
  • Runner scripts verified across degenerate/multi-suite/hidden-folder/empty/missing layouts (golang with real Go, cypress with stubbed npm/npx; .ps1 variants by review).
  • Five e2e renders against a local backend: side-by-side per-FRID vs whole-module verdict agreement; happy path (2 invocations for a 2-FRID render, previously 3 and growing quadratically); a forced cross-FRID conflict correctly attributed to the earlier FRID, fixed-scoped, classified as conflicting requirements, and reported; module-root layout and summaries A/B on a 3-FRID project.

Degenerate case (root conformance_tests.go / cypress.config.*) preserves
today's single-suite behavior byte-for-byte. Otherwise the runner iterates
non-hidden subfolders that look like suites, runs each with an
'=== conformance suite: <name> ===' header, keeps going past failures so the
full failure set is reported, and exits with the first failure's code
(exit 1 when no suites are discovered). Preparation work for whole-module
conformance execution; the renderer still passes per-FRID folders, so
behavior is unchanged.
The conformance script now receives the module's suite folder (own module)
or the required module's copied suite root instead of a per-FRID subfolder.
The current-FRID phase's single run covers every prior FRID of the module,
so the regression phase reduces to one run per required module (plus a
re-run of the own module's suite when code changed while fixing).

On failure, the run output is attributed to the implicated functionalities
by matching suite folder names; the running context is pointed at the
earliest implicated FRID so the existing fix loop, memory keying, and
conflict detection work unchanged, and the failure evidence sent to the
fix flow is scoped to that FRID (other implicated FRIDs appear only as a
summary note). Layout-level failures (suites that cannot be discovered
together, e.g. from projects rendered before whole-suite execution) fail
fast with a regeneration hint instead of entering the fix loop.
Deletes the per-FRID regression iteration (get_first/next running-context
walk, _get_next_test_to_run, _has_reached_implementation_frid,
_should_run_current_frid_tests) now that regression runs one whole suite
per module.
…er guard

The client now requests module-root-relative output paths (tests in the
functionality's subfolder, shared setup files allowed at the suite root)
and stores render responses relative to the module's conformance tests
folder. Existing-tests context sent to the API now includes shared root
files. A two-tier guard validates every response before storing: files in
other functionalities' subfolders (or required-module copies) and changes
to the definition file are rejected, and existing shared root files may
only be extended by inserting lines (difflib opcode check). One retry on
violation, then the render fails with a clear error.
The summaries' only consumer was the plan-stage dedup section of the
conformance test render prompt, which since the previous-files change
receives the actual test files - a lossy derivative adds nothing (verified
by A/B renders: identical dedup quality without summaries). Removes the
SUMMARY postprocessing state, the SummarizeConformanceTests action, and
the API client method, saving one LLM call per functionality. The
folder_name/functional_requirement entries in conformance_tests.json stay
- failure attribution and fix routing depend on them.
@pedjaradenkovic pedjaradenkovic changed the title Run conformance tests as one whole-suite invocation per module [DRAFT] Run conformance tests as one whole-suite invocation per module Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant