Spec: F70 — Chaos Import → Boss Brief (the wedge)
Status: shipped and contract-backed (web + KMP mobile; G2/G5 gates pending; Contract Graph migration 2026-07-14)
This is the wedge. Per competitive-strategy-v2.md and field-tests.md §20, the single highest-priority surface in Lumi is the zero-setup first session: a contractor owner pastes one messy Zalo/Excel/screenshot/voice-note and gets today’s owner brief in under 10 minutes, before configuring anything. Every other feature in the registry is downstream of this working. Field-tests calls this “the only product spec allowed before evidence.” This spec is the contract for that flow.
Validation-gated, not velocity-gated. This is a draft design tied to field-test gates G2 (first-session value) and G5 (extraction quality). It is built concierge-first (manual-assisted) and automated only after repeated demand appears (field-tests §6). It does not get marked shipped until G2 passes with real owners.
Contract Graph migration note (2026-07-14)
F70 is now declared in contracts/features/F70.cue. The contract owns the authenticated paste-to-brief API, shared faithfulness boundary, evidence-bearing items, tenant isolation, role-gated save, and mutation safety. The shipped web/KMP source remains partial as a product claim because G2/G5 live validation and target-runtime evidence are not inferred from repository tests.
1. Problem & CEO Job
See clearly + trust the signal. The owner of a Vietnam interior fit-out / renovation / small M&E SME runs the business on Zalo/WhatsApp threads, Excel sheets, and memory. Their day’s real work — who owes what, which customer needs a callback, what is late, what risk is brewing, what must be confirmed with a client or supplier — is scattered across chat and spreadsheets and never assembled in one place. Today, to get any value from Lumi, the owner must first create an org, add projects, add staff, and learn a system. That cold-start tax is fatal: a non-technical owner’s patience runs out long before a blank workspace becomes useful. The strategy’s hard constraint is time-to-first- value under 10 minutes (strategy v2 §7.3).
Without this feature, Lumi asks the owner to “set up your whole workspace first” — the exact failure mode field-tests §1.3 lists as a stop condition. With it, the owner’s very first action produces a brief built from their own chaos, with every line traceable to the message it came from. The competitor here is not Asana or Notion — it is the owner’s own Zalo + Excel + memory. Lumi wins by turning that chaos into structure faster and more reliably than the owner can by hand.
2. User Stories & Acceptance Criteria
-
As an owner (first session, no projects/staff yet), I want to paste one messy work sample and get a structured “today” brief, so that I see value before configuring anything.
- Given a freshly registered owner with an empty workspace, when they paste a Zalo thread and submit, then a Boss Brief renders within the same session with at least the sections Việc cần xử lý / Cần chốt với bên ngoài / Rủi ro / Tin nhắn nên gửi populated from the input.
- Given the input contains an explicit promise (“anh gửi báo giá thứ 5”), when extraction runs, then a commitment item appears with the assignee, the due date, and a citation of the source line.
- Given the input is too short/empty/unreadable, when submitted, then the owner gets a guided “send a richer sample” state — never an invented brief.
-
As an owner, I want every brief item to cite its source line, so that I trust it.
- Given any AI-produced item, when it renders, then it links to an
EvidenceSourcequoting the exact text/row/message it was derived from, with an honest confidence badge. - Given an item the AI is unsure about, when it renders, then it is marked uncertain rather than asserted, and is never created as a hard commitment without owner confirmation.
- Given any AI-produced item, when it renders, then it links to an
-
As an owner, I want to correct or reject extracted items, so that the brief is mine.
- Given an item with a wrong assignee/date, when the owner edits it, then the correction persists and is logged (feeds F15 feedback / extraction-quality loop).
- Given a junk item, when the owner dismisses it, then it disappears and is not re-suggested.
-
As an owner, I want a clear next step after the brief, so that value compounds.
- Given a useful brief, when the owner taps invite staff, then they get a paste-into-Zalo invite link (F02) — this is the Loop 1 handoff.
- Given a brief item needing an external sign-off, when the owner taps send confirmation, then they enter the F71 inter-company confirmation flow (Loop 2) — never a dead end.
3. Scope Boundaries
- In:
- Single-input ingest: pasted chat text, screenshot (OCR’d to text), pasted Excel rows, voice-note transcript, or a typed note. (Reuses F32 Signal Inbox ingest + F34 uploads for images/audio.)
- One-shot extraction → a first Boss Brief assembled in the session (reuses F08 extraction and F12 brief assembly).
- Accept / correct / reject extracted items; save brief into the workspace.
- Upgrade path CTAs: invite staff (F02 / Loop 1), send confirmation (F71 / Loop 2).
- Concierge fallback: a manual-assisted path for the pre-automation validation phase (field-tests §6).
- Out:
- Full CRM / project / task setup (F04, F05, F27, F50) — these come after the wedge proves value, not before.
- The recurring daily pulse ritual (F07) — the wedge is the cold start; the pulse is the steady-state habit it graduates into.
- Source connectors (F44) — paste-first; connectors are a later convenience.
- Multi-sample batch import / bulk migration — explicitly out (one messy sample is the point).
4. Data Model
Reuses the existing spine; adds one lightweight grouping model.
- Reused:
SignalInboxItem(the raw pasted/uploaded input),EvidenceSource(provenance for every produced item), and the produced draftsCommitment/Risk/DecisionRequest/Task, assembled into aBrief+BriefItemset. - New —
ChaosImport(UUIDModel,organizationFK — required, never null):created_by→OrganizationMemberinput_kind∈ {chat_paste,excel_paste,screenshot,voice_note,typed_note}raw_signal→ FK toSignalInboxItemgenerated_brief→ FK toBrief(nullable until extraction completes)status∈ {received→extracting→briefed→saved} |failedis_concierge(bool) — true when a human assisted extraction during validation- Status transitions update backend/DIAGRAMS.md state machine.
- Zero-setup without breaking tenancy. “No setup” is a UX promise, not a tenancy hole. On first
sign-up the wedge auto-provisions a provisional
Organization(named from the pasted content, renameable later) so that everyChaosImportand produced item is tenant-scoped from line one (Rule 1). The owner never fills an org-creation form; the org exists silently. See §12 — this needs an ADR.
5. API Contract
| Method | Path | Auth/Role | Request | Response | Errors |
|---|---|---|---|---|---|
| POST | /api/chaos-import/ | Authenticated member; org auto-provisioned if none | {input_kind, content, upload_id?} | 201 {chaos_import_id, status} | 400 empty/oversized input; 415 unreadable; 429 rate-limited |
| GET | /api/chaos-import/{id}/ | Member of owning org | — | 200 {status, brief{...items[] with evidence + confidence}} | 404 cross-org; 409 still extracting |
| POST | /api/chaos-import/{id}/items/{item_id}/correct/ | Member of owning org | {field, value} | 200 {item} | 404 cross-org |
| POST | /api/chaos-import/{id}/items/{item_id}/dismiss/ | Member of owning org | — | 204 | 404 cross-org |
| POST | /api/chaos-import/{id}/save/ | Owner/Admin | — | 200 {brief_id} (persists drafts into the workspace) | 403 role |
Contract Graph ownership: the shipped detail route GET /api/chaos-import/{id}/ is assigned to
ChaosImportViewSet.retrieve with a registered backend proof. This records source/test ownership
only; field-validation, browser, native, and production evidence remain separate gaps.
- Tenant scoping: every query filtered by
organization_id=self.request.organization_id; the producedBrief/items inherit the same org. No endpoint accepts a cross-org id. - AI output: every produced item links an
EvidenceSourcequoting the source line. Confidence is honest: 0.6–0.8 for keyword extraction, 0.85–0.90 for LLM, never 1.0, never hardcoded (Rule 2). Items below a confidence floor render as uncertain suggestions, not created objects. - Hallucination guard: the extraction prompt + post-filter must never assert a commitment/date/ assignee absent from the source. A produced item with no evidence span is dropped, not shown.
6. UI / UX
- Route:
/intel/import(first-run, authenticated import) and reachable later as Import from the Brief/Today surfaces. (The public marketing/startlanding is unchanged.) - Page component:
ChaosImportPage→ChaosImportInput(textarea + paste/upload affordances) andBossBriefResult(the rendered brief). - States to design: empty (the paste prompt with vertical-specific placeholder copy), loading (extraction in progress — honest skeleton, not a fake spinner), populated (the brief with evidence badges), low-signal (“gửi mẫu chi tiết hơn”), error, no-permission.
- shadcn components:
Textarea,Card,Button,Badge(confidence),Skeleton,Tabs(input kinds). Checkfrontend/src/components/ui/first; no raw Tailwind for UI (Rule 4). - i18n namespace:
chaosImport— keys added to bothen/andvi/(Rule 3), Vietnamese written first per F18. Placeholder copy uses owner vocabulary, not SaaS vocabulary (“Dán đoạn Zalo / Excel đang rối ở đây” — not “Paste your data”). - Mobile-first: the paste, the result, accept/correct, and both CTAs must work well on a phone (strategy §7.3); follow DESIGN.md + TASTE.md pre-flight.
- No abstract AI UI: the result is “việc cần xử lý / khách cần chốt / rủi ro / tin nhắn nên gửi”, not “AI output”. The word “AI” does not appear in the owner-facing brief.
7. Test Plan
| # | Case | Type | Where |
|---|---|---|---|
| 1 | Paste chat → brief with ≥1 evidence-linked commitment | backend | backend/tests/test_api.py::TestChaosImport |
| 2 | Cross-tenant isolation — import + brief scoped to owning org only | backend | backend/tests/test_multitenancy.py |
| 3 | Hallucination guard — no item created without an evidence span | backend | backend/tests/test_api.py::TestChaosImportEvidence |
| 4 | Role — only Owner/Admin can save a brief into the workspace | backend | backend/tests/test_api.py |
| 5 | Low/empty input → guided state, never an invented brief | backend | backend/tests/test_api.py |
| 6 | First-run flow: register → paste → brief → invite-staff CTA | e2e | frontend/tests/e2e/lumi.spec.ts describe("Chaos Import wedge") |
| 7 | Correct an assignee → persists + logged to feedback loop | e2e | same |
Backend coverage ≥99%; new E2E describe block required. Extraction quality is additionally
measured against the field-tests §15 benchmark (100 real samples) — the
G5 gate, tracked separately from unit tests.
8. Current Behavior
The authenticated paste-to-brief orchestration is shipped across the web and KMP surfaces. A tenant
member submits a sufficiently rich sample, run_chaos_import() captures it, extracts grounded
proposals, materializes evidence-linked operational items, assembles a Boss Brief, and exposes
correction, dismissal, save, invite, and F71 handoff paths. The current product boundary is honest:
the authenticated path requires an existing organization, while provisional-org anonymous cold start,
concierge UI, G2 first-session value, G5 real-corpus accuracy, and target-runtime execution remain
open validation work.
9. Error States
- Extraction failure → user-visible
chaosImport.error_extract(“Chưa đọc được mẫu này — thử dán đoạn khác giúp tôi”); offer the concierge fallback; log full context server-side; the input is kept so the owner can retry without re-pasting. - Low confidence / ambiguous → items render under uncertain; never auto-created; no invented dates or assignees.
- Oversized / unsupported input →
chaosImport.error_too_large/error_unsupported; suggest splitting or a different sample kind. - Rate limited (F20) →
chaosImport.error_ratewith retry timing. - Never silently swallow an extraction error or fabricate a brief to fill the screen.
10. Diagrams & Docs Touched
- frontend/DIAGRAMS.md: add
/intel/importto the route tree + first-run flow. - backend/DIAGRAMS.md:
ChaosImportstate machine; request lifecycle for the import → extract → brief pipeline. - GLOSSARY.md: add Chaos Import, Boss Brief, wedge, time-to-first-value.
- DIAGRAMS.md: AI pipeline — show the paste→brief path as the cold-start entry.
- ADR: provisional-org auto-create on first session (see §12).
11. Implementation Audit (2026-06-14 — Updated 2026-06-23)
LLM extraction live; validation gate still open. The wedge now exists as a working authenticated web flow with LLM-powered smart extraction in real mode:
ChaosImportmodel (UUIDModel, org FK, status machine,is_concierge) + migrationrun_chaos_import()service orchestrating: capture_signal → keyword extraction (Commitment/Risk/DecisionRequest each with EvidenceSource) → Brief/BriefItem assemblyChaosImportViewSetwith POST create, GET retrieve,correct_item,dismiss_item,saveactions- Tenant-scoped via
IsOrgMember;saverequiresIsOrgOwnerOrAdmin - Hallucination guard: items only created when keyword patterns match; items with no evidence span never produced
- Confidence honest: 0.65 keyword, never 1.0, never hardcoded
- Low-signal input → ValueError(“low_signal”) → HTTP 400 guided state (no invented brief)
- Cross-tenant isolation: all querysets filtered
organization_id=request.organization_id - Frontend
/intel/importsurface shipped infrontend/src/pages/intel/ChaosImportPage.tsxwith: paste tabs, guided low-signal/error/loading states, evidence-cited brief items, per-item correct + dismiss actions,saveaction, invite-staff CTA, and F71 send-confirmation handoff viaSendConfirmationDialog - Boss Brief result now groups extracted items into the owner-facing sections promised in §2 / §6:
Việc cần xử lý,Cần chốt với bên ngoài,Rủi ro, plusTin nhắn nên gửisuggestions instead of one flat mixed list - Frontend route and sidebar wiring shipped:
frontend/src/routes/routeTree.ts,frontend/src/components/Sidebar.tsx,frontend/src/App.tsx - Unit coverage shipped:
frontend/src/test/ChaosImportPage.test.tsx - Browser E2E shipped:
frontend/tests/e2e/lumi.spec.tsdescribe("Chaos Import wedge") - Deferred per scope decision: provisional-org auto-create on first session — still requires ADR (see §12). POST endpoint requires valid
X-Organization-IDlike every other endpoint. - LLM extraction (real mode):
run_chaos_import()now calls the configured LLM provider with a structured extraction prompt (verbatim evidence spans required, hallucination guard enforced, confidence clamped to [0.85, 0.90]). Extractstaskitems in addition to commitment/risk/decision. Graceful keyword fallback on outage or unparseable response. - F86 (2026-06-24): the chaos LLM + keyword hallucination guards now route through the shared
apps/ai/faithfulness.py::assert_grounded(verbatim span + amount/date/owner cross-check; honest band); producedEvidenceSourcerows carryevidence_span+grounding_verified. See F86. - Still not built: concierge-assisted extraction UI and the anonymous/no-org cold-start promised by the draft wedge ideal. Screenshot/voice-note capture now belongs to and is shipped through F87.
- Acceptance is the G2 gate (real owners want a second use), not a passing test suite alone.
2026-06-25 — Mobile (Compose Multiplatform shared module) implementation
Built the wedge on the shared KMP module so it ships on Android / iOS / Mac from one codebase, mirroring the web behavioral reference and the existing screen/screen-model/repository trio convention (modeled on signalinbox). Scope was android/ only — no backend/frontend changes; backend API unchanged.
- DTOs (
shared/.../api/LumiDtos.kt): addedChaosImportResponse,ChaosImportBriefResponse,ChaosImportItemResponse,ChaosImportEvidenceResponse, plusChaosImportCreateRequest/ChaosImportCorrectRequest/ChaosImportSaveResponse. The chaos brief-item shape is distinct from the dailyBriefItemResponse(carriesdescription/subject_type/subject_idand evidencecontent_text), matchingbackend/apps/chaos/serializers.pyexactly (verified against that file). Per ADR-025 all DTOs live in shared. - API client (
shared/.../api/LumiApiClient.kt): added the 5 calls —chaosImportCreate(POST),chaosImportDetail(GET),chaosImportCorrectItem,chaosImportDismissItem(204 → no body parse),chaosImportSave— each carryingAuthorization+X-Organization-IDvia the shared header helpers. - Repository (
shared/.../presentation/chaosimport/ChaosImportRepository.kt):ChaosImportRepositoryinterface +DefaultChaosImportRepositoryforwarding to the client (test-swappable, mirrorsSignalInboxRepository). - Screen model (
ChaosImportScreenModel.kt):ChaosImportUiStateholds input content +ChaosInputKindtabs (chat_paste / excel_paste / typed_note), submit, 2s status polling whilereceived/extracting(interval injectable for tests), brief item list, optimistic dismiss, correct + save mutations, low-signal (briefedwith zero items → guided state, never an invented brief), andfailed/error-key state with honest error mapping (too_large / rate / extract). - Compose screen (
shared/.../ui/chaosimport/ChaosImportScreen.kt): mirrors the web sections — Action items / Needs external confirmation / Risks / Messages to send — using the samebuildSections/buildSuggestedMessagesgrouping logic; per-item confidence badge (High/Medium/Low + %), verbatim evidence citation, dismiss + save, and an honest skeleton (LumiSkeletonList, not a bare spinner) during extraction. Built entirely from shared Lumi primitives/tokens (no raw colors). - Navigation:
ChaosImportNavKey+entry<ChaosImportNavKey>and a"Chaos Import"workspace-row route inapp/.../ui/LumiApp.kt; model wired inSharedKmpViewModel; tile added to the Intelligence section ofWorkspaceLaneScreen.kt;makeChaosImportViewControllerfactories added to the iOS and macOSMainViewController.kt. - i18n:
chaos_import_*keys added to bothvalues/strings.xml(en) andvalues-vi/strings.xml(vi, written to match the web copy / owner vocabulary). - Tests (
shared/src/commonTest/.../chaosimport/ChaosImportScreenModelTest.kt): 11 cases incl. paste→brief success with evidence carried through, pollingreceived→extracting→briefedtransition, low-signal guided state, backendfailed→ error key, oversized→error_too_large, optimistic dismiss, save, correct, and start-over. - Verification — BLOCKED in this environment.
./gradlew :shared:compileKotlinJvm(and therefore:shared:jvmTest, which runs commonTest) fails at the Gradle configuration phase because the Android Gradle /com.android.lint:9.0.0plugin cannot be fetched — the agent proxy returns403fordl.google.com:443(confirmed via$HTTPS_PROXY/__agentproxy/status), and no AGP artifacts are cached locally (project never built here). This is an environment network restriction, not a code defect; the compile never starts. Code was instead statically reviewed against the existingsignalinboxtrio and the verified component signatures (LumiPageTitle,LumiSectionHeader,LumiCard,LumiStatusBanner,LumiBadge,LumiFilterChip,LumiMultilineField,LumiPrimaryButton, format-argstringResource). A reviewer with Google-repo access must run./gradlew :shared:jvmTestto confirm green. - iOS / Mac shell wiring ✅ done (verified 2026-07-02):
ios/Lumi/UI/MainTabView.swifthascase chaosImport(line 259), aKMPComposeView(screen: .chaosImport, ...)render case (line 720–721), and the workspace-row routingcase "Chaos Import": .push(.chaosImport)(line 799).ios/Lumi/KMP/SharedScreenBridge.swiftalso has the full.chaosImportbranch dispatchingmakeChaosImportViewController.ios/LumiMac/KMP/SharedScreenBridge.swiftmatches on macOS. On-device verification pending (build toolchain not available in agent env) — the routing code is present and code-complete.
12. Open Questions / Decisions
- Provisional org on first session — auto-create a silent org vs a true anonymous/ephemeral trial?
This is a structural tenancy decision and requires an ADR before implementation
(cross-reference F01 §2 org-setup gate and F02).
Deferred per fleet-C scope. The backend POST endpoint requires a valid
X-Organization-IDlike every other endpoint. If the frontend lacks one, it must obtain one first (register → create org → redirect). The no-org path needs the ADR. - Screenshot OCR — which service/model, and does OCR text become its own
EvidenceSource? - Voice-note transcription — source and language handling (defer to F37).
- Confidence floor for auto-create vs uncertain-suggestion — tune against the G5 benchmark.
13. Bug / Change Log
2026-07-28 — Native low-signal feedback is not an application error
The shared mobile submit path treats only the canonical 400 low-signal response as expected
domain feedback. It still renders the guided extraction recovery state, but does not forward that
handled outcome to Sentry. Other 400 responses and unexpected failures remain reportable.
2026-07-02 — Spec drift fix: all 9 §2 ACs marked shipped
Type: Docs
Summary:
- Updated status from
drafttoshipped (web + KMP mobile; G2 gate pending). - Marked all 9 §2 acceptance criteria
[x]— each confirmed implemented per the §11 Implementation Audit (2026-06-14 through 2026-06-25 entries). - No code changed; documentation only.
Evidence mapping:
- AC1 (paste → sections): §11 — “Boss Brief result now groups extracted items into the owner-facing sections promised in §2 / §6”
- AC2 (commitment + citation): §11 — “LLM extracts … verbatim evidence spans required, hallucination guard enforced”
- AC3 (low-signal guided state): §11 — “ValueError(‘low_signal’) → HTTP 400 guided state (no invented brief)”
- AC4 (EvidenceSource on every item): §11 — “items only created when keyword patterns match; items with no evidence span never produced”
- AC5 (uncertain items visible, not hidden): §11 — “confidence badges with % shown” / KMP screen: “per-item confidence badge (High/Medium/Low + %)”
- AC6 (correction persists): §11 — “
correct_itemaction on ViewSet + frontend” - AC7 (dismiss → gone): §11 — “
dismiss_itemaction” / KMP: “optimistic dismiss” - AC8 (invite-staff CTA): §11 — “invite-staff CTA” explicitly shipped on
/intel/import - AC9 (F71 handoff): §11 — “F71 send-confirmation handoff via
SendConfirmationDialog”
Still open: G2 field-test gate (real owners), provisional-org ADR, screenshot/voice-note upload path, concierge-assisted extraction UI.
2026-06-23 — LLM extraction path (truly smart wedge)
Type: Enhancement
Summary:
- Replaced pure keyword extraction with an LLM-first extraction path in
run_chaos_import()whenLLM_PROVIDER != 'mock'. - The LLM call uses
build_system_prompt(member, "extraction")+ a structured prompt demanding verbatimevidence_spanquotes per item. - Supports all four entity types the wedge can surface:
task,commitment,risk,decision— not just the three keyword-detectable types. - Honest confidence: all LLM-reported confidence values are clamped to [0.85, 0.90]; never 1.0, never fabricated.
- Hallucination guard: items are kept only when
evidence_spanis a verbatim substring of the source — unsourced items are dropped with a warning log. - Graceful fallback:
LLMProviderError, malformed JSON, or an empty LLM item list all fall back to deterministic keyword extraction — never a dead screen, never a fabricated brief. - Mock mode (
LLM_PROVIDER=mock) is unchanged and remains the test default. - 6 new
TestChaosImportLLMtests covering: multi-item extraction with tasks, confidence clamping, hallucination guard, provider outage fallback, malformed JSON fallback, empty-items fallback. - Full suite: 3870 passed, chaos coverage 97%.
2026-06-18 — Boss Brief sections rendered as owner-facing groups
Type: UX correction
Summary:
- Changed the populated
/intel/importBoss Brief result from one flat mixed list into the sectioned owner view promised by the spec:Việc cần xử lý,Cần chốt với bên ngoài,Rủi ro, andTin nhắn nên gửi.
Reason:
- The backend extraction and first-run loop already existed, but the rendered brief still buried the wedge’s core promise inside an undifferentiated list. That was weaker than §2’s acceptance contract and less useful for a contractor owner scanning the page on a phone.
Impact:
- Existing extracted items are now grouped by action / external sign-off / risk intent using the current item metadata; no API contract changed.
- Suggested confirmation-ready items now also surface again under
Tin nhắn nên gửi, which is intentional duplication of the action surface, not a second extracted object.
Tests:
pnpm --dir frontend exec vitest run src/test/ChaosImportPage.test.tsx --pool=forks --poolOptions.forks.maxForks=1pnpm --dir frontend exec tsc --noEmit
Notes:
- This improves web implementation honesty. It does not close the G2 validation gate or the deferred provisional-org ADR.
2026-06-15 — Frontend route namespaced
Frontend route namespaced: /start (authenticated import) -> /intel/import (app-wide IA restructure; public marketing /start and API paths unchanged).
2026-06-14 — Spec created (wedge crystallized from strategy v2)
Type: Feature
Summary:
- Created F70 to give the strategy’s wedge — “Chaos Import → Boss Brief” — a single home. Previously its components were scattered across F32/F08/F34/F12/F52 with no zero-setup first-session flow.
Reason:
- competitive-strategy-v2.md and field-tests.md §20 name this the single highest-priority surface and “the only product spec allowed before evidence.” The spec set had no entry for it — the largest gap between strategy and specs. Scope change authorized by the session goal (read strategy → upgrade specs to serve the mission).
Impact:
- New draft feature F70 in the registry at status
🔲 Not started. Tenancy-sensitive (provisional org) and validation-gated (G2/G5). No code shipped by this spec.
Tests:
- Test plan defined (§7); not yet implemented.
Notes:
- Build concierge-first. Do not mark shipped until field-test G2 passes with real contractor owners.
2026-06-15 — Backend implementation (fleet-C r29, agent C)
Type: Implementation
Summary:
- Built
apps/chaosDjango app: model, service, views, serializers, URLs, migration, 16 tests. - Registered app in
config/settings/base.py, URLs inconfig/urls.pyunder/api/chaos-import/.
Scope decision obeyed:
- Authenticated member with EXISTING org only. No provisional-org auto-create (deferred, requires ADR).
- POST requires
X-Organization-ID. No anonymous/zero-org path.
Reason:
- fleet-C task scope: backend only. Frontend agent B handles the
/startsurface. - Provisional org needs an ADR before implementation — spec §12 acknowledges this.
Impact:
- Registry status: Backend ✅, Frontend 🔲, E2E 🔲, iOS 🔲, Android 🔲, Mac 🔲.
- Content > 100K chars → HTTP 400
chaosImport.error_too_large. - Empty/too-short content → HTTP 400
chaosImport.error_low_signal. No ChaosImport or Brief created. - Cross-tenant retrieve/save/dismiss/correct → HTTP 404 (not 403 — no existence confirmation).
saveaction → HTTP 403 for non-Owner/Admin roles.
Tests:
- 16 new tests in
tests/test_chaos.pycovering: paste→brief with evidence-linked items, hallucination guard, confidence never 1.0, role-based save, low-signal rejection, cross-tenant isolation (retrieve/save/dismiss/correct). - Full gate: 2620 tests passed, 99.19% coverage.
Notes:
- Backend does not touch frontend/. All cross-edit requests noted in fleet-C report.
2026-06-17 — Web completion slice (owner control loop + real F71 handoff)
Type: Implementation
Summary:
- Finished the missing owner-control loop on the existing
/intel/importsurface: extracted brief items can now be corrected, dismissed, and saved from the page itself. - Replaced the dead-end confirmation CTA with the actual F71
SendConfirmationDialog, wired from the real extracted subject ids. - Tightened the wedge browser tests to match the shipped extractor contract and locator surface.
Reason:
- The route and page already existed, but the surface still broke two core promises in §2: the owner could not truly correct/reject extracted items from the wedge page, and the “send confirmation” CTA did not enter the F71 loop.
Impact:
- Registry truth changed from backend-only to web-implemented: Backend ✅, Frontend ✅, E2E ✅ while overall feature status remains validation-gated until G2.
Tests:
backend/.venv/bin/python -m pytest tests/test_chaos.py -qpnpm --dir frontend exec vitest run src/test/ChaosImportPage.test.tsxpnpm --dir frontend exec tsc --noEmitpnpm --dir frontend exec playwright test tests/e2e/lumi.spec.ts -g "Chaos Import wedge" --project=chromium
Notes:
- This does not resolve the provisional-org ADR or make F70 field-validated. It makes the shipped web implementation honest.