6.2 KiB
Asynchronous test handoff v1
This contract supports externally performed human and automated tests. The human
HTTP adapter and dedicated web page are now documented in
Web console. Automated execution,
notifications, bot steering and client automation are not provided by that page.
docs/architecture.md remains unchanged and authoritative: VianoBugAnalysis
does not steer labs. It requests observations through a future external adapter.
Durable contract
AsyncTestCoordinator is imported from viano_bug_analysis.lifecycle.async_tests.
It is a trusted controller service, not a callable operation exposed directly to
an LLM. The investigation controller validates requests before calling it. The
web adapter authenticates/authorizes users and confirms feedback before calling
confirm_feedback; a payload claiming confirmed = true is not authentication.
User-supplied observations are untrusted data, not executable instructions.
Two bundled JSON schemas define the case-local exchange:
async-test-request-v1: stable request/action/hypothesis IDs, case/package IDs, revision, executor (humanorautomated), question, prerequisites, steps, requested observations, environment, deadline and reserved budget ledger ref.async-test-feedback-v1: matching identity/executor, observed environment, tester ID, outcome (completedorunable_to_test), observations, attachment references/hashes, and confirming actor/time. Unsupported operations, unknown fields and unconfirmed feedback are rejected.
The controller reserves budget first, using testing.request_human or
testing.request_automated, then calls submit(request). These actions require
explicit cost overrides in the frozen budget policy. The example budget config
sets human tests to 40 units and automated tests to 20. These are tunable initial
values; they do not start any test execution. Existing revisions need their
existing policy and cannot silently adopt a new cost table.
One outstanding case-level test is allowed at present. A reservation and its submission are separate durable steps. A failed submission does not silently refund the reservation: the controller can retry the same valid request or explicitly fail an undispatched reservation under existing budget rules. Future delivery/claim/cancellation policies will need explicit contracts; none are inferred from a deadline or idle time.
Waiting and confirmation
INVESTIGATING_HYPOTHESES + matching reserved action
-> request stored + BLOCKED/AWAITING_TEST_FEEDBACK
-> worker continues with other cases
-> authenticated external adapter confirms matching feedback
-> feedback stored + INVESTIGATING_HYPOTHESES (same analysis_revision)
-> future controller evaluates result and settles the reserved action
Submission stores an immutable request under
analysis/async-tests/NNNN/<hashed-request-id>/request.json, sets the manifest
pointer async_test_request, and publishes a wait checkpoint. The checkpoint
has automatic_retry = false. The deadline is recorded as retry_not_before
for scheduling visibility, but it does not authorize an automatic resume.
The inbox worker explicitly skips AWAITING_TEST_FEEDBACK; ordinary lifecycle
advance cannot resume such a case. Deadline expiry neither consumes budget
nor creates a failure, new analysis revision, refund or replacement request.
Deadline escalation/notifications are future adapter/controller policy.
confirm_feedback(feedback) verifies the original handoff, matching identities,
pending reservation, unchanged ledger, schemas and attachment hashes. It stores
feedback.json, sets async_test_feedback, and resumes the investigation even
before retry_not_before. It deliberately uses a narrowly controlled event-driven
resume path rather than disabling retry protection for other blocked reasons.
While waiting, remaining balance, expenses, rewards, low-information counters
and pending reservations remain unchanged. Confirmation also leaves the budget
ledger unchanged. Only subsequent record_result/settle applies novelty,
semantic scoring and possible reward. Waiting hours never cost extra credits;
confirmation never restores start budgets. Unavailable tests can return a
confirmed unable_to_test observation and be assessed as a low-information
result. Unrelated post-diagnosis review or patch rejection still uses the
existing REOPENED path and creates a new revision.
Both APIs are idempotent. The same document reuses the current package;
conflicting content under the same request ID is rejected. Unknown, wrong-case,
wrong-revision, unmatched and unconfirmed feedback cannot wake the case. Events
increase only package_generation and preserve all previous payloads. A case
waiting for external feedback can be admitted on another service before its
deadline and still stays blocked until confirmed feedback arrives.
Future web/bot adapter responsibilities
The UI will list persisted requests, allow authorized testers to claim them, capture observations and upload attachments, and call the confirmation API. External adapters need reliable/idempotent delivery, authentication, authorization, attachment size/type policy and notification/escalation handling. Delivery state must not replace the case-local original request and feedback history. Draft feedback stays outside the authoritative package until confirmed; no console entry or SSH workflow is required.
Attachments must already exist in the package when confirmation is called, with
matching hashes. The future upload importer will append them using the existing
safe writer, preferably under the same request's attachments/ directory.
Unknown files are preserved. Checkpoint-declared request/feedback artifacts and
their async-test attachment references are excluded from raw CaseBuilder input
identity, so expected investigation feedback does not force case regeneration.
Existing original-source attachments retain their original input classification.
The coordinator's configurable max_json_bytes (default 1 MiB) is an operational
safeguard, not a permanent limit of either v1 format. Case locking, generation
comparison and atomic package publication use the existing lifecycle foundation.
No lock is held while a human, bot, network provider or model is working.