215 lines
13 KiB
Markdown
215 lines
13 KiB
Markdown
# LLM investigation loop v1
|
||
|
||
The Investigator connects the existing Hypothesis Builder, LLMGateway, snapshot
|
||
Tool Router, EvidenceStore, BudgetManager and asynchronous test coordinator.
|
||
`docs/architecture.md` remains unchanged and authoritative. This phase performs
|
||
investigation, not final diagnosis or Change Request generation. It never writes
|
||
project source, SQL, patches, branches, builds or lab/client instructions for
|
||
direct execution.
|
||
|
||
## API and dispatch
|
||
|
||
```python
|
||
from viano_bug_analysis.analysis import Investigator, InvestigationConfig
|
||
|
||
loop = Investigator(
|
||
store, gateway,
|
||
InvestigationConfig.load("config/investigation.local.toml"),
|
||
router=router, # Supply the existing Vcore schema adapter where needed.
|
||
)
|
||
result = await loop.run(case_id, package_id)
|
||
```
|
||
|
||
`step` processes at most one model decision and its confirmed local execution.
|
||
`run` repeats eligible steps up to `max_steps_per_dispatch`, then returns
|
||
`YIELDED`. Callers can explicitly bound a dispatch through `max_steps`.
|
||
`PROGRESSED`, `REJECTED`, `YIELDED`, `RETRY_PENDING`, `DEFERRED`, `BLOCKED` and
|
||
`COMPLETED` describe scheduling outcomes. Unsafe input, stale state, exceeded
|
||
operational limits or changed policies raise a controlled `InvestigationError`;
|
||
duplicate concurrent dispatch raises the existing nonblocking `LockBusy`.
|
||
The server worker/scheduler remains a separate integration: no continuous daemon,
|
||
sleeping retry loop or UI is introduced.
|
||
|
||
Input must have an accepted current-revision interpretation and hypothesis batch.
|
||
The Investigator verifies the existing budget origins and canonical case freshness;
|
||
it does not silently build missing earlier phases or reopen changed raw inputs.
|
||
Existing pending actions without a controller-owned plan/last evidence binding
|
||
are rejected explicitly. Existing initialized budgets are reused, not refilled.
|
||
When no budget config is explicitly supplied, the stored effective budget policy
|
||
is adopted automatically for subsequent accounting. An explicit changed config
|
||
still follows BudgetManager's policy-change rejection rules.
|
||
|
||
## Deterministic cycle
|
||
|
||
1. Give each hypothesis one initial turn, then prefer higher confidence with
|
||
numeric-ID ties. A reviewed early completion request may defer alternatives;
|
||
see [Early diagnosis review](early-diagnosis-v1.md).
|
||
2. Build a bounded context from canonical case, accepted interpretation, current
|
||
hypothesis states, questions, notes, budget policy/balances, current-revision
|
||
stored evidence and the previous result. First iteration has no prior result.
|
||
3. Persist that context and its hash before the model call. `investigation_v1`
|
||
is retained for historical requests. New prompts extend the output contract
|
||
with reviewable early diagnosis and assessment-only deferral.
|
||
4. Execute one eligible LLM round through the existing persisted failover/retry
|
||
gateway. No global worker lock spans the external call.
|
||
5. Validate the whole reply: schema, references, confidence, question updates,
|
||
assessment binding, tool scope/arguments and projected affordability/status.
|
||
6. Persist the accepted decision as an execution plan before applying effects.
|
||
7. Settle the previous evidence's bounded semantic assessment, if present; then
|
||
reserve the next action and perform exactly one allowed query or test handoff.
|
||
8. Persist raw reply and normalized evidence, then account its deterministic
|
||
novelty through `record_evidence`. Semantic assessment occurs in a later
|
||
model iteration, not on the result's publication step.
|
||
9. Publish the updated hypothesis state and scheduling position.
|
||
|
||
Validation simulates settlement and reservation with the same deterministic budget
|
||
rules used by execution. A valid assessment with an invalid next action is wholly
|
||
rejected: it receives neither a refund nor partial question/confidence updates.
|
||
Local preflight reads bounded snapshots but does not dispatch query handlers or
|
||
perform external work. Runtime failures after a valid plan are recoverable from
|
||
that plan; they are distinct from technically invalid model replies.
|
||
|
||
## Model/controller contract
|
||
|
||
Each reply has exactly `assessment`, `update` and `next`:
|
||
|
||
- `assessment`: null on first iteration; otherwise integer semantic score 0–100,
|
||
concrete reason and valid evidence IDs including the previous result.
|
||
- `update`: qualitative confidence (`unassessed`, `weak`, `plausible`, `supported`,
|
||
`strongly_supported`, `weakened`), known evidence IDs, existing open questions
|
||
to resolve, new nonduplicate questions and an audit note.
|
||
- `next`: one existing tool operation/arguments, an external human/automated test
|
||
descriptor, or `finish`/`reject` with a reason.
|
||
|
||
Evidence citations must exist in the supplied current-revision context. Supported
|
||
confidence requires nonempty stored findings. Resolved questions require evidence
|
||
and cannot be unknown or already resolved. A strong-support update combined with
|
||
rejection is inconsistent and rejected. These checks establish technical grounding,
|
||
not scientific proof that the model's causal assessment is correct.
|
||
|
||
The controller assigns action/request IDs, deadlines, checkpoint IDs, question
|
||
IDs, costs, refunds and balances. They are not model-controlled output fields.
|
||
The first loop controller works over the accepted initial hypotheses. Dynamic
|
||
`hypothesis.create`, cross-hypothesis mutation and arbitrary controller commands
|
||
are not exposed; creation limits and immutable birth records remain unchanged.
|
||
Adding replacement hypotheses requires a dedicated creation/budget/registry
|
||
contract rather than granting a model extra allocations through this schema.
|
||
|
||
All source, database, human feedback and prior model notes are untrusted data.
|
||
Symbol occurrences and partial/empty queries retain their existing scope warnings.
|
||
No conclusions about current live server behavior are inferred from old snapshots.
|
||
The durable context includes current-revision evidence. The opt-in project-research
|
||
prompt uses a compact view documented in [project-research-v1.md](project-research-v1.md).
|
||
If the configured byte bound is exceeded, dispatch rejects explicitly;
|
||
operators must align context, gateway request and artifact limits.
|
||
|
||
## Budget and stopping
|
||
|
||
Every investigation query/test uses a positive configured cost. Refunds remain
|
||
strictly below cost; deterministic novelty and semantic utility must both justify
|
||
them. Empty/duplicate findings earn no novelty reward, overlaps receive the
|
||
existing item-based cap, and low-information/exhausted accounts are terminal.
|
||
Model token usage and monetary metrics remain separate from investigation units.
|
||
|
||
The new additive BudgetManager `complete` operation marks budget eligibility as
|
||
`investigation_finished`, preserves the balance and does not label a supported
|
||
hypothesis as factually rejected. Pending actions must first be assessed/closed.
|
||
The original hypothesis birth artifact is immutable; current qualitative states
|
||
live in the controller's versioned snapshots.
|
||
|
||
Logical defaults, frozen per analysis revision:
|
||
|
||
| Config | Default | Meaning |
|
||
| --- | --- | --- |
|
||
| `max_iterations_per_hypothesis` | 50 | Maximum research-producing model iterations; one final assessment/closure is permitted |
|
||
| `max_invalid_responses` | 3 | Consecutive rejected replies before blocking the case for technical correction |
|
||
| `max_questions_per_hypothesis` | 30 | Bound on accumulated question records |
|
||
| `test_deadline_seconds` | 21600 | Controller-owned external test deadline |
|
||
| `max_steps_per_dispatch` | 8 | Fair scheduler yield boundary |
|
||
|
||
An invalid reply changes only retry/audit bookkeeping. A following prompt includes
|
||
its safe rejection code. Repeated invalid replies cause `BLOCKED` with
|
||
`INVALID_LLM_RESPONSES`, requiring explicit operator resume after correction.
|
||
The hypothesis stays active; pending results, reservations and remaining credit
|
||
are preserved. No budget completion or zero-score settlement is fabricated.
|
||
The same initial hypotheses cannot be regenerated to reset their limits.
|
||
|
||
The iteration cap prevents free model-only research loops even when credit is
|
||
large. The final extra iteration can assess a pending result but may not start
|
||
another action. Questions, earlier notes and evidence remain in immutable history.
|
||
|
||
Once all accounts/dispositions are terminal, the case enters `BUILDING_DIAGNOSIS`
|
||
with final investigation state and deterministic `summary.md`. It does not create
|
||
a diagnosis, select a root cause or route a Coding-Agent task. The summary reports
|
||
balances, confidence, dispositions, evidence and outstanding questions. Its
|
||
countercheck marker records actions on alternatives; it is not semantic proof
|
||
that an alternative was meaningfully disproved. The later evaluator must still
|
||
consider uncertainty, evidence quality and missing counterchecks.
|
||
|
||
## Provider failures and external tests
|
||
|
||
Unreachable providers use existing ordered failover, configured delay and attempt
|
||
count (default 10). Pending retries return immediately with `retry_not_before`.
|
||
Exhaustion returns `BLOCKED`, preserving budgets, pending evidence and the frozen
|
||
context. Known credential, HTTP configuration, privacy/adapter and unexpected
|
||
provider failures also block the case rather than abandon its hypotheses.
|
||
|
||
After the external problem is fixed and the due blocked case is explicitly
|
||
resumed through the lifecycle, a caller can supply a stable `retry_id` to `step`
|
||
or `run`. This opens a new transport operation for an exhausted/configuration-
|
||
failed call; it does not reset investigation iterations, credit or evidence.
|
||
It cannot override an ordinary provider backoff or reset model-invalid counters.
|
||
Saved successful execution plans are completed without another model call, even
|
||
when transport configuration changes after their publication.
|
||
|
||
Human/automated test descriptors require explicitly configured action costs.
|
||
The controller freezes a deadline, reserves credit, stores the exact request and
|
||
delegates to `AsyncTestCoordinator`. The case returns
|
||
`BLOCKED/AWAITING_TEST_FEEDBACK` without parking a worker. No time-based charges
|
||
are applied. Authenticated, confirmed feedback resumes the same revision; the
|
||
loop imports it as evidence and later evaluates it. Web delivery/authentication,
|
||
bot steering, claims/cancellation and deadlines' notifications remain external
|
||
future adapters. See [async-tests-v1.md](async-tests-v1.md).
|
||
|
||
## Persistence and recovery
|
||
|
||
Context and state files are appended under `analysis/investigation/NNNN/`.
|
||
`manifest.artifacts.investigation_state` and `investigation_summary` are pointers.
|
||
Each state checkpoint has monotonically increasing sequence, parent ref and hash
|
||
binding; context hashes, identity and selected hypothesis are checked on replay.
|
||
Accepted plans are additionally bound to the original successful LLM call,
|
||
operation, saved request, prompt/schema/context and exact output document.
|
||
|
||
Reservation, result publication, evidence accounting, assessment and final state
|
||
publication are separately idempotent. After a crash, an accepted plan resumes
|
||
those steps; existing evidence is reused, not queried again or assigned new IDs.
|
||
Repeated completion repairs/validates stored output without new provider calls.
|
||
Pointer deletion or changed policy cannot silently restart the investigation.
|
||
CaseAssembler excludes only checkpoint-declared investigation artifacts, so
|
||
expected controller work does not make the accepted case stale.
|
||
|
||
`InvestigationLimits` are independent operational defaults: 1 MiB context,
|
||
4 MiB JSON artifact and 10,000 state checkpoints. They are adjustable safety
|
||
bounds, not permanent format limits. Compiled static schema validators are reused.
|
||
CheckpointStore caches validated generations only behind a newly computed full
|
||
archive-byte hash and unchanged limits. PackageReader additionally takes a bounded
|
||
immutable ZIP snapshot and reuses detached validation metadata for identical
|
||
snapshot hashes/limits, with a bounded entry/metadata cache. No timestamp-based
|
||
trust, extraction, skipped changed-file validation or raw archive retention in
|
||
the cache is introduced. Static bundled schema changes require process restart.
|
||
|
||
Tests exercise round-robin investigations, real read-only queries, semantic
|
||
assessment/novelty, bounded failures, limits, reference validation, questions,
|
||
provider retries/config errors, actual local HTTP transport, portable resume,
|
||
crashes after evidence publication, external test confirmation and byte-preserving
|
||
output. The BUG-20 integration uses actual wowdiag/wowsrc data and simulated model
|
||
decisions; it tests orchestration, not real model reasoning or discovery of the
|
||
known fix. No paid/cloud model is called by these tests.
|
||
|
||
Question resolution is idempotent: reconfirming an already resolved question
|
||
does not invalidate an otherwise valid decision and needs no new evidence.
|
||
Resolving any still-open question requires evidence references. Unknown question
|
||
IDs invalidate the entire decision before assessments, tools or budget changes
|
||
are applied. Mixing old confirmations with new resolutions follows the same
|
||
rules; existing question history is preserved.
|