ship: v0.3 phase 0 — pre-execution (specify, clarify, research, plan, grill, mvp/ux) #16
Merged
coreci-bot
merged 5 commits from 2026-09-29 17:13:33 +00:00
phase/00-pre-execution into milestone/v0.3-hosted
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3ea96c0984 |
docs(grill): adversarial review — 11 challenges, 10 binding decisions, 1 escalation
---ci---
project: researchx
phase: 0
milestone: v0.3
status: grill
decisions:
- id: G-101
decision: "Startup sweep handles PLANNING runs: C3-11's 'verified' CANCELLED-legality claim is false (states.py PLANNING to {AWAITING_APPROVAL,FAILED}); add PLANNING to CANCELLED in _LEGAL_TRANSITIONS or document a bypass; pinned by sweep test in T-1.8"
rationale: "A crash mid-PLANNING leaves a persisted state the sweep cannot legally cancel — restart-path corruption at the first hosted redeploy"
confidence: 0.90
- id: G-102
decision: "Stale out-of-scope rows fixed (REQUIREMENTS 'Auth/multi-tenancy' + PROJECT 'multi-tenant/auth') to match the recorded supersession"
rationale: "Same-file contradictions with the owner-recorded v0.3 supersession"
confidence: 0.95
- id: G-103
decision: "REQ-75 split bound (delegation-end P3, hosted-default P4); traceability row fixed; PLAN's pitfall-phase mapping authoritative over C3-19"
rationale: "G-001-class triple-mapping contradiction across three documents"
confidence: 0.85
- id: G-104
decision: "Exposure hardening: password min length 12 at register + admin-create; per-IP login rate limit at HAProxy front; audit asserts throttle + uniform 401s"
rationale: "Public URL + argon2 ~50-100ms CPU per verify = DoS amplifier; no policy existed anywhere"
confidence: 0.80
- id: G-105
decision: "KEK-loss posture stated: loss = per-user keys unrecoverable, honest degradation, re-entry under re-provisioned KEK; owner backs up off-repo; rotation out of v0.3 (recorded)"
rationale: "KEK becomes load-bearing at P2; loss posture was stated nowhere"
confidence: 0.85
- id: G-106
decision: "deploy.sh: free-disk assert + dangling-image prune + documented 4-container host budget"
rationale: "P4 doubles image families on a single LXC host; current script has neither"
confidence: 0.75
- id: G-107
decision: "Staged deploy defined: candidate pair on the host, health green, four smoke assertions host-locally; public cutover is a discrete owner-directive act with -prev armed"
rationale: "P4's DoD used an undefined term; the host runs one container today"
confidence: 0.75
- id: G-108
decision: "P3 pressure valve (G-006 precedent): may ship as P3a backend + P3b frontend patches without scope change"
rationale: "P3 is the heaviest phase (7 REQs + standalone client + all swaps) with no pre-agreed valve"
confidence: 0.70
- id: G-109
decision: "Task-inbox honesty: live-mode status derived (answered-iff DONE); checkbox display-honest in live mode; persisted check state is v0.4+; pinned by test"
rationale: "REQ-78 promises 'checkable' but the derived GET-only read-model silently reverts user checks"
confidence: 0.75
- id: G-110
decision: "Cost posture stated: server-tier runs bill the owner's key; bound = admin-managed accounts; per-user counters surface usage; no hard cap in v0.3"
rationale: "Server-key-as-fallback (owner-picked) with the cost ceiling stated nowhere"
confidence: 0.70
escalations:
- "[G-111] P4's DoD (staged smoke on the LXC host) requires a host deployment D-019 forbids without a directive — owner must pre-authorize staged deploys for P4 DoD (no public cutover) or accept host proofs deferred to the gate"
requirements:
covered: []
partial: []
---/ci---
Verdict: Proceed (0.68). 11/12 sampled research claims verified
exact; the one false claim (sweep legality) bound as G-101 with a
test pin. G-102/G-103 applied to REQUIREMENTS/PROJECT/PLAN in this
commit; G-101/104..110 encoded as PLAN must-haves; G-111 visible via
ciagent audit.
|
||
|
|
dca86a74ad |
docs(P00): create phase plans — v0.3 hosted P1..P4 + P5 note
---ci--- project: researchx phase: 0 milestone: v0.3 status: plan requirements: covered: [] partial: [] message: >- PLAN.md: vertical-slice plans for P1 (auth+sessions+scoping, T-1.1.. T-1.12), P2 (per-user settings+model keys+factory, T-2.1..T-2.11), P3 (live surfaces, read-models, report.json/evidence.json, standalone live client, T-3.1..T-3.13), P4 (hosting, live default, smoke+exposure audit, T-4.1..T-4.9); P5 final-review note. MVP/UX sections written (User-Facing Surface, Happy Path, UX Acceptance Criteria). C3-18 ApiClient extension list documented exhaustively before P1 (G-002 lesson). Pitfall ledger P-1..P-14 assigned and closable by v0.3.4. Carrying gates: G-005 snapshot+drift per route-touching phase, G-007 owner-keyed counters, G-008 DDG fixtures, D-018/D-019 halt+deploy. ---/ci--- |
||
|
|
6f5c4d5aa1 |
docs(P00): research findings — v0.3 hosted auth, key store, partitioning, hosting
---ci--- project: researchx phase: 0 milestone: v0.3 status: research requirements: covered: [] partial: [] message: >- RESEARCH-v03.md: 12 topics, 20 conclusions (C3-01..C3-20), 14 verified multi-user pitfalls (P-1..P-14). Key findings: shared-adapter fallback-mutation bug confirmed (ollama.py:73-79) — per-run factory mandatory; config_status reads private runs._actors (first multi-user breakage); all read endpoints die on restart — disk read-models are load-bearing for hosting; CORS lacks allow_credentials; module-level create_app() would serve fakes in production — new researchx.api.main entry required; frontend marker regex forces [p-N]→[^pN] normalization at the report.json boundary. ARCHITECTURE.md rewritten for v0.3 (new components: Identity & Sessions, Per-User Key Store, Model Adapter Factory; deployment topology). PERSONAS.md v0.3 roster: security- engineer phase-specific P1/P2/P4. config.json gains the 'keys' secrets scope (RESEARCHX_KEK). ---/ci--- |
||
|
|
33f4fa003a |
decision(P00): clarification — v0.3 hosted auth, key store, partitioning, live surfaces
---ci---
phase: 0
milestone: v0.3
status: clarify
decisions:
- id: D-101
decision: "Sessions: server-side store (in-process dict + durable sessions.json), httpOnly SameSite=Lax cookies, opaque tokens, 14-day sliding expiry, immediate revocation"
rationale: "Single uvicorn worker makes in-process sound; server-side is the only posture satisfying REQ-70 deactivation"
confidence: 0.90
- id: D-102
decision: "argon2id via argon2-cffi, verify via asyncio.to_thread"
rationale: "REQ-69 names argon2id; standard maintained implementation"
confidence: 0.95
- id: D-103
decision: "401 guard on all /api/* except login/register; CSRF = SameSite=Lax + custom header on non-GET; /healthz outside /api"
rationale: "Same-origin proxy + JSON fetch + custom header kills cross-site CSRF without token round-trips"
confidence: 0.82
- id: D-104
decision: "Register open only while user store empty (first user = admin); then admin-created accounts with admin-set passwords"
rationale: "Only mechanism without CLI/mail; race-safe under single asyncio worker"
confidence: 0.85
- id: D-105
decision: "user_id = 8-char slug, email login, no email verification"
rationale: "House ID style; filesystem-safe partition key"
confidence: 0.75
- id: D-106
decision: "User-prefixed storage runs/<user_id>/<run_id>/ (supersedes D-010); owner_id in RunState; no migration"
rationale: "Defense in depth; per-user library = single directory scan"
confidence: 0.88
- id: D-107
decision: "Data root = RESEARCHX_DATA_DIR (dev backend/var/researchx; container /var/lib/researchx)"
rationale: "cwd-dependent storage breaks under container workdirs"
confidence: 0.85
- id: D-108
decision: "KEK = RESEARCHX_KEK (env-file 'keys' scope), AES-256-GCM with user_id as AAD; disabled honestly when unconfigured"
rationale: "REQ-73 mandate; graceful degradation keeps zero-key dev green"
confidence: 0.83
- id: D-109
decision: "Key store scope = model key only in v0.3"
rationale: "REQ-73/74 name model keys; minimal encrypted surface"
confidence: 0.80
- id: D-110
decision: "Model adapter constructed per run via factory resolving user→server→keyless; probe per resolved tier"
rationale: "Shared adapter mutates _active_base globally (verified bug); per-user keys impossible on shared instance"
confidence: 0.90
- id: D-111
decision: "GET /api/config stays read-only status; new GET/PUT /api/config/settings for per-user settings; storage path display-only hosted"
rationale: "Two read models already split in the ApiClient"
confidence: 0.87
- id: D-112
decision: "Code default stays mock; hosted image built with NEXT_PUBLIC_RESEARCHX_API_MODE=live; no live delegation to mock after P3"
rationale: "Build-time inlining of NEXT_PUBLIC vars; zero-key discipline preserved"
confidence: 0.85
- id: D-113
decision: "REQ-82 in scope as backend work: persist report.json + evidence.json at DONE; endpoints enriched; live exports use real data"
rationale: "Evidence is in-memory only today; hover quotes impossible without persisted artifacts"
confidence: 0.90
- id: D-114
decision: "Open questions = plan sub-questions answered-iff DONE; no synthetic suggestions; empty state for new users"
rationale: "Real, persisted, user-scoped, honest, zero extra model cost"
confidence: 0.65
- id: D-115
decision: "Read-models read disk artifacts, not RunRegistry; in-flight runs marked cancelled on restart; rehydration out of v0.3 scope"
rationale: "RunRegistry is in-process; disk-backed read-models mandatory for hosted restarts"
confidence: 0.80
requirements:
covered: []
partial: []
---/ci---
REQUIREMENTS.md REQ-69..85 refined with the decision outcomes;
PROJECT.md carries the D-101..D-115 decision log.
|
||
|
|
a4afcccd7f |
docs(init): validate specification — v0.3 hosted milestone
---ci--- project: researchx phase: 0 milestone: v0.3 status: specify requirements: covered: [] partial: [] message: >- v0.3 'hosted' scope established (owner-directed 2026-09-29): auth + sessions (user/pass, admin-managed, OAuth deferred), per-user model API keys (encrypted at rest, resolution chain user→server→keyless), live-bound user-scoped surfaces (library, settings, suggestions, refine, graph/inbox, profile), backend hosting (SSE-safe), real inference as product default. Requirement set REQ-69..85 written; single-user/no-auth constraint superseded; config.json milestone_name set; ROADMAP v0.3 section added (P0..P5). ---/ci--- |