decision(P00): clarification — v0.2 MVP ambiguities resolved (D-007..D-020)
---ci---
phase: 0
milestone: v0.2
status: clarify
decisions:
- id: D-007
decision: Backend layout = backend/ package at repo root, src-layout researchx with config/, methodologies/, adapters/, engine/, evidence/, trust/, api/ per ARCHITECTURE §Components
rationale: Matches ARCHITECTURE.md component map 1:1; src-layout avoids import shadowing; uv manages the venv + Python 3.12
confidence: 0.95
alternatives: [flat single-package, api-first layout]
- id: D-008
decision: Provision uv + uv-managed Python 3.12 (official installer, user-local ~/.local/bin); system Python is 3.11.2
rationale: REQ-33 mandates uv-managed Python 3.12; uv fetches a managed CPython so the system interpreter is irrelevant
confidence: 0.9
alternatives: [system 3.11 venv + pip (deviation from spec)]
- id: D-009
decision: Backend serves on 127.0.0.1:8000; frontend dev on :3000 calls backend via NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000; FastAPI CORS allows localhost:3000
rationale: FastAPI/uvicorn defaults for a local-first single-user tool; frontend env var keeps the ApiClient boundary intact
confidence: 0.85
alternatives: [single-origin reverse proxy, fixed port 3001]
- id: D-010
decision: Run IDs = 8-char nanoid-style lowercase alnum slug (e.g. r-3f9k2q7z), generated by the API layer; storage layout = <storage_dir>/runs/<run_id>/
rationale: Human-referenceable in URLs and folders; nanoid avoids UUID's file-name collisions with 8 chars at 62-alphabet entropy (~10^14)
confidence: 0.8
alternatives: [uuid4 hex, monotonic counter]
- id: D-011
decision: Ollama endpoints resolve from secrets scopes: base URLs via OLLAMA_BASE_URL (default https://ollama.com/v1) and fallback http://localhost:11434/v1; API key via OLLAMA_API_KEY from .ciagent/.env.secrets only
rationale: config.json secrets.model scope already declares OLLAMA_API_KEY + OLLAMA_BASE_URL; env-file secrets-loader is the only resolution path per ship/verify credential rules
confidence: 0.9
alternatives: [config.json fields, interactive setup]
- id: D-012
decision: DuckDuckGo keyless fallback = HTML-lite endpoint (html.duckduckgo.com/html) scraped conservatively (top results, title+url+snippet); Tavily remains the default search adapter via TAVILY_API_KEY
rationale: Keyless fallback must need zero credentials; the html endpoint requires none and is the standard keyless DDG surface; Tavily default per REQ-09
confidence: 0.75
alternatives: [duckduckgo_search python lib, searx instance]
- id: D-013
decision: OpenAPI client generation = openapi-typescript (types) + openapi-fetch (typed fetch client) into frontend/src/lib/api/generated/, bound behind the existing ApiClient interface in P3
rationale: Zero-runtime overhead, TS-strict, produces a typed fetch function that wraps cleanly behind ApiClient; avoids heavyweight SDK codegen
confidence: 0.8
alternatives: [orval, @openapitools/openapi-generator-cli]
- id: D-014
decision: SSE transport = GET /api/runs/{id}/events via sse-starlette EventSourceResponse; typed event bus is asyncio.Queue-fed with pydantic event models (run_started, query_fired, source_visited, passage_extracted, state_changed, run_done, run_error)
rationale: sse-starlette is the maintained FastAPI SSE standard; pydantic events give the typed bus REQ-16 demands; matches the MockApiClient replay contract already in the frontend
confidence: 0.85
alternatives: [websockets, polling]
- id: D-015
decision: Quote-anchoring fuzzy match = normalized token-subset + difflib SequenceMatcher ratio >= 0.85 as the primary check; exact substring match short-circuits; mismatch flagged in the ledger, never silently dropped
rationale: difflib is stdlib (zero deps), 0.85 threshold balances recall/precision on quoted prose; flagged mismatches preserve trust-loop transparency
confidence: 0.75
alternatives: [rapidfuzz, embedding similarity]
- id: D-016
decision: URL liveness pass = HTTP HEAD/GET (follow redirects, 10s timeout) classifying 200-299=live, 3xx-stale-after-redirect-limit/stale-content=stale, 4xx/5xx/timeout/dead-url=dead; runs post-run per REQ-19; recheck at export
rationale: Simple, deterministic classification REQ-19 names live/stale/dead; single GET with redirect following captures the common moved-page case
confidence: 0.8
alternatives: [HEAD-only, wayback fallback]
- id: D-017
decision: Engine durability = JSON state file per run (runs/<id>/state.json) rewritten atomically (tmp+rename) after every state transition + EventBus subscribers receive replay on resume; asyncio tasks checkpointed via state machine position, not mid-task
rationale: REQ-15 demands pause/cancel/resume across restarts; atomic rewrite prevents torn files; transitions are natural checkpoint boundaries
confidence: 0.85
alternatives: [sqlite, append-only journal]
- id: D-018
decision: Run termination semantics for THIS pipeline run: phases ship P1..P4 + final P5; the milestone → main merge HALTS at the owner approval gate (merge_to_main escalation hook) exactly as v0.1 did — the run presents v0.2.5 and stops
rationale: Owner-approved run directive (this session): 'P0–P5, halt at owner gate'; config.json escalation_hooks includes merge_to_main; v0.1 precedent (v0.1.8 halted, owner recorded approval in a follow-up)
confidence: 1.0
alternatives: [autonomous merge at full autonomy]
- id: D-019
decision: Deploy policy for this run = none; no LXC staging without an explicit owner directive (deploy escalation hook)
rationale: Owner-approved run directive (this session): 'No deploys without owner directive'
confidence: 1.0
alternatives: [stage v0.2.x-uat at P5 gate]
- id: D-020
decision: Frontend stays on the v0.1 ApiClient boundary in P1/P2 (MockApiClient), P3 adds a generated OpenAPI client + ApiClient binding switch (env-flag RESEARCHX_API_MODE=mock|live with mock default), no component rewrites (REQ-26/REQ-54)
rationale: Keeps REQ-54 zero-throwaway promise explicit; live binding only activated when the backend runs, mock remains default for dev/tests
confidence: 0.9
alternatives: [hard swap in P3, dual clients per component]
---/ci---
CLARIFY stage, milestone v0.2: 14 ambiguities resolved at full
autonomy (defaults accepted). Key resolutions: backend/ src-layout
package, uv + managed Python 3.12, run IDs as short slugs, DDG
html-lite keyless fallback, openapi-typescript client gen, sse-starlette
event transport, difflib quote anchoring at 0.85, JSON durable state
with atomic rewrites, owner-gate halt at P5, no deploys without
directive. PROJECT.md + REQUIREMENTS.md updated with the clarified
constraints.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"phase": 0,
|
||||
"stage": "specify",
|
||||
"stage": "clarify",
|
||||
"milestone": "v0.2",
|
||||
"phase_role": "pre_execution",
|
||||
"attempts": 0,
|
||||
"updated_at": "2026-09-27T10:20:00Z"
|
||||
"updated_at": "2026-09-27T10:30:00Z"
|
||||
}
|
||||
Reference in New Issue
Block a user