update spec workflow to use repo-canonical two-layer model (#1865)

* update skills

* fixes and formatting
This commit is contained in:
Justin Hernandez
2026-03-24 13:42:19 -07:00
committed by GitHub
parent 89476718eb
commit 692aaf33dc
9 changed files with 140 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
---
name: spec-from-audit
description: Generate one Linear spec document per issue — agent-executable implementation plans with file paths, validation commands, and acceptance criteria.
description: Generate one spec per issue — repo file (canonical) + Linear document (mirror). Agent-executable implementation plans with file paths, validation commands, and acceptance criteria.
disable-model-invocation: false
user-invocable: true
argument-hint: '[issue IDs or path-to-audit-doc]'
@@ -8,7 +8,7 @@ argument-hint: '[issue IDs or path-to-audit-doc]'
# Spec from Audit
You take Linear issues (created by `/gaps-to-issues`) and generate one spec per issue as a Linear document. Each spec is an agent-executable implementation plan — a new Claude Code session with no prior context should be able to pick up the spec and produce a correct PR.
You take Linear issues (created by `/gaps-to-issues`) and generate one spec per issue. Each spec is written to the repo (`specs/`) as the canonical version, then mirrored to a Linear document for cross-tool access. A new Claude Code session with no prior context should be able to pick up the repo spec and produce a correct PR.
## Input
@@ -35,9 +35,10 @@ Do not guess file contents — read them. Specs with wrong line numbers or stale
### Step 3: Generate Specs
For each issue, create a spec as a Linear document using `mcp__linear-server__create_document`.
For each issue, write the spec to **both** locations:
Link the document to the **issue** (not the project).
1. **Repo file** — Write to `specs/projects/sdk/workstreams/<scope>/plans/<ID>-<slug>.md` using the Write tool. Determine `<scope>` from the workstream the issue belongs to (e.g., `webview`, `sdk-core`, `build-pipeline`). Always create or update the backlog row in the workstream's `SPEC.md` — if `SPEC.md` doesn't exist yet, create it.
2. **Linear document** — Create using `mcp__linear-server__create_document`, linked to the **issue** (not the project). This is the cross-tool access copy.
**Title format:** `SPEC: <issue title>`
@@ -133,4 +134,5 @@ Show the user:
- If you discover the issue description is wrong (e.g., the code was already fixed), note this and ask the user whether to still create the spec or update the issue.
- Specs are for agents, not humans. Write them as precise instructions, not explanatory documents.
- The spec is the source of truth, not the issue body. Issue bodies are lightweight pointers — the spec must be fully self-contained. Do not assume the agent has read the issue description.
- Link specs to issues (not projects). Use `mcp__linear-server__create_document` with the `issue` parameter.
- The repo file (`specs/`) is the canonical version. The Linear document is a copy for cross-tool access. Both should have identical content.
- Link Linear documents to issues (not projects). Use `mcp__linear-server__create_document` with the `issue` parameter.

View File

@@ -46,22 +46,24 @@ nvm use && corepack enable && yarn install
## Specs & Planning
**Every feature — even minor ones — needs a spec.** Specs live in **Linear** as documents attached to issues. Do not create spec files in the `specs/` folder — that folder is deprecated and being migrated to Linear.
**Every feature — even minor ones — needs a spec.** For SDK work (`packages/`, `webview-app`, `webview-bridge`), specs live in **both** the repo (`specs/`) and Linear. The repo spec is the canonical, version-controlled execution plan. The Linear issue is the tracking and discovery layer. For app-only or non-SDK work, a Linear issue with inline scope is sufficient — no repo spec required.
### Where Specs Live
- **Specs → Linear documents**, attached to the relevant Linear issue (not the project)
- **Architecture context`specs/projects/sdk/OVERVIEW.md`** (read-only reference, still in repo)
- **Audit docs → `docs/reviews/`** (PR audit findings, kept in repo for git history)
- **`specs/` folder** — deprecated. Existing specs are being migrated to Linear. Do not create new files here.
- **Execution specs → `specs/projects/sdk/workstreams/<scope>/plans/<ID>-<slug>.md`** — version-controlled, agent-executable plans
- **Backlog`specs/projects/sdk/workstreams/<scope>/SPEC.md`** — durable context plus backlog table per workstream
- **Architecture context → `specs/projects/sdk/OVERVIEW.md`** — system architecture, bridge protocol, decision matrix
- **Audit docs → `docs/reviews/`** — PR audit findings, kept in repo for git history
- **Linear issues** — tracking, discovery, status. Link to the repo spec. Attach a Linear document copy for cross-tool access.
### Planning Protocol
1. **Read** this file's Key Rules and any relevant Linear issue/spec — understand the current state and constraints
1. **Read** this file's Key Rules and any relevant specs — understand the current state and constraints
2. **Create a Linear issue** if one doesn't exist — include scope, files modified, acceptance criteria
3. **Create a spec as a Linear document** attached to the issue — this is the execution plan
4. **Then implement** — one spec = one PR ≤2k LOC
5. **After completion:** Update the Linear issue status. Close when done.
3. **Write the spec** in `specs/` following the two-layer model (backlog row in `SPEC.md`, execution plan in `plans/`)
4. **Create a Linear document** attached to the issue with the spec content (so non-GitHub users can review)
5. **Then implement** — one spec = one PR (see PR size target in Key Rules)
6. **After completion:** Update the Linear issue status. Close when done.
### Spec-Writing Guidelines
@@ -72,7 +74,7 @@ Specs are agent-executable prompts. A new Claude Code session with no prior cont
- **Be explicit about constraints.** "You will NOT modify..." not just "Focus on..."
- **Provide exact file paths with line numbers.** `src/utils/sumsubProvider.ts:118` not "the provider file."
- **State the validation command.** Agents will run it. If it's not there, they'll skip validation.
- **One spec = one PR ≤2k LOC.** If a spec would produce >2k LOC, split it.
- **One spec = one PR.** Target the PR size from Key Rules (1k3k LOC). If a spec would exceed that, split it.
- **Mark items as required vs optional.** Don't let agents infer priority.
- **Include out-of-scope sections.** These are as important as in-scope sections for preventing drift.
- **Use `--remote` for medium+ work.** Medium and large specs benefit from `claude --remote` so work continues in the background.
@@ -83,17 +85,17 @@ Three Claude Code skills automate the review-to-implementation pipeline:
1. **`/pr-audit`** — Multi-agent review (component + integration + routing), produces audit doc in `docs/reviews/`
2. **`/gaps-to-issues`** — Creates Linear issues from audit PR buckets
3. **`/spec-from-audit`** — Generates agent-executable specs as Linear documents, one per issue
3. **`/spec-from-audit`** — Generates agent-executable specs (repo file + Linear document), one per issue
Run them in sequence with review pauses between each step.
### Why Specs
- Prevents scope creep — writing "files NOT modified" forces focus
- Survives session loss — specs live in Linear, not session memory
- Survives session loss — specs live in the repo and Linear, not session memory
- Enables parallel work — multiple agents can pick up specs from the same project
- Creates audit trail — what was planned vs what was built
- Enables cross-tool review — anyone with Linear access can review specs, not just GitHub users
- Creates audit trail — what was planned vs what was built (version-controlled in git)
- Enables cross-tool review — Linear documents let non-GitHub users review specs
## Validation Commands

View File

@@ -291,4 +291,4 @@ See `.cursor/rules/test-memory-optimization.mdc` for comprehensive guidelines, e
The Self Wallet app serves as a **test environment** for the SDK refactor. For SDK architecture context:
- **[SDK Overview](../specs/projects/sdk/OVERVIEW.md)** — System architecture, bridge protocol, decision matrix (read-only reference)
- **Implementation specs** — Live in Linear as documents attached to issues. Check the relevant Linear issue for the current spec. Do not create spec files in `specs/` — that folder is deprecated.
- **Implementation specs** — Canonical source is `specs/projects/sdk/workstreams/<scope>/plans/` (version-controlled). Linear documents attached to issues are mirrored copies for tracking/discovery. When in doubt, trust the repo spec.

View File

@@ -147,7 +147,7 @@ yarn build # Confirm build still works
For architecture context:
- **[SDK Overview](../../specs/projects/sdk/OVERVIEW.md)** — System architecture, bridge protocol, decision matrix (read-only reference)
- **Implementation specs** — Live in Linear as documents attached to issues. Check the relevant Linear issue for the current spec. Do not create spec files in `specs/` — that folder is deprecated.
- **Implementation specs** — Canonical source is `specs/projects/sdk/workstreams/<scope>/plans/` (version-controlled). Linear documents attached to issues are mirrored copies for tracking/discovery. When in doubt, trust the repo spec.
Before implementing SDK work, read `CLAUDE.md` Key Rules for constraints and validation commands.

View File

@@ -74,7 +74,7 @@
| ----- | ---------------------------------------------------------------------------- | ------ | -------- | ---------- | ------------------------------------------------------------------------------------------ | --- |
| SC-01 | Consolidate bridge-layer fallback duplicates with engine-owned adapters | Done | High | - | [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | - |
| SC-02 | Expose `generateKey()` and `getPublicKey()` in bridge crypto adapter surface | Done | Medium | SC-01 | [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | - |
| SC-03 | Extract reusable app adapter factories for SelfClient assembly | Done | Medium | SC-02 | [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | - |
| SC-03 | Extract reusable app adapter factories for SelfClient assembly | Done | Medium | SC-02 | [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | - |
Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
@@ -84,7 +84,7 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
| ------------------------------------------------------------------------------------------ | ----- | ------ |
| [plans/SC-01-fallback-adapter-dedup.md](./plans/SC-01-fallback-adapter-dedup.md) | SC-01 | Done |
| [plans/SC-02-crypto-bridge-surface.md](./plans/SC-02-crypto-bridge-surface.md) | SC-02 | Done |
| [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | SC-03 | Done |
| [plans/SC-03-selfclient-adapter-assembly.md](./plans/SC-03-selfclient-adapter-assembly.md) | SC-03 | Done |
## Completion Checklist

View File

@@ -20,13 +20,13 @@ from the browser entry point.
### What the SDK provides
| Adapter | Factory | Location | Consumer |
| ------------------ | ----------------------------- | ------------------------------------------------------ | ------------- |
| Crypto (browser) | `createWebCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/browser/crypto.ts` | webview-app |
| Crypto (RN) | `createCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/react-native/crypto.ts` | RN app |
| Network (browser) | `createWebNetworkAdapter()` | `mobile-sdk-alpha/src/adapters/browser/network.ts` | webview-app |
| Network (RN) | `createNetworkAdapter()` | `mobile-sdk-alpha/src/adapters/react-native/network.ts`| RN app |
| Analytics | `createWebAnalyticsAdapter()` | `mobile-sdk-alpha/src/adapters/browser/analytics.ts` | webview-app |
| Adapter | Factory | Location | Consumer |
| ----------------- | ----------------------------- | ------------------------------------------------------- | ----------- |
| Crypto (browser) | `createWebCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/browser/crypto.ts` | webview-app |
| Crypto (RN) | `createCryptoAdapter()` | `mobile-sdk-alpha/src/adapters/react-native/crypto.ts` | RN app |
| Network (browser) | `createWebNetworkAdapter()` | `mobile-sdk-alpha/src/adapters/browser/network.ts` | webview-app |
| Network (RN) | `createNetworkAdapter()` | `mobile-sdk-alpha/src/adapters/react-native/network.ts` | RN app |
| Analytics | `createWebAnalyticsAdapter()` | `mobile-sdk-alpha/src/adapters/browser/analytics.ts` | webview-app |
## What Was Done
@@ -52,20 +52,20 @@ consumers can import it.
## Files Modified
| File | Change | Risk |
| ----------------------------------------------------------- | ---------------------------------------- | -------- |
| `packages/mobile-sdk-alpha/src/adapters/browser/network.ts` | **Created** — browser network factory | **Low** |
| `packages/mobile-sdk-alpha/src/adapters/browser/index.ts` | Added barrel export | **Low** |
| `packages/mobile-sdk-alpha/src/browser.ts` | Added re-export | **Low** |
| File | Change | Risk |
| ----------------------------------------------------------- | ------------------------------------- | ------- |
| `packages/mobile-sdk-alpha/src/adapters/browser/network.ts` | **Created** — browser network factory | **Low** |
| `packages/mobile-sdk-alpha/src/adapters/browser/index.ts` | Added barrel export | **Low** |
| `packages/mobile-sdk-alpha/src/browser.ts` | Added re-export | **Low** |
## Files NOT Modified
| File | Why |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| File | Why |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `app/src/providers/selfClientProvider.tsx` | RN app keeps its own inline adapters — avoids accidental breakage in production app |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | webview-app wiring is WV-07 scope |
| `packages/mobile-sdk-alpha/src/client.ts` | `createSelfClient()` factory is correct as-is |
| `packages/webview-bridge/**` | Bridge adapters are a separate assembly path |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | webview-app wiring is WV-07 scope |
| `packages/mobile-sdk-alpha/src/client.ts` | `createSelfClient()` factory is correct as-is |
| `packages/webview-bridge/**` | Bridge adapters are a separate assembly path |
## Design Decision: Separate RN and Browser Adapter Paths

View File

@@ -52,7 +52,7 @@ On **March 11, 2026**, the active SDK scope changed to **WebView only, with no c
| WV-04 | Define the host callback contract for launch, dismiss, and final result without native modules | Done | Medium | WV-02 | [plans/WV-04-host-callback-contract.md](./plans/WV-04-host-callback-contract.md) | Browser host fallback now uses `postMessage` for iframe/popup embedding while native transports keep their current behavior |
| WV-05 | Integrate KYC provider Web SDK into ProviderLaunchScreen (Sumsub as default) | In Progress | High | WV-02 | [plans/WV-05-sumsub-web-sdk.md](./plans/WV-05-sumsub-web-sdk.md) | Code complete on `feat/webview-sdk`, needs testing |
| WV-06 | Wire KYC result through verification pipeline to host lifecycle callback | Ready | High | WV-05 | [plans/WV-06-kyc-result-flow.md](./plans/WV-06-kyc-result-flow.md) | Sumsub result → kycResultStore → ConfirmIdentificationScreen → lifecycle.setResult() |
| WV-07 | SelfClient assembly and proving machine export for WebView | Ready | High | SC-03 | [plans/WV-07-selfclient-proving-assembly.md](./plans/WV-07-selfclient-proving-assembly.md) | Export useProvingStore, map bridge→SDK adapters, keychain-backed documents, create real SelfClient |
| WV-07 | SelfClient assembly and proving machine export for WebView | Ready | High | SC-03 | [plans/WV-07-selfclient-proving-assembly.md](./plans/WV-07-selfclient-proving-assembly.md) | Export useProvingStore, map bridge→SDK adapters, keychain-backed documents, create real SelfClient |
| WV-08 | Wire tunnel flow with real proving machine (register → disclose) | Ready | High | WV-07 | [plans/WV-08-tunnel-proving-flow.md](./plans/WV-08-tunnel-proving-flow.md) | Replace mock tunnel proving with real provingMachine: Sumsub → store doc → prove → disclose → result |
Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`

View File

@@ -34,11 +34,17 @@ exports alongside the existing type-only exports:
```typescript
// Existing (keep):
export type { ProvingStateType, provingMachineCircuitType } from './proving/provingMachine';
export type {
ProvingStateType,
provingMachineCircuitType,
} from './proving/provingMachine';
// Add:
export type { ProvingState } from './proving/provingMachine';
export { useProvingStore, getPostVerificationRoute } from './proving/provingMachine';
export {
useProvingStore,
getPostVerificationRoute,
} from './proving/provingMachine';
```
Additive-only — no RN regression risk.
@@ -53,15 +59,23 @@ boundary), not IndexedDB. Use the existing `secureStorage` bridge domain.
```typescript
import type { WebViewBridge } from '../bridge';
import type { DocumentsAdapter, DocumentCatalog, IDDocument } from '@selfxyz/mobile-sdk-alpha';
import type {
DocumentsAdapter,
DocumentCatalog,
IDDocument,
} from '@selfxyz/mobile-sdk-alpha';
const CATALOG_KEY = 'self_document_catalog';
const DOC_PREFIX = 'self_doc_';
export function createKeychainDocumentsAdapter(bridge: WebViewBridge): DocumentsAdapter {
export function createKeychainDocumentsAdapter(
bridge: WebViewBridge,
): DocumentsAdapter {
async function storageGet(key: string): Promise<string | null> {
const result = await bridge.request<{ value: string | null }>(
'secureStorage', 'get', { key },
'secureStorage',
'get',
{ key },
);
return result?.value ?? null;
}
@@ -121,7 +135,7 @@ import { bridgeAuthAdapter } from './auth';
import { createKeychainDocumentsAdapter } from './keychain-documents';
import {
createWebAnalyticsAdapter,
createWebNetworkAdapter, // from SC-03
createWebNetworkAdapter, // from SC-03
webNFCScannerShim,
} from '@selfxyz/mobile-sdk-alpha/browser';
@@ -150,7 +164,9 @@ export function createSdkAdapters(opts: CreateSdkAdaptersOpts): Adapters {
const navigation: NavigationAdapter = {
goBack,
goTo: (routeName, params) => {
const query = params ? `?${new URLSearchParams(params as Record<string, string>)}` : '';
const query = params
? `?${new URLSearchParams(params as Record<string, string>)}`
: '';
navigate(`/${routeName}${query}`);
},
};
@@ -177,7 +193,10 @@ Replace the current `SelfClientAdapters` bag-of-adapters with a real
`SelfClient` instance created via `createSelfClient()`.
```typescript
import { createSelfClient, createListenersMap } from '@selfxyz/mobile-sdk-alpha/browser';
import {
createSelfClient,
createListenersMap,
} from '@selfxyz/mobile-sdk-alpha/browser';
import { createSdkAdapters } from '@selfxyz/webview-bridge/adapters';
// Replace SelfClientAdapters type with SelfClient from SDK
@@ -185,7 +204,7 @@ import { createSdkAdapters } from '@selfxyz/webview-bridge/adapters';
// (they are WebView-specific and not part of SDK Adapters interface)
export interface WebViewAdapters {
client: SelfClient; // real SDK client with provingMachine access
client: SelfClient; // real SDK client with provingMachine access
lifecycle: BridgeLifecycleAdapter;
haptic: BridgeHapticAdapter;
biometrics: BridgeBiometricsAdapter;
@@ -193,6 +212,7 @@ export interface WebViewAdapters {
```
The `SelfClient` instance gives webview-app access to:
- `client.useProvingStore` — Zustand hook for proving state
- `client.getProvingState()` — snapshot accessor
- `client.emit()` / `client.on()` — event system
@@ -204,13 +224,13 @@ The `SelfClient` instance gives webview-app access to:
Add packages externalized by the SDK's tsup build:
| Package | Version | Why |
|--------------------|---------|----------------------------------|
| `socket.io-client` | ^4.8.3 | TEE status WebSocket listener |
| `xstate` | ^5.20.2 | Internal state machine |
| `node-forge` | ^1.3.3 | AES-256-GCM encryption |
| `buffer` | ^6.0.3 | Node.js Buffer polyfill |
| `elliptic` | ^6.5.4 | Crypto ops via @selfxyz/common |
| Package | Version | Why |
| ------------------ | ------- | ------------------------------ |
| `socket.io-client` | ^4.8.3 | TEE status WebSocket listener |
| `xstate` | ^5.20.2 | Internal state machine |
| `node-forge` | ^1.3.3 | AES-256-GCM encryption |
| `buffer` | ^6.0.3 | Node.js Buffer polyfill |
| `elliptic` | ^6.5.4 | Crypto ops via @selfxyz/common |
`zustand` and `@selfxyz/common` are already deps.
@@ -233,7 +253,11 @@ Pass required config fields to `createSelfClient()`:
```typescript
const client = useMemo(() => {
const adapters = createSdkAdapters({ bridge, navigate, goBack: () => navigate(-1) });
const adapters = createSdkAdapters({
bridge,
navigate,
goBack: () => navigate(-1),
});
const listeners = createListenersMap();
return createSelfClient({
config: {
@@ -249,31 +273,31 @@ const client = useMemo(() => {
## Files You Will Create
| File | What | Risk |
|-----------------------------------------------------------|---------------------------------------------------|----------|
| `packages/webview-bridge/src/adapters/keychain-documents.ts` | Keychain-backed DocumentsAdapter via secureStorage | **Low** |
| `packages/webview-bridge/src/adapters/sdk-adapter-map.ts` | Bridge→SDK adapter mapping + factory | **Low** |
| File | What | Risk |
| ------------------------------------------------------------ | -------------------------------------------------- | ------- |
| `packages/webview-bridge/src/adapters/keychain-documents.ts` | Keychain-backed DocumentsAdapter via secureStorage | **Low** |
| `packages/webview-bridge/src/adapters/sdk-adapter-map.ts` | Bridge→SDK adapter mapping + factory | **Low** |
## Files You Will Modify
| File | Change | Risk |
|--------------------------------------------------------------|------------------------------------------------------|------------|
| `packages/mobile-sdk-alpha/src/browser.ts` | Add `useProvingStore`, `ProvingState` exports | **Low** |
| `packages/webview-bridge/src/adapters/index.ts` | Add barrel exports for new adapters | **Low** |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | Replace adapter bag with real SelfClient | **Medium** |
| `packages/webview-app/package.json` | Add 5 dependencies | **Low** |
| `packages/webview-app/src/main.tsx` | Add Buffer polyfill (2 lines) | **Low** |
| `specs/projects/sdk/workstreams/webview/SPEC.md` | Add WV-07 to backlog | **None** |
| File | Change | Risk |
| ----------------------------------------------------------- | --------------------------------------------- | ---------- |
| `packages/mobile-sdk-alpha/src/browser.ts` | Add `useProvingStore`, `ProvingState` exports | **Low** |
| `packages/webview-bridge/src/adapters/index.ts` | Add barrel exports for new adapters | **Low** |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | Replace adapter bag with real SelfClient | **Medium** |
| `packages/webview-app/package.json` | Add 5 dependencies | **Low** |
| `packages/webview-app/src/main.tsx` | Add Buffer polyfill (2 lines) | **Low** |
| `specs/projects/sdk/workstreams/webview/SPEC.md` | Add WV-07 to backlog | **None** |
## Files You Will NOT Modify
| File | Why |
|---------------------------------------------------------------|--------------------------------------------------------------|
| `packages/mobile-sdk-alpha/src/proving/provingMachine.ts` | Engine is already browser-compatible; no changes needed |
| `packages/mobile-sdk-alpha/src/client.ts` | `createSelfClient()` factory is correct as-is |
| `packages/native-shell-android/**` | secureStorage handler already exists and handles JSON values |
| `packages/native-shell-ios/**` | secureStorage handler already exists and handles JSON values |
| `packages/webview-app/src/screens/**` | Screen wiring is WV-08 scope |
| File | Why |
| --------------------------------------------------------- | ------------------------------------------------------------ |
| `packages/mobile-sdk-alpha/src/proving/provingMachine.ts` | Engine is already browser-compatible; no changes needed |
| `packages/mobile-sdk-alpha/src/client.ts` | `createSelfClient()` factory is correct as-is |
| `packages/native-shell-android/**` | secureStorage handler already exists and handles JSON values |
| `packages/native-shell-ios/**` | secureStorage handler already exists and handles JSON values |
| `packages/webview-app/src/screens/**` | Screen wiring is WV-08 scope |
## Constraints

View File

@@ -76,20 +76,20 @@ export const TunnelProvingScreen: React.FC = () => {
**State → UI mapping:**
| provingMachine state | UI shown |
|--------------------------|--------------------------------------------------|
| `idle` | Loading spinner |
| `parsing_id_document` | "Preparing document..." |
| `fetching_data` | "Fetching verification data..." |
| `validating_document` | "Validating document..." |
| `init_tee_connexion` | "Connecting to prover..." |
| `ready_to_prove` | "Ready" (auto-confirm or user confirms) |
| `proving` | "Generating proof..." (with Euclid animation) |
| `post_proving` | "Finalizing..." |
| `completed` | Navigate to result screen (success) |
| `error` / `failure` | Navigate to result screen (error with code) |
| `passport_not_supported` | Show unsupported document error |
| `passport_data_not_found`| Show missing document error |
| provingMachine state | UI shown |
| ------------------------- | --------------------------------------------- |
| `idle` | Loading spinner |
| `parsing_id_document` | "Preparing document..." |
| `fetching_data` | "Fetching verification data..." |
| `validating_document` | "Validating document..." |
| `init_tee_connexion` | "Connecting to prover..." |
| `ready_to_prove` | "Ready" (auto-confirm or user confirms) |
| `proving` | "Generating proof..." (with Euclid animation) |
| `post_proving` | "Finalizing..." |
| `completed` | Navigate to result screen (success) |
| `error` / `failure` | Navigate to result screen (error with code) |
| `passport_not_supported` | Show unsupported document error |
| `passport_data_not_found` | Show missing document error |
### 3. Wire disclose flow after register
@@ -163,31 +163,31 @@ tunnel flow.
## Files You Will Modify
| File | Change | Risk |
|----------------------------------------------------------------------------|-------------------------------------------------|------------|
| `packages/webview-app/src/screens/tunnel/TunnelProvingScreen.tsx` | Replace mock with real provingMachine | **Medium** |
| `packages/webview-app/src/screens/tunnel/TunnelResultScreen.tsx` | Wire real result from proving state | **Low** |
| `packages/webview-app/src/screens/tunnel/TunnelProofReceiptScreen.tsx` | Wire user confirmation to provingMachine | **Low** |
| `packages/webview-app/src/App.tsx` | Update tunnel routes if needed | **Low** |
| `specs/projects/sdk/workstreams/webview/SPEC.md` | Add WV-08 to backlog | **None** |
| File | Change | Risk |
| ---------------------------------------------------------------------- | ---------------------------------------- | ---------- |
| `packages/webview-app/src/screens/tunnel/TunnelProvingScreen.tsx` | Replace mock with real provingMachine | **Medium** |
| `packages/webview-app/src/screens/tunnel/TunnelResultScreen.tsx` | Wire real result from proving state | **Low** |
| `packages/webview-app/src/screens/tunnel/TunnelProofReceiptScreen.tsx` | Wire user confirmation to provingMachine | **Low** |
| `packages/webview-app/src/App.tsx` | Update tunnel routes if needed | **Low** |
| `specs/projects/sdk/workstreams/webview/SPEC.md` | Add WV-08 to backlog | **None** |
## Files You Will NOT Modify
| File | Why |
|---------------------------------------------------------------|--------------------------------------------------------|
| `packages/mobile-sdk-alpha/src/proving/provingMachine.ts` | Engine unchanged — consumed as-is |
| `packages/webview-bridge/**` | Bridge layer unchanged — WV-07 already handled mapping |
| `packages/native-shell-android/**` | No new native handlers needed |
| `packages/native-shell-ios/**` | No new native handlers needed |
| `packages/webview-app/src/screens/proving/ProvingScreen.tsx` | Non-tunnel proving screen — separate concern |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | Already wired in WV-07 |
| File | Why |
| ------------------------------------------------------------ | ------------------------------------------------------ |
| `packages/mobile-sdk-alpha/src/proving/provingMachine.ts` | Engine unchanged — consumed as-is |
| `packages/webview-bridge/**` | Bridge layer unchanged — WV-07 already handled mapping |
| `packages/native-shell-android/**` | No new native handlers needed |
| `packages/native-shell-ios/**` | No new native handlers needed |
| `packages/webview-app/src/screens/proving/ProvingScreen.tsx` | Non-tunnel proving screen — separate concern |
| `packages/webview-app/src/providers/SelfClientProvider.tsx` | Already wired in WV-07 |
## Files You May Create
| File | What |
|-----------------------------------------------------------------------|---------------------------------------------------|
| `packages/webview-app/src/hooks/useProvingFlow.ts` | Optional: shared hook for register→disclose chain |
| `packages/webview-app/src/screens/tunnel/TunnelProviderScreen.tsx` | If tunnel needs its own Sumsub launch screen |
| File | What |
| ------------------------------------------------------------------ | ------------------------------------------------- |
| `packages/webview-app/src/hooks/useProvingFlow.ts` | Optional: shared hook for register→disclose chain |
| `packages/webview-app/src/screens/tunnel/TunnelProviderScreen.tsx` | If tunnel needs its own Sumsub launch screen |
## Constraints
@@ -211,7 +211,8 @@ tunnel flow.
Construct it directly from Sumsub's attestation:
```typescript
const kycData: KycData = {
documentType: deserializeApplicantInfo(attestation.serializedApplicantInfo).idType,
documentType: deserializeApplicantInfo(attestation.serializedApplicantInfo)
.idType,
documentCategory: 'kyc',
mock: false,
signature: attestation.signature,