Hmm. For now, based on the limited checks I was able to run on my side, I think it looks something like this:
Short answer
Yes, your summary of the separation is what I had in mind:
- the structured
ExecutionWitness is the canonical audit record;
- the renderer is a separate, non-agentic component;
- the training view is derived from the witness rather than being authored inside the solver;
- and
Accept / Reject / Defer applies to the evidence available for each layer, rather than forcing one binary verdict for the whole sample.
For the two questions:
- For dataset construction, my default would be a reason-coded, offline-first hybrid rather than sending every
Defer case directly to a stronger LLM or every case to humans.
- I do think the
autoresearch-MIL harness contains useful patterns, but I would borrow its ownership, logging, memory, and audit controls rather than replacing Agent-ProSAT’s existing inner research loop.
The key distinction for me is:
A stronger model is most useful when it can produce a new artifact that can be checked independently—not merely when it can express a stronger preference between rules that remain equally consistent with the same evidence.
So I would use the stronger LLM for bounded repair, candidate generation, structured conversion, or proposing a discriminating test. I would not treat “the stronger model chose rule B” as verification by itself.
My default routing policy
A practical initial policy could be:
| Observed state |
Default route |
| Parse or formatting failure |
Deterministic repair first, then bounded LLM repair |
| No candidate, but the family is already supported |
Generate additional candidates, then replay all demonstrations deterministically |
| No candidate because an operator or family is unsupported |
Solver/schema development queue |
| Multiple candidates, but all predict the same target answer |
The answer may be usable; keep the witness/rule ambiguous |
| Multiple candidates with different target answers |
Generate a distinguishing query or keep the case offline |
| A distinguishing query exists and a reliable answer source exists |
Ask the generator, oracle, or a human reviewer |
| A distinguishing query exists but no reliable answer source exists |
Keep the candidate set unresolved and replayable |
| Timeout or resource failure |
Bounded retry, then offline queue |
| Witness and renderer disagree |
Deterministic rerender; reject the rendered view if it still disagrees |
| Dataset target, computed answer, and witness replay disagree |
Audit queue rather than automatic promotion |
In other words:
deterministic checks
→ classify why the item was deferred
→ choose the cheapest route that can add checkable information
→ replay deterministically
→ accept only the layer actually supported by that evidence
This is close in spirit to learning to defer, where the useful question is not only whether the first system is uncertain, but whether the downstream expert is actually likely to handle that kind of case better.
First separate what is being accepted
I would probably avoid giving the entire sample one status. There are at least four separable objects:
answer_status
witness_status
renderer_status
training_view_status
For example:
answer_status = accepted
witness_status = ambiguous
renderer_status = not_applicable
training_view_status = answer_only
This matters because multiple rules may fit the demonstrations while still producing the same answer for the current target.
In that situation, the answer can be stable within the current candidate space even though the inferred rule is not unique. That does not prove that the answer is correct under every plausible latent rule, but it is a materially different state from a case where the candidates also disagree on the target answer.
Likewise:
- a correct final answer does not automatically validate the witness;
- a valid witness does not automatically validate every rendered explanation;
- and a faithful rendered explanation is not automatically safe as a training view if it was conditioned on the target answer.
So I would make the cascade operate at those boundaries rather than treating Accept as one undifferentiated label.
Minimal decision record
Before choosing or learning a router, I would record something approximately like:
{
"answer_status": "accepted|rejected|deferred",
"witness_status": "accepted|rejected|ambiguous|unsupported",
"renderer_status": "accepted|rejected|not_run",
"training_view_status": "full|answer_only|excluded",
"decision": "accept|reject|defer",
"defer_reason": "multiple_candidates_different_answers",
"candidate_count": 4,
"target_output_count": 2,
"escalation_target": "offline_oracle_queue",
"resolution_evidence": null
}
I would also retain, when available:
candidate_rule_ids
candidate_set_hash
hypothesis_space_version
target_output_set
failed_invariant
unsupported_operator_set
distinguishing_input
oracle_available
dataset_revision
source_row_id
solver_commit
witness_schema_version
renderer_version
verifier_version
escalation_model_version
escalation_prompt_version
parent_run_id
One field that may be especially useful is the difference between:
resolved_with_new_verifiable_evidence
resolved_by_unverified_preference
Those should not be counted as the same kind of “resolved.”
A small pinned probe
I ran two small CPU-only probes against the public binary/equation-transform data and the public solver snapshot at commit 84c548c. I would treat these only as instrumentation signals about that finite hypothesis space—not as a claim that every ambiguous item has the same underlying cause.
The two observations that changed my view most were:
- Multiple demonstration-consistent candidates were common in the current compact candidate space.
- A target answer could be correct even when the selected proxy transformation disagreed with the trace’s claimed transformation on other inputs.
That makes me lean toward inspecting and recording the candidate set before routing the case.
It also makes me think target-answer correctness and witness validity should be separate promotion conditions.
Probe setup, results, and limitations
Candidate-ambiguity probe
For the current binary and positional equation-transform candidate spaces, I enumerated the candidates that matched all available demonstrations instead of stopping at the first match.
The public solve_binary implementation currently selects the first per-bit function that matches all demonstrations and then breaks; the positional equation-transform path similarly selects the first matching input position. That behavior can be seen in the pinned prosat.py.
The probe covered:
| Measurement |
Binary |
Equation transform |
| Rows examined |
1,557 |
709 |
| Representable in the tested candidate space |
1,255 |
153 |
| Multiple candidates among representable rows |
1,233 |
37 |
| Multiple candidates, same target output |
204 |
3 |
| Multiple candidates, different target outputs |
1,029 |
34 |
| First-versus-reversed-order output changed |
877 |
34 |
| Current first match gave the target answer |
806 |
104 |
| Ground-truth answer existed in candidate-output set |
1,191 |
136 |
The “first versus reversed order” result is only a simple order-sensitivity proxy, not an exhaustive study of all candidate orderings.
A particularly relevant result was that, for binary rows where the first candidate was wrong, the correct target answer was often still produced by another demonstration-consistent candidate. For the ambiguous positional equation-transform rows, the first mapping was never correct in that probe, while the correct answer was present among the candidate outputs in most of those rows.
That suggests at least two distinct conditions:
candidate-generation failure
candidate-selection ambiguity
They should probably not receive the same Defer reason.
There were also rows with multiple candidates but a single target output. This gives an empirical reason to distinguish:
answer accepted
witness ambiguous
However, a small number of those target-invariant cases were still wrong relative to the dataset target, so invariance within the current candidate space is useful evidence, but not a standalone correctness proof.
Likewise, some rows had a unique candidate within the tested space but still produced the wrong target answer. Therefore:
candidate_count == 1
is not sufficient on its own. “Unique within this hypothesis space” and “correct latent rule” are different claims.
Trace-replay probe
For the binary subset, I also parsed the rule expression recorded after Identified: in the public traces and replayed it independently.
A lightweight parser handled 1,400 of 1,557 rows. For all 1,400 parsed rows, the replayed rule reproduced:
- all listed demonstrations; and
- the stored
computed_answer.
It reproduced the dataset target in 1,383 of those 1,400 rows.
I then compared the current first-match solver’s transformation with the replayed claimed transformation over all 256 possible 8-bit inputs where that comparison was meaningful.
Among cases where the current solver got the target answer right and the two transformations were comparable:
- 366 matched the claimed transformation on all 256 inputs;
- 303 got the target right but diverged somewhere else in the input space.
So in that comparison set, target correctness did not reliably imply transformation equivalence.
Also, among 913 rows where the claimed transformation was expressible by the current compact per-bit library, the first-match solver selected the globally equivalent transformation in 366 cases.
That suggests:
expressible by the library
≠
selected correctly from the demonstrations
The operation-family differences were also informative. Simpler combinations involving shifts and bitwise OR/XOR were often representable, while families involving constructs such as CHOICE, MAJORITY, or more complex composed transformations were generally outside the compact per-bit candidate space.
This supports splitting at least:
selection ambiguity
unsupported hypothesis family
unsupported witness schema
rather than sending all three to the same escalation route.
Why I would not overinterpret this
These probes were run against:
- a pinned public solver snapshot;
- a pinned public dataset revision;
- a deliberately finite candidate library;
- primarily the binary subset;
- and the rule stated in the generated trace as the replay reference.
Therefore they do not establish:
- the intrinsic ambiguity rate of the original puzzle generator;
- that every proxy divergence is a solver defect;
- that the stated trace rule is necessarily the intended latent rule;
- that full truth-table equivalence should be required for every task family;
- or that one routing arm is empirically superior to another.
For an answer-only task, observational equivalence on the relevant input may be enough. The full 256-input comparison is instead useful when the object being promoted is meant to represent a reusable transformation witness.
Where a stronger LLM helps—and where it does not
My default rule would be:
Use a stronger LLM when it can produce something that can subsequently be checked, not merely when it can provide a more confident tie-break.
Good escalation candidates include:
- repairing malformed structured output;
- converting an unsupported expression into a candidate AST;
- generating additional candidate rules;
- proposing a distinguishing input;
- identifying a specific failed invariant;
- making a bounded local repair;
- or summarizing candidate differences for a human reviewer.
Afterward, the result should return to the deterministic side:
LLM-produced candidate or repair
→ canonical structured form
→ replay demonstrations
→ run invariants/property checks
→ update the status only for the layer supported
A useful nearby example is the OpenR1 Update #2: rules-based verification was used first, and an LLM judge was explored for a subset of rejected answers whose references or formatting were difficult to validate automatically.
That is a good precedent for selective recovery of difficult-to-parse cases. I would not take it as evidence that an LLM judge can identify the intended latent rule when several rules remain exactly consistent with the same demonstrations.
The same OpenR1 write-up also reports that reward-model top-1 selection among correct generations did not improve over selecting a random correct generation in that ablation. The task is different, but it is another reason not to assume that a more elaborate ranker automatically identifies a better reasoning trace.
For true program ambiguity, the closer neighboring idea may be active program synthesis: preserve the consistent candidate set, find an input that is likely to separate those candidates, and ask for that input’s output. The Significant Inputs for Program Synthesis paper is a useful example of this pattern.
The important limitation is that a distinguishing input is only useful if there is also a reliable source for its answer:
distinguishing input exists
+ generator/oracle/human can answer
→ ambiguity can potentially be reduced
distinguishing input exists
+ no reliable answer source
→ keep the candidate set unresolved
A stronger LLM can suggest the question, but unless its answer is independently verifiable, using the same LLM as both question generator and oracle would not add much separation.
A more explicit Defer decision tree
Start
│
├─ Generate/collect candidate witnesses
│
├─ No candidate
│ │
│ ├─ Parse or formatting failure
│ │ ├─ Deterministic repair
│ │ ├─ Bounded LLM repair
│ │ └─ Replay all demonstrations
│ │
│ ├─ Known schema, candidate generator incomplete
│ │ ├─ Generate additional candidate
│ │ └─ Replay deterministically
│ │
│ ├─ Unsupported operator/family
│ │ └─ Solver/schema development queue
│ │
│ └─ Timeout/resource failure
│ └─ Bounded retry, then offline queue
│
├─ One candidate
│ │
│ ├─ Replay fails
│ │ └─ Reject candidate
│ │
│ ├─ Applicable property checks fail
│ │ └─ Defer or reject witness
│ │
│ └─ Checks pass
│ └─ Accept at the supported evidence level
│
└─ Multiple candidates
│
├─ All candidates give the same target output
│ ├─ Answer may be accepted conditionally
│ ├─ Witness remains ambiguous
│ └─ Use answer-only training view if appropriate
│
└─ Candidate target outputs differ
│
├─ Distinguishing query can be generated
│ │
│ ├─ Reliable oracle/generator exists
│ │ └─ Query it and replay candidates
│ │
│ ├─ Human can answer naturally
│ │ └─ Clustered human review
│ │
│ └─ No reliable answer source
│ │ └─ Offline unresolved queue
│ │
│ └─ No useful distinguishing query
│ └─ Solver-development backlog
The decision tree does not need to be implemented all at once. The immediate high-information step is simply to retain the candidate count, target-output set, and defer reason.
What I would borrow from autoresearch-MIL
I would say yes, selectively.
The current Agent-ProSAT repository already contains the main inner loop:
agent.py edits the solver;
assess.py evaluates the result;
- the run is committed or reverted;
- and recent accepted/rejected trajectory information is returned to the next iteration.
So I do not think another harness is needed to create the basic research loop.
What looks useful from autoresearch-MIL is its control-plane discipline:
| Existing Agent-ProSAT mechanism |
MIL pattern worth borrowing |
Mutable prosat.py |
Explicit user-owned versus agent-owned files |
assess.py evaluation |
Evaluator and promotion policy outside the editable surface |
| Commit/revert |
Hypothesis–commit–metrics linkage |
runs.tsv trajectory |
Append-only per-run record |
| Output/session files |
Unique run IDs and raw logs |
| Accepted/rejected status |
Persist crash, discard, reject, and defer artifacts |
| Per-family metrics |
Branch-pinned research memory |
| Twin-blind check |
Immutable evaluation and lineage metadata |
The MIL README and program.md explicitly separate user-owned read-only files from agent-editable files, keep one append-only result row and raw log per run, and preserve crash/discard states.
That seems directly reusable here.
I would probably define something like:
User-owned or immutable during an experiment
evaluation code
hidden grouped-holdout registry
witness schema contract
promotion thresholds
renderer conformance tests
dataset revision policy
Agent-owned
prosat.py
candidate generators
family-specific solver modules
solver parameters
possibly renderer code, but under a separate test boundary
Per-run artifacts
run_id
hypothesis
parent_commit
result_commit
dataset_revision
solver_version
witness_schema_version
candidate_set_hash
defer_reason_counts
target-only accuracy
witness replay/property results
family metrics
crash/reject/defer status
raw log path
artifact hashes
I would also keep unsuccessful knowledge in memory, not only the best score:
failed hypotheses
known shortcut families
unsupported operators
false resolutions
defer clusters
canary failures
That would make autoresearch-MIL an audit and research-memory layer around Agent-ProSAT rather than a replacement for its solver-improvement loop.
Why I would avoid reducing promotion to one scalar too early
The MIL experiment loop is built around a clear primary metric for its training task.
Agent-ProSAT has several qualitatively different objectives:
- target-answer correctness;
- coverage;
- target isolation;
- witness replayability;
- candidate ambiguity;
- family-level non-regression;
- renderer fidelity;
- training-view safety;
- runtime and trace cost;
- and escalation cost.
I would therefore order the decision approximately as:
integrity gates
→ protected-family non-regression
→ answer coverage/correctness
→ witness coverage and ambiguity resolution
→ renderer/training-view checks
→ runtime, token, and escalation cost
A single combined score can be added later for ranking runs, but I would retain the components and keep some of them as hard gates.
Otherwise, an increase in coverage could hide:
- a regression in one family;
- an increase in unsupported proxy rules;
- an increase in false ambiguity resolutions;
- or target-correct traces that are not reusable witnesses.
Two guardrails I would add early
1. Extend the blind check to the witness/training view
The pinned public assess.py makes the twin-blind computed-answer comparison a hard gate.
The separate tests/verify_blind.py also counts exact reasoning matches between real-target and dummy-target runs.
Once the trace becomes training data, I would consider promoting the trace-side check as well:
real target vs dummy target
→ computed answer invariant
→ canonical witness invariant or semantically equivalent
→ rendered training view invariant
For structured JSON, canonical event equality or semantic replay equality may be more useful than raw string equality.
This is another benefit of the witness/renderer split: the canonical witness can be compared semantically, while harmless wording variation in a renderer does not have to invalidate the solver.
The broader idea also connects naturally to work on execution-grounded supervision, where executable traces can be checked separately from the natural-language rationale, such as Code Execution as Grounded Supervision for LLM Reasoning.
2. Separate development feedback from promotion evaluation
Because the agent receives prior run metrics and accepted/rejected feedback, it is adaptively optimizing against the assessment surface.
That is the intended loop, but it also means I would separate:
visible development set
hidden grouped promotion set
frozen final audit set
The visible development set can return detailed family-level failures.
The hidden promotion set can be grouped by puzzle family, generator lineage, or transformation family and return a more limited result.
The frozen audit set can be reserved for milestones.
This is not specific evidence that the current solver has overfit its evaluation data. It is just a general guardrail for any iterative agent that repeatedly receives evaluation feedback. Repeated adaptive reuse of a holdout can itself lead to holdout overfitting; Generalization in Adaptive Data Analysis and Holdout Reuse is the classic reference.
Metrics I would watch
At minimum:
accepted-answer correctness
answer coverage
accepted-witness correctness/replay rate
witness coverage
defer rate by reason
verified resolution rate
false resolution rate
cost per verified resolution
family non-regression
Additional useful diagnostics could include:
candidate multiplicity rate
target-output disagreement rate
answer-stable/witness-ambiguous rate
unsupported-family rate
parser-recovery rate
LLM-escalation rate
human minutes
replayability
target/computed/witness agreement
renderer fidelity
solver runtime
trace tokens
I would pay particular attention to false resolution:
a case that was genuinely unresolved under the available evidence, but was converted into an apparently confident single witness without new verifiable evidence.
Reducing the raw number of deferred cases is not necessarily progress if false resolution increases.
This is similar to the risk/coverage distinction in selective prediction: abstaining less is only useful when the accepted set remains reliable. SelectiveNet is a useful reference for that general framing, although the downstream routing problem here is broader.
A small routing pilot before learning a router
I would start with explicit reason-based rules rather than immediately training a learned router.
A small stratified pilot could compare:
A. deterministic processing only
B. deterministic → stronger LLM with structured failure evidence
C. offline replay after solver/schema updates
D. clustered oracle/human review
The stronger-LLM arm should receive structured context such as:
defer_reason
candidate_set
target_output_set
failed_invariant
counterexample
unsupported_operator_set
rather than only receiving the original puzzle and “try again.”
Measure:
verified resolution rate
false resolution rate
answer coverage
witness coverage
cost per verified resolution
human minutes
latency
replayability
family-level regression
Once enough outcome data exist, those logs could support a learned routing policy. Before that, a learned router would mostly be encoding assumptions without much direct evidence about which expert resolves which failure family.
Minimal lineage
I do not think this requires a large tracking platform initially. A checked-in JSON or YAML manifest plus append-only event records could be enough.
For example:
dataset_revision
source_row_id
generator_commit
solver_commit
witness_schema_version
renderer_version
verifier_version
candidate_set_hash
decision
defer_reason
escalation_target
escalation_model_and_prompt_version
final_output_hash
parent_run_id
I would keep three things separate:
append-only audit events
current materialized training view
raw unresolved/deferred queue
That way:
- the audit record is not rewritten when policy changes;
- the training view can be regenerated;
- and deferred items can be replayed after a solver or schema update.
My suggested implementation order
If I were sequencing it, I would probably do:
- Emit canonical structured witnesses.
- Separate answer, witness, renderer, and training-view statuses.
- Record candidate sets and target-output sets where enumeration is feasible.
- Add reason-coded
Accept / Reject / Defer.
- Use bounded escalation only when the route can add checkable evidence.
- Keep unresolved cases replayable offline.
- Borrow MIL’s ownership, run logging, failure persistence, and lineage patterns.
- Add witness-side target-isolation and hidden promotion checks.
- Compare routing arms on a small stratified deferred set.
- Learn or tune routing only after outcome logs exist.
So, to answer the original either/or directly:
For the dataset-generation phase, I would queue unresolved ambiguity offline by default, while dynamically escalating only the repairable or candidate-generating cases where the stronger model can produce something that the deterministic harness can verify.
And for the second question:
Yes, I think the earlier MIL harness is relevant—but mainly as a source of governance, append-only experiment records, failure memory, and ownership boundaries around Agent-ProSAT’s existing loop.
That seems like the lowest-cost route that preserves the audit/training-view separation while still letting the system improve iteratively.