Skip to content

refactor(conformance): the judge is a codeupipe pipeline - #15

Merged
JoshuaWink merged 2 commits into
resolve-plain-logicfrom
judge-as-pipeline
Oct 13, 2026
Merged

JoshuaWink merged 2 commits into
resolve-plain-logicfrom
judge-as-pipeline

Conversation

@JoshuaWink

Copy link
Copy Markdown
Member

What

The judge of the conformance suite is now a codeupipe pipeline. It was eight plain functions in conformance/run.py.

This PR is on top of #14. Merge #14 first.

Why

The test tools were the last large part of the repository that was plain code, so the repository's own rule (CUP-I008) needed a comment on each of their functions. This is the first of them written the way the product is written: as primitives.

The pipeline (conformance/judging/)

Step What it does
LoadCasesFilter Reads the cases. Two cases with one id stop the run
NoTargetsNamedPredicate + DefaultTargetsFilter With no target named: each target that this machine can run
RunTargetsFilter Runs the cases on each target
JudgeResultsFilter Compares each result with what its case expects. The one place that decides pass or fail
SummarizeFilter The counts, the matrix and the exit code
FormatMatrixFilter The matrix as Markdown
WriteResultsTap Writes latest.json and latest.md

Two edges stay plain, each with its reason: ProcessLauncher (starts a runner) and NodeProbe (asks which Node the machine has).

run.py keeps its command line and the names that the tests and bench.py use (load_cases, run_target, judge, default_targets, TARGETS). Each one calls a step of the pipeline, so there is one judge and not two.

How it was checked against the old judge

A fault in the judge can make a broken runtime look correct. So the new judge ran beside the old one:

  • The printed report, latest.json and latest.md are the same byte for byte, on all 7 targets.
  • Both judges got the same 6550 results and gave the same verdict for each one. 2700 of those results were made wrong on purpose (a key removed, a value changed, an error in the place of an output, true in the place of 1), and both judges failed each of them with the same problems.

The old judge is not in this PR. It was used for this comparison only.

What it gains

  • 8 allow-plain comments are gone, and 2 are added for the edges. The pinned number in the repository self-check goes from 81 to 75.
  • Each step has tests that start no process (tests/conformance/test_judge_pipeline.py, 14 tests). Before, the judge was tested only through a full run of a target.

Checks

  • Python tests: 535 pass.
  • Conformance: 30 of 30 on each target.
  • Both linters report nothing, in strict mode.
  • Speed check: within its band. bench.py uses the same launcher and the same comparison as before.

Not in this change

  • The runner (conformance/runners/python/runner.py) and scorecard/ are still plain code with comments.

🤖 Generated with Claude Code

The judge was eight plain functions in run.py. It is now a pipeline in
conformance/judging: read the cases, choose the targets, run each
target, compare, count, format, and write the results. Each step is a
primitive in its own file and has tests that start no process.

run.py keeps its command line and the function names that the tests and
bench.py use. Each one calls a step of the pipeline, so there is one
judge.

The new judge was run beside the old one. Their reports are the same
byte for byte on all 7 targets, and they gave the same verdict for each
of 6550 results, 2700 of them wrong on purpose.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(conformance): the Python runner is codeupipe pipelines

The runner was 15 plain functions in runner.py. It is now two pipelines
in conformance/runners/python/case_runner: one plays a case on a target
and one times a scenario. They share the steps that read the target,
write the Predicates, build the pipeline and compile it. Each step is a
primitive in its own file with tests of its own. runner.py is the
command line.

The new runner was run beside the old one on each Python target, with
all 30 cases and 7 more that were made to fail. The reports are the
same byte for byte. In the timing mode the outputs and the refusals are
the same, and the times are the same within the noise of a run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(scorecard): use the steps of the new runner

The differential test tool used two functions of the old runner file.
It now uses the same steps that the runner uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@JoshuaWink
JoshuaWink added this pull request to stack #17 October 13, 2026 18:59
@JoshuaWink
JoshuaWink merged commit f13fd6b into beta Oct 13, 2026
9 of 10 checks passed
@JoshuaWink
JoshuaWink deleted the judge-as-pipeline branch October 13, 2026 19:02
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