The engine owns the lifecycle.
The complete flow begins with a user-impact contract, gathers scoped signals, proposes candidates, selects a permitted check, collects evidence, updates hypotheses, and evaluates verification. Each iteration receives a new view of the same explicit state. The model sees what it needs for its bounded judgment; the engine resolves action IDs, reserves budget, and controls transitions.
This implementation uses native JavaScript modules that run in the browser and in Node. It has no database migration and no new frontend framework dependency. The site simulator uses synthetic collectors and a transparent fixture judge. The optional CLI model adapter can replace the judge while the same engine continues to own permissions and closure.
const engine = new InvestigationEngine("cache");
await engine.requestJudgment(async (view, signal) => {
// Call an authorized provider from a server-side adapter.
// Return a bounded envelope; never execute a model-written command.
return {kind:"choose_check", checkId:"contract",
reason:"Identify the violated user contract first."};
});
const gate = engine.verify(); // evaluates evidence; does not force closureStore authoritative evidence separately from memory.
An evidence ledger preserves observations and provenance. Investigation memory can summarize which paths were explored and which checks failed, but it should point to ledger IDs. A compressed model summary must not overwrite raw observations or make eliminated alternatives disappear. The engine returns immutable snapshots; private state prevents the judge from setting status or editing collector results through the public interface.
A capability registry maps a known check ID to a typed collector. Prerequisites constrain when each collector is useful. This simulator allows reads and isolated synthetic replays. It contains no shell command, arbitrary URL fetch, deployment, or payment capability. Production credentials belong to collectors with separately scoped service permissions, outside model context.
Audit both decisions and refusals.
The event log records accepted decisions, rejected proposals, evidence, verification attempts, and unresolved handoffs. Model calls have deadline and cost metering. Rejected decisions consume decision budget, while a repeated check cannot consume a second collector call. Recorded decisions let replay reconstruct the same fixture observations and gates without invoking a model again.
Replay consistency is different from source authenticity. Exported browser reports are unsigned training artifacts, and a consistent fabricated event history is not proof that a production collector actually ran. A deployed system would add authenticated source references, access controls, integrity protection, retention policy, and durable versioned storage.
Observe the investigator as a production service.
Track rejected decisions, repeated-check attempts, candidate expansions, unexplained scopes, verifier refusals, model timeouts, budget consumption, and human handoff time. Connect these metrics to run IDs and policy versions. Keep high-cardinality incident details out of broad metric labels and redact sensitive payloads at the collector boundary.
Use the workbench below to step through the same flow that a model adapter would use. Request verification before and after a replay, attempt an unrestricted proposal, and export the event report. A denied proposal is a useful result: it demonstrates that uncertain judgment cannot expand the execution surface.
LLMs make uncertain judgments. Software controls state, authority, verification, and stopping.