Skip to content

Commit cf0b79b

Browse files
committed
feat(recovery-ui): add frontend recovery timeline
1 parent 25a17d8 commit cf0b79b

25 files changed

Lines changed: 3590 additions & 2 deletions
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Session Context: C05 frontend recovery
2+
3+
## Date/time
4+
5+
- UTC: 2026-09-08T06:19:49Z
6+
7+
## User goal
8+
9+
Implement Coder C milestone C05, pass FreePi Gate B with GLM 5.3 Flash, then
10+
start C06.
11+
12+
## Original prompt/request
13+
14+
"we have done all milestones of coders A,B,C to 04. Lets start build milestone
15+
for coder C 05-frontend-recovery. Before we start check if you can write
16+
something in npx free-pi-cli or if failed npx.cmd free-pi-cli. Check also
17+
previos task to understand what have built already. If milestone c05 will be
18+
finished and gate B will be passed that start with next milestone C 06"
19+
20+
The user later confirmed the repository path on `C:` and instructed PowerShell
21+
use. The user also required `/model free-pi/glm-5.3-flash` before each FreePi
22+
review.
23+
24+
## Assumptions
25+
26+
- Gate P4 backend convergence is merged at `25a17d8` and freezes the
27+
`recovery-view-v1` semantics implemented by `@oneshot/reconciliation`.
28+
- Gate P4 did not publish its planned frontend mock artifact. C05 will first
29+
publish a C-owned, versioned, sanitized mock boundary without changing the
30+
shared OpenAPI or A/B-owned frontend slices.
31+
- C05 remains an independently composable React/Vite slice. Gate P5 owns final
32+
application-shell composition.
33+
34+
## Plan
35+
36+
1. Freeze a versioned, sanitized recovery UI contract and mock fetch server.
37+
2. Build the recovery route, timeline, provenance, MCP, agent/core, and UNKNOWN
38+
experiences.
39+
3. Add fixture scenarios and component/accessibility/keyboard/responsive tests.
40+
4. Run package and root checks, FreePi Gate A, draft PR CI, and FreePi Gate B.
41+
5. Start C06 only after C05 Gate B passes.
42+
43+
## Key decisions
44+
45+
- Keep authoritative OneShot/Arc evidence visually separate from provider,
46+
Graph, and LLM observations.
47+
- Expose refresh and escalation only. Never expose payment or generic retry
48+
actions.
49+
- Discard unknown fields and reject forbidden raw-provider or secret-shaped data
50+
at the mock/client boundary.
51+
52+
## Files/components touched
53+
54+
- `packages/recovery-ui/`: independent React/Vite recovery slice, frozen JSON
55+
schema, sanitized mock server, fixture stories, styles, and 50 tests.
56+
- `tsconfig.json`: recovery UI project reference.
57+
- `pnpm-lock.yaml`: pinned recovery UI dependencies.
58+
- This context record.
59+
60+
## Commands/checks
61+
62+
- `git fetch origin develop` - PASS.
63+
- Base: `25a17d86b56822a7e7440d34c331b740cb6d7f04`.
64+
- `npx.cmd free-pi-cli` interactive write test - PASS; reviewer replied
65+
`FREEPI_WRITE_OK`.
66+
- `pnpm.cmd install --frozen-lockfile --config.confirmModulesPurge=false` - PASS.
67+
- `pnpm.cmd --filter @oneshot/recovery-ui run verify` - PASS: format, lint,
68+
typecheck, 50 tests, and Vite library build.
69+
- Desktop and 390-pixel viewport browser inspection - PASS; no horizontal
70+
overflow and all recovery panels/actions remain usable.
71+
- `pnpm.cmd lint`, `pnpm.cmd typecheck`, `pnpm.cmd check:generated`, and
72+
`pnpm.cmd validate:fixtures` - PASS.
73+
- `pnpm.cmd test` - first run exposed the existing millisecond-sensitive C03
74+
replay test; immediate full rerun passed all 560 tests.
75+
- `pnpm.cmd format:check` - baseline checkout limitation: Prettier reports 122
76+
untouched CRLF files. The focused recovery UI Prettier check passes.
77+
- `npx.cmd --yes markdownlint-cli2@0.18.1` for the two new Markdown files -
78+
PASS.
79+
- Docker integration checks unavailable because Docker is not installed on this
80+
Windows host; C05 adds no database/runtime integration path.
81+
82+
## External-doc findings
83+
84+
- npm registry metadata confirms React 19.2.8 and Vite 8-compatible
85+
`@vitejs/plugin-react` 6.1.1.
86+
87+
## Residual risks
88+
89+
- Final app-shell composition remains owned by project Gate P5.
90+
- Windows root formatting remains red on untouched CRLF files; changed-package
91+
formatting is green.
92+
93+
## Git and PR state
94+
95+
- Branch: `milestone/c05-frontend-recovery`.
96+
- Base: `origin/develop` at `25a17d86b56822a7e7440d34c331b740cb6d7f04`.
97+
- Commit: uncommitted.
98+
- PR: not created.
99+
- CI: not applicable.
100+
101+
## Review gates
102+
103+
- Gate A: NOT RUN.
104+
- Gate B: NOT RUN.
105+
106+
## Handoff/next steps
107+
108+
1. Implement and validate C05.
109+
2. Run fresh FreePi Gate A with `free-pi/glm-5.3-flash`.
110+
3. Push a draft PR, verify CI, and run fresh Gate B.
111+
4. Begin C06 after Gate B passes.

‎packages/recovery-ui/README.md‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# OneShot Recovery UI
2+
3+
`@oneshot/recovery-ui` is the independently composable C05 recovery timeline
4+
and evidence-history slice. It renders only sanitized recovery data and has no
5+
settlement submission capability.
6+
7+
## Entry points
8+
9+
- `RecoveryRoute`: fetches and paginates a recovery view through an injected
10+
`RecoveryClient`.
11+
- `RecoveryTimeline`: renders already-validated pages for later Gate P5 shell
12+
composition.
13+
- `createRecoveryClient`: browser client for the frozen mock/API boundary.
14+
- `createInMemoryRecoveryClient`: deterministic component-test client.
15+
- `handleRecoveryMockRequest`: request handler used by the Vite development
16+
server.
17+
18+
Run the standalone fixture viewer:
19+
20+
```bash
21+
pnpm --filter @oneshot/recovery-ui dev
22+
```
23+
24+
Open `/?scenario=aged-unknown`. Any scenario exported by
25+
`RECOVERY_SCENARIOS` may be selected.
26+
27+
## Frozen mock boundary
28+
29+
- Mock server version: `c05-mock-v1`.
30+
- Response schema version: `recovery-timeline-v1`.
31+
- Read endpoint:
32+
`GET /mock/v1/intents/{businessIntentId}/recovery?scenario={scenario}&cursor={cursor}`.
33+
- Safe action endpoints: `POST .../refresh` and `POST .../escalations`.
34+
- No retry, payment, force-pay, signing, submission, or ownership endpoint
35+
exists.
36+
37+
The runtime parser rejects secret-shaped strings and forbidden raw-provider
38+
fields before data reaches a component. Fixture values are synthetic and
39+
contain no credentials or raw request/response bodies.
40+
41+
## Fixture stories
42+
43+
Fixtures cover all four advisor recommendations plus invalid output, fresh,
44+
empty, lagging, unhealthy, unavailable, Graph-disabled fallback,
45+
contradictory, pending, committed, failed-safe, and aged-`UNKNOWN` states.
46+
Every fixture has two pages with one repeated observation to prove pagination
47+
and duplicate collapse. Equal-clock events without a durable sequence are
48+
visibly marked as order-ambiguous.
49+
50+
## Copy glossary
51+
52+
- **Authoritative OneShot state**: durable OneShot state. It controls whether a
53+
terminal transition is allowed.
54+
- **Authoritative Arc chain evidence**: independently verified receipt and
55+
transfer-log proof bound to the intent.
56+
- **Provider observation**: sanitized Privy status. It is evidence, not final
57+
authority.
58+
- **Candidate discovery**: The Graph result retrieved through Subgraph MCP. It
59+
can find candidates but cannot authorize settlement.
60+
- **LLM recommendation**: one of `WAIT`, `RECONCILE`, `ESCALATE`, or
61+
`RETURN_EXISTING_RESULT`. It remains advisory.
62+
- **Deterministic core disposition**: bounded command enforced by OneShot.
63+
- **Not observed through block N**: no candidate appeared within the indexed
64+
horizon. It never means a settlement did not occur.
65+
66+
## Gate P5 composition
67+
68+
Gate P5 should import `RecoveryRoute` or `RecoveryTimeline`, provide the real
69+
frozen recovery API client, and import `@oneshot/recovery-ui/styles.css` inside
70+
the A05-owned shell.
71+
The shell must retain authority labels, the separate advisor/core panels, and
72+
the two safe actions. Composition must not introduce a generic retry or payment
73+
button.
74+
75+
## Verification
76+
77+
```bash
78+
pnpm --filter @oneshot/recovery-ui verify
79+
```
80+
81+
Tests cover contract redaction, every fixture story, Graph degradation,
82+
pagination, duplicate observations, clock ambiguity, keyboard activation,
83+
responsive breakpoints, React escaping of malicious evidence strings, and
84+
automated accessibility checks.

‎packages/recovery-ui/index.html‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta name="theme-color" content="#08111f" />
7+
<title>OneShot recovery evidence</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

‎packages/recovery-ui/package.json‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "@oneshot/recovery-ui",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"description": "Composable recovery timeline and evidence history UI for OneShot.",
7+
"exports": {
8+
".": {
9+
"types": "./dist/src/index.d.ts",
10+
"import": "./dist/recovery-ui.js"
11+
},
12+
"./styles.css": "./dist/recovery-ui.css"
13+
},
14+
"sideEffects": [
15+
"**/*.css"
16+
],
17+
"files": [
18+
"dist",
19+
"schemas",
20+
"README.md"
21+
],
22+
"scripts": {
23+
"build": "tsc -b && vite build",
24+
"clean": "tsc -b --clean",
25+
"dev": "vite",
26+
"format": "prettier --check --ignore-path ../../.prettierignore \"**/*.{ts,tsx,json,css,html,md}\"",
27+
"format:write": "prettier --write --ignore-path ../../.prettierignore \"**/*.{ts,tsx,json,css,html,md}\"",
28+
"lint": "eslint src test vite.config.ts",
29+
"test": "vitest run",
30+
"typecheck": "tsc -b --pretty false",
31+
"verify": "pnpm run format && pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build"
32+
},
33+
"dependencies": {
34+
"react": "19.2.8",
35+
"react-dom": "19.2.8"
36+
},
37+
"devDependencies": {
38+
"@testing-library/dom": "10.4.1",
39+
"@testing-library/react": "16.3.3",
40+
"@testing-library/user-event": "14.6.7",
41+
"@types/node": "24.13.3",
42+
"@types/react": "19.2.18",
43+
"@types/react-dom": "19.2.7",
44+
"@vitejs/plugin-react": "6.1.1",
45+
"axe-core": "4.13.0",
46+
"jsdom": "30.0.1",
47+
"typescript": "6.0.3",
48+
"vite": "8.0.0",
49+
"vitest": "5.0.0"
50+
}
51+
}

0 commit comments

Comments
 (0)