8.8 KiB
Change requests and final output v1
Historical v1 contract. New contexts use Differentiated handoff v2: confirmed causes always receive coding and human-dev documents (including explicit no-assignment outcomes). Missing remediation data no longer fails the analysis. Persisted v1 calls retain their original prompts; closed packages retain their historical outcomes. Pending v1 responses receive the new delivery documents.
This milestone implements architecture phases 4C and 4D. A confirmed diagnosis is
translated into a bounded coding request and validated as a portable output case.
The program does not implement the change, execute SQL, deploy, build or steer a lab.
docs/architecture.md remains authoritative and unchanged.
from viano_bug_analysis.analysis import (
ChangeRequestBuilder, ChangeRequestConfig, ChangeRequestLimits, OutputValidator,
)
builder = ChangeRequestBuilder(store, gateway,
ChangeRequestConfig.load("config/change-request.local.toml"), router=router)
result = await builder.build(case_id, package_id)
if result.status in {"COMPLETED", "INCONCLUSIVE"}:
output = await OutputValidator(store, gateway, router=router).publish(case_id, package_id)
Coding contract
Input must have an accepted current-revision final diagnosis. Missing earlier phases are rejected without invoking their models. The builder replays/verifies the diagnosis, investigation, budget, evidence and raw-input freshness before request generation and again before publication. An inconclusive diagnosis returns INCONCLUSIVE without calling a model or creating a coding request.
The new change_request_v1 prompt supplies the canonical case, accepted
interpretation, exact diagnosis, current-revision evidence, hashed local source
and database references, immutable bugfix policy and frozen retry policy.
All report, source, feedback and previous model text are untrusted data.
The model proposes only status, problem_summary, affected_scope, required_change, implementation_intent, implementation_guidance, constraints, preserve, forbidden_changes, do_not_fix_by, validation_requirements, missing_information and reason. Each affected scope entry has a source/database kind, declared safe source_ref and evidence IDs; the findings must actually reference that local artifact. A ready request requires scope related to stored root-cause evidence, nonempty validation requirements and no missing information. Unknown paths, IDs, duplicated scopes, incorrect roles and model policy/task injections are rejected as a whole. Partial/empty results do not establish an available API.
The controller supplies task.type=bugfix, case/package identity, a case-scoped
CR-NNNN ID, analysis revision, diagnosis pointer/hash, unchanged root cause,
unchanged observed/expected interpretation statements, prompt/context/model-call
bindings and selected project_context_refs with source hashes/sizes.
change-request-v1 wraps the accepted model-specific fields under request;
controller-owned fields are top-level. The fixed policy is recreated by code,
verified on replay and explicitly has precedence over case-specific guidance:
- Smallest practically sufficient fix; no new features or unnecessary refactoring.
- Preserve behavior outside the diagnosed defect and avoid unrelated file/row changes.
- Do not invent APIs, schemas or symbols; use only verified local context.
- Report missing implementation context instead of guessing.
- No deployment, restarts or production access.
Prose guidance still requires semantic review; reference/schema validation cannot prove the causal diagnosis or detect every invented identifier in natural language. Offline tests verify orchestration and contracts, not real-model bugfix quality.
Waiting, rejection and review
Each build dispatch performs at most one eligible provider round, through the existing durable gateway/failover logic. There is no sleeping worker or new investigation debit. Unreachable/configuration-failed providers return retry metadata or BLOCKED and preserve budgets. After explicit lifecycle resume, a stable retry_id may reopen an exhausted/configuration-failed transport; it cannot bypass normal backoff or reset invalid reply counts.
max_invalid_responses defaults to 3 and is frozen per analysis revision. Omitted
configuration on resume adopts the stored policy; explicit changes are rejected.
Invalid replies append audit errors and return REJECTED with no partial request.
After the limit, a deterministic review decision records validation exhaustion.
A valid insufficient_context response also creates a failure_report.json and
moves to FAILED_TO_ANALYZE/review. The confirmed diagnosis remains preserved:
a cause can be known while its verified implementation context is insufficient.
No change_request artifact is created in either review branch.
Context, decisions and errors live under analysis/change-requests/NNNN/. A ready request and deterministic human summary live under handoffs/coding/CR-NNNN/change_request.json and .md. Manifest pointers are change_request_context, change_request, change_request_summary and failure_report. The diagnosis replay accepts only a checkpoint-declared later CR failure report; it still verifies the original diagnosis. All review data is checked against the frozen decision and original hypothesis/question state.
Final validation and local delivery
OutputValidator.validate is read-only: absent diagnosis/CR completion checkpoints are rejected, so it cannot initiate missing LLM phases. Package bytes and semantic budgets stay unchanged; existing replay mechanisms may repair reconstructible service indices/runtime metadata. It checks package integrity, checkpoint history, raw-input freshness, current revision, evidence provenance, exact diagnosis/request/model bindings, fixed policy, deterministic summaries, local context hashes and manifest pointers. Review cases require FAILED_TO_ANALYZE, review routing, a valid failure report and no coding request.
finalize validates first, appends analysis/output/NNNN/validation.json and advances a successful case to OUTPUT_READY/outbox. The validation report binds identity, revision, source generation and diagnosis/request hashes. Ready cases without a matching validation checkpoint/report are rejected. Repeated finalization validates the same completed generation, without another model call or budget adjustment.
publish revalidates and atomically copies the immutable ZIP snapshot into local outbox/ or review/. Identity hashes, revision and generation form a bounded service-owned filename; the filename remains functionally irrelevant to readers. Copy publication flushes/fsyncs a temporary file, uses a same-directory hard link that cannot overwrite an existing destination, and removes the temporary name. The destination filesystem must support hard links; unsupported filesystems fail with a controlled storage error rather than a non-atomic fallback. Existing identical bytes are an idempotent success; differing bytes or symlinks are rejected. A crash before export can retry the already-finalized generation. A crash after publication reuses the identical file. Export does not increment package generation because it copies the exact validated bytes rather than creating another package.
Local outbox availability is not acknowledgment by a coding agent. publish does not set HANDED_OFF, send remote messages or count a coding handoff. A future recipient acknowledgment/worker integration owns that transition. A case already marked HANDED_OFF is validated but not exported again. Review exports retain their original failure checkpoint/report; successful outputs additionally carry the final validation artifact.
Reopened revisions preserve all old CRs/reports and reset current output pointers. Each new revision receives its own CR ID and validation report. Unknown input files and all immutable older artifacts remain unchanged. The CaseAssembler excludes only checkpoint-declared generated output paths, never arbitrary unknown files.
ChangeRequestLimits defaults to 2 MiB context and 4 MiB JSON/summary artifacts. These are adjustable safety defaults, not permanent package-format boundaries; align them with gateway request and package limits. Oversized input is rejected, never silently truncated. No secrets are deliberately introduced into output.
Tests cover confirmed and review outputs, fixed policy/provenance, full byte preservation, budgets, malformed replies, exhaustion, provider block/resume, crash recovery, portable replay, conflicting export files, missing validation and reopened revisions. The real BUG-20 archive pair reaches validated local review with simulated model replies and no seeded known solution.
Next milestone: continuous worker/scheduler with service-wide structured logs, metrics, heartbeat and status diagnostics. Web feedback and bot/client adapters remain future integrations.