ship: v0.2 P2 research engine + trust loop #11

Merged
coreci-bot merged 8 commits from phase/02-engine-trust into milestone/v0.2-mvp 2026-09-27 11:48:28 +00:00
Owner

REQ-07, 12, 13..24: asyncio state machine with plan-approval halt, durable JSON state (atomic rewrites, position-aware resume), typed event bus + trace.jsonl, evidence store (visited-only), SSRF-guarded liveness, quote anchoring (REQ-20 real mismatch detection), citation ledger, verification checklist + REQ-23 export gate, confidence labels, live probe wiring. Verify: 2 P0 + 9 P1 found and fixed in-phase with regression pins. Gates: backend 108 tests + mypy strict + ruff; frontend 90 tests. Tag target v0.2.2.

REQ-07, 12, 13..24: asyncio state machine with plan-approval halt, durable JSON state (atomic rewrites, position-aware resume), typed event bus + trace.jsonl, evidence store (visited-only), SSRF-guarded liveness, quote anchoring (REQ-20 real mismatch detection), citation ledger, verification checklist + REQ-23 export gate, confidence labels, live probe wiring. Verify: 2 P0 + 9 P1 found and fixed in-phase with regression pins. Gates: backend 108 tests + mypy strict + ruff; frontend 90 tests. Tag target v0.2.2.
coreci-bot added 8 commits 2026-09-27 11:48:24 +00:00
---ci---
phase: 2
milestone: v0.2
status: plan
message: >-
  Phase-boundary PLAN refresh (v0.1 practice): P2 plan written —
  evidence store, state machine, event bus, RunActor with
  AWAITING_APPROVAL halt, durable pause/resume, trust loop
  (liveness, anchoring, ledger, checklist, confidence labels),
  SSRF guard (P1 verify flag promoted to mandatory), live probe
  wiring (REQ-07/12 complete here), demo script, run-id
  consolidation. MVP/UX sections authored. G-006 split lever
  noted.
requirements:
  covered: []
  partial: []
---/ci---
---ci---
phase: 2
milestone: v0.2
status: execute
persona: data-engineer
task: T-2.1
requirements:
  covered: [REQ-18]
---/ci---
---ci---
phase: 2
milestone: v0.2
status: execute
persona: backend-engineer
task: T-2.3
requirements:
  covered: [REQ-13, REQ-14, REQ-15, REQ-16, REQ-18, REQ-19, REQ-20, REQ-21, REQ-22, REQ-24]
---/ci---

Engine: typed state machine (PLANNING → AWAITING_APPROVAL →
SEARCHING → EXTRACTING → REFLECTING depth loop → SYNTHESIZING →
VERIFYING → DONE/CANCELLED/FAILED with a legal-transition table),
RunActor with plan approval halt, asyncio pause/resume gates,
cancel persisting terminal state, CancelledError re-raised after
shielded persist, durable state.json rewritten atomically per
transition. Typed EventBus (run_started, query_fired,
source_found, source_visited, passage_extracted, state_changed,
run_done, run_error) + trace artifacts. Evidence store: stable
p-<n> passage IDs, paragraph extraction, writer context =
stored passages only (visited-only by construction). Trust loop:
SSRF-guarded liveness (live/stale/dead, redirect-follow, 10s,
2MB cap), quote anchoring (NFC/casefold/whitespace normalize,
exact-substring short-circuit, SequenceMatcher ≥ 0.85,
weak_match flags), citation ledger JSON (url, visited_at,
passages, claims, health, authority tier), exportable
verification checklist, single-source vs corroborated confidence
labels. 96 tests green on fakes — zero API keys.
---ci---
phase: 2
milestone: v0.2
status: execute
persona: backend-engineer
task: T-2.6
requirements:
  covered: [REQ-15, REQ-31]
---/ci---

Actor is position-aware: a restored state past PLANNING skips the
planning phase and re-enters at the approval/research boundary with
its persisted plan (state file round-trip proven: state, cursor,
plan all survive). researchx.engine.demo walks the full pipeline on
fakes into a temp runs dir (state.json, report.md, ledger.json,
checklist.md + 10 events). make_run_config now uses the storage
adapter's reduced-alphabet run-id generator (verify P2 flag
resolved: dual generators consolidated). 99 tests green.
---ci---
phase: 2
milestone: v0.2
status: execute
persona: backend-engineer
task: T-2.13
requirements:
  covered: [REQ-07, REQ-12]
---/ci---

REQ-07/12 COMPLETE: probe results attach to run state (persisted
in state.json, surfaced via probe_attached event); probe failure
degrades honestly - the run proceeds without probe data, never
crashes (MockTransport-proven both paths). README gains the engine
architecture section (state machine, artifacts, trust loop, demo
command). 101 tests green.
---ci---
phase: 2
milestone: v0.2
status: verify
persona: backend-engineer
task: T-2.5
requirements:
  covered: [REQ-16, REQ-18, REQ-20, REQ-23]
---/ci---

P0-1: SSRF guard now lives in adapters/url_guard.py (IPv4+IPv6
via getaddrinfo, fails closed on unresolvable) and is wired into
Tavily.fetch, DDG.fetch, AND the engine extract step (refused
URLs logged as source_refused events, never fetched). Liveness
redirects followed manually with per-hop re-guarding - a 302 to a
private IP now classifies DEAD, and STALE is reachable (redirect
loop / missing location).

P0-2: writer prompts gain {evidence} slots; render_writer_prompt
requires evidence; regression test proves evidence text reaches
the writer prompt (recording model).

P1s: ledger anchoring now anchors the REPORT's extracted quotes
against all passages (mismatch detection real, REQ-20 testable);
trace.jsonl append-only per run (REQ-16 trace file); _execute is
position-aware - resume works from SEARCHING/EXTRACTING/
REFLECTING/SYNTHESIZING/VERIFYING (mid-run restart test); cancel
honored post-approval via per-iteration checks in the research
loop; REQ-23 export gate (>= 0.99 liveness with failure listing
in the checklist); authority tiers dot-anchored; extracting step
processes ALL sub-questions (breadth fix); AdapterError taxonomy
covers raw httpx errors at the extract boundary. 108 tests.
---ci---
phase: 2
milestone: v0.2
status: verify
requirements:
  covered: [REQ-07, REQ-12, REQ-13, REQ-14, REQ-15, REQ-16, REQ-18, REQ-19, REQ-20, REQ-21, REQ-22, REQ-23, REQ-24]
  partial: []
lessons:
  - "P0s both masked by fake tests: SSRF guard existed but was never wired into the fetch boundary; writer prompts had no evidence slot so the visited-only constraint was vacuous - both fixed with regression pins (evidence-in-prompt recording test, refused-fetch test)"
  - "Fake-adapter tests mask integration gaps: the three highest-risk behaviors were exactly the untested ones. P4 adversarial suite must include real-boundary probes"
  - "P2 flags for post-hoc: DNS-rebinding TOCTOU residual risk (getaddrinfo vs connect-time resolution), evidence store not persisted across restarts (renumbered IDs on resume), reflecting step is re-planning (depth>1 loop untested), liveness body accumulation vs HEAD"
---/ci---

Structural: mypy strict 36 files, ruff clean. Behavioral: 108
backend tests (full walk, approval halt, pause/resume mid-run,
cancel pre+post approval, restart from AWAITING_APPROVAL and
SEARCHING, probe wiring both paths, trust thresholds, SSRF
refusals, export gate) + 90 frontend green. REQ-13..24 mapped.
Security: SSRF enforced at every fetch path + per-hop redirect
guarding; no value leaks (probe persists typed data only). The
phase is shippable: both P0s and all blocking P1s resolved with
regression coverage.
---ci---
phase: 2
milestone: v0.2
status: verify
---/ci---
coreci-bot merged commit 558f21a851 into milestone/v0.2-mvp 2026-09-27 11:48:28 +00:00
Sign in to join this conversation.