Bounded local repair execution
The repair executor turns one routed dogfood failure into a retained candidate patch. It uses the configured Responses provider once, after existing Go tests reproduce a failure in the pinned Praetor source. This stage supports reviewed owned Praetor engine source. Public repositories remain dogfood inputs; their arbitrary application tests are not dispatched by this executor.
praetorctl dogfood repairs status --config /absolute/execution.json --report
/absolute/report.json reads admission state. repairs run consumes one eligible
case. Both strictly validate the retained suite report and recompute the route
from the explicitly configured routing policy. They never execute saved plan
instructions or follow transcript paths in the report.
The private execution JSON has these required fields:
| Field | Contract |
|---|---|
version |
1 |
source_root, source_sha |
Clean absolute source checkout and full 40-character commit SHA |
state_dir |
Private absolute state directory; parent exists |
allowed_files |
1–8 explicit existing non-test .go paths under internal/ or cmd/ |
test_packages |
1–4 exact ./internal/<name> or ./cmd/<name> packages |
timeout_seconds |
30–300 seconds for the complete execution |
max_patch_bytes |
1,024–262,144 bytes |
repair_policy |
Existing routing policy with declared token estimates and cost ceiling |
provider |
Exact endpoint, model, pinned credential helper, input and output bounds |
dogfood repairs resolves two independent rows from the text register.
The task row becomes register, register_source and optional max_output_tokens; the
prompt surface becomes prompt_register and prompt_register_source. Each planned job and
execution report preserve those exact values and register_manifest_sha256, which binds
them to the exact manifest bytes. The prompt row always names
surfaces.prompts; the task source names either tasks.<label> or surfaces.agent. A job
budget lowers the provider's max_output_tokens for that request and never raises it above
the configured value. Both resolutions are mandatory at every runtime policy boundary.
An empty, partial or contradictory tuple is rejected before planning, scheduling or
provider dispatch. The planning CLI resolves the tuple from the repository manifest. The
scheduler replaces any caller tuple from its captured manifest snapshot; the executor
compares every retained tuple field and digest with the manifest blob in source_sha, not
the mutable checkout, before admission. Both boundaries reject manifest task rows outside
the captured routing vocabulary. Ignored caller tuple fields are removed before a schedule
fingerprint is computed, so they cannot reset its failure circuit.
The planner validates its generated job instructions before it
marks a job reviewable; a failed generated brief remains in a blocked plan with its failure
record. The executor validates that task brief again, then validates the static prompt
scaffold with the independent prompts surface row before reading source evidence.
It validates the separate Responses API instructions with the same prompt row before
provider dispatch and validates proposal.summary with the task row before any candidate
source mutation. Internal text must pass the Caveman brief, message or return contract as
appropriate. When the task row resolves to internal, the scaffold carries a summary:
line that names the return fields in the order caveman.SchemaFields reports them, so
the provider is told the shape the summary check enforces
(TestRepairPromptStatesTheSummaryReturnShape in internal/repairrun/register_test.go). Runtime checks reject source-document escape constructs and expose prose
hidden in quotes or inline code; social and docs produce an explicit not_applicable
record. The execution
report preserves the four records as job_instructions_validation, prompt_validation,
request_instructions_validation and summary_validation. Untrusted source and test
payloads are appended only after both owned prompt segments pass and are never linted as
instructions.
Each validation record carries the checker contract version and SHA-256 of the exact bytes
it checked. Terminal-state readback reconstructs the deterministic job, prompt and request
text, rereads proposal.json for the summary, reruns the current checker, and requires the
complete retained record to match. A changed input, stale checker version, forged digest or
missing stage record is invalid and is not treated as consumed success. Early failures may
retain only the contiguous validation prefix reached before they stopped; verified outcomes
require all four records.
provider fields are base_url, token_command, token_command_sha256, model,
max_output_tokens, and max_input_bytes. The routed model must equal the
configured provider model; there is no fallback. Configured cost is an estimate,
not a billing reservation. Unknown measured cost remains absent. The returned
model is server-reported identity.
The endpoint is configurable: a canonical HTTPS DNS/IP URL of at most 4096 bytes,
with an optional port 1–65535 and clean literal path. Credentials, query strings,
fragments, escapes and trailing slashes are rejected. The transport appends
/responses; redirects and environment proxies remain disabled. Selecting a URL
does not establish ownership or authorization. Helper digest and credential
handling checks still apply. Connection profiles can
generate this provider subsection alongside the shared MCP registry.
Admission uses a stable key derived from the source commit, exact configuration
and routing input hashes, and case kind, ID and input hash. Report timestamps,
error messages and attempt paths do not create new attempts. A crash after
started.json consumes that key. Status reports it as interrupted; execution
continues only for a different unconsumed case or changed source/policy. A lock
prevents overlapping execution. At most 32 attempts are retained per state root;
there is no automatic evidence deletion.
Source extraction reads the immutable Git tree and individual blobs. Dirty files, untracked files, mutable export attributes, shared Git metadata, original transcripts and global CLI configuration are excluded. Trees are limited to 20,000 entries and 16 MiB, with regular files only. Only the allowlisted source contents and isolated failed-test identities enter the model prompt. Raw retained failure excerpts are never sent.
Verification runs fixed go test -json arguments with candidate source mounted
read-only in bubblewrap. The sandbox has no network, host home or credentials;
it can read the installed toolchain and workstation Go dependency cache. That
cache visibility is why this rollout is restricted to reviewed owned source.
Temporary writes use a 1 GiB private tmpfs. A user systemd scope limits the whole
process tree to 4 GiB memory, zero swap, 128 tasks and 200% CPU; per-process limits
also bound address space, CPU time, output file size and open descriptors. Missing
namespaces, user scopes or dependencies fail before provider dispatch.
A successful candidate must execute every completed baseline test identity and pass every previously non-skipped test. Additional tests may complete after an early failure is fixed. Exit status zero with missing tests is rejected. Every changed path and file mode is checked against the baseline; tests, instructions and configuration cannot be edited. This first stage also preserves imports, declarations, function signatures and call expressions, rejects new initialization hooks, and rejects added test control framing. It supports local expression and control-flow fixes; broader changes are rejected for review. Test events alone are not a tamper-proof proof of arbitrary Go semantics. Logs, exact patch, source manifest, proposal, usage and result remain in the private attempt directory.
not_reproduced means baseline tests passed and no provider was called.
scoped_test_verified means the retained candidate passed these unchanged tests.
It does not claim the original private corpus was fixed. Failed, timed-out,
rejected and interrupted attempts remain visible and consumed. Execution does
not modify the source checkout, install the candidate, publish, merge or promote
it. The separate local timer may select the next retained failure for execution.