Skip to content

Commit 0ec8a77

Browse files
hyperpolymathclaude
andcommitted
feat(frontend): conversational errors + STATUS.md truth-alignment
Conversational error system (UX Manifesto Rule 4): - New ConversationalError.res component: icon + title + reason + [Fix It] buttons (max 3 per manifesto). Severity variants (Critical/Warning/Info) with colour-coded borders. - Active errors rendered above content area in App.res - All API error paths now surface user-facing errors: - Import failures → "Try a different file" - Save failures → "Try again" - Security scan failures → "Run again" - Gap analysis failures → "Run again" - DismissError and RetryImport messages for error lifecycle - Model.activeErrors tracks visible errors; Model.userError type STATUS.md truth-alignment (TSDM Workstream 5): - Updated date to 2026-03-23 - Documented all 3 meander session additions (Pipeline Designer, URL routing, undo/redo, auto-save, dark mode, conversational errors) - Updated "8 views" → "9 views (51 modules)" - Moved dark mode from "Partial" to "Works" - Corrected security views status (fully implemented views, not stubs, but still displaying sample data rather than live validation) Clean build: 51 modules, 0 errors, 0 warnings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 71a52e6 commit 0ec8a77

10 files changed

Lines changed: 786 additions & 78 deletions

File tree

STATUS.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
11
# stapeln Status (Source of Truth)
22

3-
**Date:** 2026-03-10
3+
**Date:** 2026-03-23
44

55
## Product Goal
66

77
A reasonably IT-capable 12-year-old can help their parents build a secure container stack without prior container knowledge.
88

99
## What Works Today
1010

11-
- **UI Prototype (frontend):** 8 views implemented as ReScript modules in `frontend/src/`.
12-
- **TEA Architecture:** State, Msg, Update, View pattern in place via AppIntegrated.res.
13-
- **Security UX Components:** Port config, security inspector, gap analysis, simulation mode modules exist.
14-
- **Import/Export Hooks:** Buttons exist (not wired to durable storage).
11+
- **UI Prototype (frontend):** 9 views (51 ReScript modules) in `frontend/src/`, all compiling with 0 errors/warnings.
12+
- **TEA Architecture:** State, Msg, Update, View pattern in App.res. AppIntegrated.res exists as legacy alternative.
13+
- **Pipeline Designer (new):** Full 3-panel node-graph editor (PipelineDesigner, PipelineCanvas, PipelinePalette, PipelineOutput) with SVG canvas, bezier connections, minimap, context menus, drag-drop, 6 pre-built templates, code generation preview.
14+
- **URL-based routing:** AppRouter.res syncs tabs with browser URLs; back/forward navigation works.
15+
- **Undo/redo system:** Snapshot-based with 50-depth cap, Ctrl+Z/Ctrl+Y, visible buttons with disabled state.
16+
- **Auto-save:** 30-second interval with dirty tracking and visual "Saved"/"Unsaved" indicator.
17+
- **Dark mode:** System detection (prefers-color-scheme), localStorage persistence, HTML class sync for Tailwind.
18+
- **Conversational errors:** UX Manifesto Rule 4 pattern (title + reason + [Fix It] buttons) on all API error paths.
19+
- **Import/Export:** Working file picker → TEA dispatch cycle. Import errors show conversational fix suggestions.
20+
- **Security UX Components:** Port config (1,165 lines), security inspector (832 lines), gap analysis (951 lines), simulation mode (1,622 lines) — all fully implemented views, not stubs.
1521
- **Backend API (MVP):** Phoenix REST endpoints for stacks and validation are defined.
1622
- **GraphQL API (MVP):** Absinthe schema at `/api/graphql` is defined.
1723
- **Shared API Boundary:** REST/GraphQL route through `backend/lib/stapeln/native_bridge.ex`.
18-
- **ABI/FFI Contract:** Idris2 ABI (`src/abi/*`) has 8 genuine proofs (no believe_me). Zig FFI (`ffi/zig/src/main.zig`) provides CRUD + validate + dispatch.
24+
- **ABI/FFI Contract:** Idris2 ABI (`src/abi/*`) has 8 genuine proofs (no believe_me). Zig FFI (`ffi/zig/src/main.zig`) provides CRUD + validate + dispatch. Real SHA-256 + Ed25519 in `crypto.zig`.
1925
- **VeriSimDB Integration:** Remote client with JSONL local fallback, configurable timeouts.
2026
- **Runtime Boundary:** `stapeln/backend` is the design/control plane. Container lifecycle orchestration is delegated to `container-stack/svalinn` and `container-stack/vordr`.
2127

2228
## What Is Partial or Scaffolded
2329

24-
- **Dark mode:** Hardcoded to `false` in StackView.res; AppIntegrated passes `isDark` but StackView ignores it.
30+
- **Security views display sample data:** SecurityInspector and GapAnalysis render hardcoded demo data, not live validation results from the backend.
2531
- **WebSocket integration:** Socket.res exists but no live channel push/receive logic.
2632
- **Auth:** JWT + Plug module present but no token refresh, revocation, or session management.
2733
- **Firewall:** Schema exists but no nftables integration.
2834
- **Database:** Ecto schemas and conditional Repo present but no migrations.
2935
- **Post-Quantum Crypto:** Module scaffolded; no real XMSS implementation.
30-
- **Simulation:** Packet flow UI renders but no real backend simulation engine.
36+
- **Simulation:** Packet flow UI fully renders with animation and stats but no real backend simulation engine.
3137

3238
## Preserved Future Work
3339

frontend/src/App.res

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ let make = () => {
256256
})
257257
}
258258

259-
| TriggerImportDesign => {
259+
| TriggerImportDesign | RetryImport => {
260260
// Side effect: open file picker, dispatch result back through TEA
261261
Import.triggerImport(
262262
importedModel => dispatch(ImportDesignSuccess(importedModel)),
@@ -455,6 +455,41 @@ let make = () => {
455455
</div>
456456
</nav>
457457

458+
// Active errors (UX Manifesto Rule 4: conversational with [Fix It] buttons)
459+
{Array.length(state.model.activeErrors) > 0
460+
? <div
461+
style={Sx.make(~padding="12px 16px", ~background="#0d1117", ())}
462+
role="alert"
463+
ariaLive=#polite
464+
>
465+
{state.model.activeErrors
466+
->Array.map(err => {
467+
let fixes = switch err.fixLabel {
468+
| Some(label) => {
469+
let action = switch err.title {
470+
| t if String.includes(t, "import") => () => dispatch(RetryImport)
471+
| t if String.includes(t, "save") => () => dispatch(SaveStack)
472+
| t if String.includes(t, "Security") => () => dispatch(RunSecurityScan)
473+
| t if String.includes(t, "Gap") => () => dispatch(RunGapAnalysis)
474+
| _ => () => dispatch(DismissError(err.id))
475+
}
476+
[ConversationalError.primaryFix(label, action)]
477+
}
478+
| None => []
479+
}
480+
<ConversationalError
481+
key={err.id}
482+
title={err.title}
483+
reason=?{err.reason}
484+
severity={err.severity}
485+
fixes
486+
onDismiss={() => dispatch(DismissError(err.id))}
487+
/>
488+
})
489+
->React.array}
490+
</div>
491+
: React.null}
492+
458493
<div className="content">
459494
{switch state.currentPage {
460495
| NetworkView => TopologyView.view(state.model, state.isDark, dispatch)

frontend/src/App.res.js

Lines changed: 51 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)