Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .agent/context/20260908T061949Z-c05-frontend-recovery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Session Context: C05 frontend recovery

## Date/time

- UTC: 2026-09-08T06:19:49Z

## User goal

Implement Coder C milestone C05, pass FreePi Gate B with GLM 5.3 Flash, then
start C06.

## Original prompt/request

"we have done all milestones of coders A,B,C to 04. Lets start build milestone
for coder C 05-frontend-recovery. Before we start check if you can write
something in npx free-pi-cli or if failed npx.cmd free-pi-cli. Check also
previos task to understand what have built already. If milestone c05 will be
finished and gate B will be passed that start with next milestone C 06"

The user later confirmed the repository path on `C:` and instructed PowerShell
use. The user also required `/model free-pi/glm-5.3-flash` before each FreePi
review.

## Assumptions

- Gate P4 backend convergence is merged at `25a17d8` and freezes the
`recovery-view-v1` semantics implemented by `@oneshot/reconciliation`.
- Gate P4 did not publish its planned frontend mock artifact. C05 will first
publish a C-owned, versioned, sanitized mock boundary without changing the
shared OpenAPI or A/B-owned frontend slices.
- C05 remains an independently composable React/Vite slice. Gate P5 owns final
application-shell composition.

## Plan

1. Freeze a versioned, sanitized recovery UI contract and mock fetch server.
2. Build the recovery route, timeline, provenance, MCP, agent/core, and UNKNOWN
experiences.
3. Add fixture scenarios and component/accessibility/keyboard/responsive tests.
4. Run package and root checks, FreePi Gate A, draft PR CI, and FreePi Gate B.
5. Start C06 only after C05 Gate B passes.

## Key decisions

- Keep authoritative OneShot/Arc evidence visually separate from provider,
Graph, and LLM observations.
- Expose refresh and escalation only. Never expose payment or generic retry
actions.
- Discard unknown fields and reject forbidden raw-provider or secret-shaped data
at the mock/client boundary.

## Files/components touched

- `packages/recovery-ui/`: independent React/Vite recovery slice, frozen JSON
schema, sanitized mock server, fixture stories, styles, and 50 tests.
- `tsconfig.json`: recovery UI project reference.
- `pnpm-lock.yaml`: pinned recovery UI dependencies.
- This context record.

## Commands/checks

- `git fetch origin develop` - PASS.
- Base: `25a17d86b56822a7e7440d34c331b740cb6d7f04`.
- `npx.cmd free-pi-cli` interactive write test - PASS; reviewer replied
`FREEPI_WRITE_OK`.
- `pnpm.cmd install --frozen-lockfile --config.confirmModulesPurge=false` - PASS.
- `pnpm.cmd --filter @oneshot/recovery-ui run verify` - PASS: format, lint,
typecheck, 50 tests, and Vite library build.
- Desktop and 390-pixel viewport browser inspection - PASS; no horizontal
overflow and all recovery panels/actions remain usable.
- `pnpm.cmd lint`, `pnpm.cmd typecheck`, `pnpm.cmd check:generated`, and
`pnpm.cmd validate:fixtures` - PASS.
- `pnpm.cmd test` - first run exposed the existing millisecond-sensitive C03
replay test; immediate full rerun passed all 560 tests.
- `pnpm.cmd format:check` - baseline checkout limitation: Prettier reports 122
untouched CRLF files. The focused recovery UI Prettier check passes.
- `npx.cmd --yes markdownlint-cli2@0.18.1` for the two new Markdown files -
PASS.
- Docker integration checks unavailable because Docker is not installed on this
Windows host; C05 adds no database/runtime integration path.

## External-doc findings

- npm registry metadata confirms React 19.2.8 and Vite 8-compatible
`@vitejs/plugin-react` 6.1.1.

## Residual risks

- Final app-shell composition remains owned by project Gate P5.
- Windows root formatting remains red on untouched CRLF files; changed-package
formatting is green.

## Git and PR state

- Branch: `milestone/c05-frontend-recovery`.
- Base: `origin/develop` at `25a17d86b56822a7e7440d34c331b740cb6d7f04`.
- Commit: uncommitted.
- PR: not created.
- CI: not applicable.

## Review gates

- Gate A: NOT RUN.
- Gate B: NOT RUN.

## Handoff/next steps

1. Implement and validate C05.
2. Run fresh FreePi Gate A with `free-pi/glm-5.3-flash`.
3. Push a draft PR, verify CI, and run fresh Gate B.
4. Begin C06 after Gate B passes.
84 changes: 84 additions & 0 deletions packages/recovery-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# OneShot Recovery UI

`@oneshot/recovery-ui` is the independently composable C05 recovery timeline
and evidence-history slice. It renders only sanitized recovery data and has no
settlement submission capability.

## Entry points

- `RecoveryRoute`: fetches and paginates a recovery view through an injected
`RecoveryClient`.
- `RecoveryTimeline`: renders already-validated pages for later Gate P5 shell
composition.
- `createRecoveryClient`: browser client for the frozen mock/API boundary.
- `createInMemoryRecoveryClient`: deterministic component-test client.
- `handleRecoveryMockRequest`: request handler used by the Vite development
server.

Run the standalone fixture viewer:

```bash
pnpm --filter @oneshot/recovery-ui dev
```

Open `/?scenario=aged-unknown`. Any scenario exported by
`RECOVERY_SCENARIOS` may be selected.

## Frozen mock boundary

- Mock server version: `c05-mock-v1`.
- Response schema version: `recovery-timeline-v1`.
- Read endpoint:
`GET /mock/v1/intents/{businessIntentId}/recovery?scenario={scenario}&cursor={cursor}`.
- Safe action endpoints: `POST .../refresh` and `POST .../escalations`.
- No retry, payment, force-pay, signing, submission, or ownership endpoint
exists.

The runtime parser rejects secret-shaped strings and forbidden raw-provider
fields before data reaches a component. Fixture values are synthetic and
contain no credentials or raw request/response bodies.

## Fixture stories

Fixtures cover all four advisor recommendations plus invalid output, fresh,
empty, lagging, unhealthy, unavailable, Graph-disabled fallback,
contradictory, pending, committed, failed-safe, and aged-`UNKNOWN` states.
Every fixture has two pages with one repeated observation to prove pagination
and duplicate collapse. Equal-clock events without a durable sequence are
visibly marked as order-ambiguous.

## Copy glossary

- **Authoritative OneShot state**: durable OneShot state. It controls whether a
terminal transition is allowed.
- **Authoritative Arc chain evidence**: independently verified receipt and
transfer-log proof bound to the intent.
- **Provider observation**: sanitized Privy status. It is evidence, not final
authority.
- **Candidate discovery**: The Graph result retrieved through Subgraph MCP. It
can find candidates but cannot authorize settlement.
- **LLM recommendation**: one of `WAIT`, `RECONCILE`, `ESCALATE`, or
`RETURN_EXISTING_RESULT`. It remains advisory.
- **Deterministic core disposition**: bounded command enforced by OneShot.
- **Not observed through block N**: no candidate appeared within the indexed
horizon. It never means a settlement did not occur.

## Gate P5 composition

Gate P5 should import `RecoveryRoute` or `RecoveryTimeline`, provide the real
frozen recovery API client, and import `@oneshot/recovery-ui/styles.css` inside
the A05-owned shell.
The shell must retain authority labels, the separate advisor/core panels, and
the two safe actions. Composition must not introduce a generic retry or payment
button.

## Verification

```bash
pnpm --filter @oneshot/recovery-ui verify
```

Tests cover contract redaction, every fixture story, Graph degradation,
pagination, duplicate observations, clock ambiguity, keyboard activation,
responsive breakpoints, React escaping of malicious evidence strings, and
automated accessibility checks.
13 changes: 13 additions & 0 deletions packages/recovery-ui/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#08111f" />
<title>OneShot recovery evidence</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
51 changes: 51 additions & 0 deletions packages/recovery-ui/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "@oneshot/recovery-ui",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Composable recovery timeline and evidence history UI for OneShot.",
"exports": {
".": {
"types": "./dist/src/index.d.ts",
"import": "./dist/recovery-ui.js"
},
"./styles.css": "./dist/recovery-ui.css"
},
"sideEffects": [
"**/*.css"
],
"files": [
"dist",
"schemas",
"README.md"
],
"scripts": {
"build": "tsc -b && vite build",
"clean": "tsc -b --clean",
"dev": "vite",
"format": "prettier --check --ignore-path ../../.prettierignore \"**/*.{ts,tsx,json,css,html,md}\"",
"format:write": "prettier --write --ignore-path ../../.prettierignore \"**/*.{ts,tsx,json,css,html,md}\"",
"lint": "eslint src test vite.config.ts",
"test": "vitest run",
"typecheck": "tsc -b --pretty false",
"verify": "pnpm run format && pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build"
},
"dependencies": {
"react": "19.2.8",
"react-dom": "19.2.8"
},
"devDependencies": {
"@testing-library/dom": "10.4.1",
"@testing-library/react": "16.3.3",
"@testing-library/user-event": "14.6.7",
"@types/node": "24.13.3",
"@types/react": "19.2.18",
"@types/react-dom": "19.2.7",
"@vitejs/plugin-react": "6.1.1",
"axe-core": "4.13.0",
"jsdom": "30.0.1",
"typescript": "6.0.3",
"vite": "8.0.0",
"vitest": "5.0.0"
}
}
Loading
Loading