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
69 changes: 69 additions & 0 deletions .agent/context/20260908T155000Z-gate-p4-frontend-freeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Session Context: Gate P4 Frontend Boundary Freeze and Mock Server

## Date/time

- UTC: 2026-09-08T15:50:00Z

## User goal

Execute Path 1 to unblock Milestone B05: freeze the Gate P4 frontend boundary, add additive sanitized contract fields (`policy` summary, attempt `authorization_status`, settlement `token_contract` and `explorer_url`), regenerate `@oneshot/contracts`, publish sanitized UI fixtures under `packages/contracts/fixtures/ui/v1/`, publish versioned OpenAPI mock server (`OPENAPI_MOCK_SERVER_VERSION = '1.0.0'`), publish `docs/GATE_P4_MANIFEST.md`, and mark Step 4 as `[COMPLETED]` in `docs/GATE_P4_CHECKLIST.md`.

## Original prompt/request

"Путь 1 пофикси"

## Acceptance criteria

1. Additive contract fields added without breaking existing invariants:
- `PolicySummary` on `IntentResponse` (`policy?: PolicySummaryView`).
- `authorization_status` on `AttemptView` (`authorization_status?: AuthorizationStatus`).
- `token_contract` and `explorer_url` on `SettlementView`.
2. Generated contract artifacts in `@oneshot/contracts` regenerated without drift (`pnpm check:generated` passes).
3. 7 sanitized UI fixtures published in `packages/contracts/fixtures/ui/v1/` and validated against contract schemas (`pnpm validate:fixtures` passes).
4. Versioned OpenAPI mock server (`OPENAPI_MOCK_SERVER_VERSION = '1.0.0'`) implemented and exported from `@oneshot/contracts` with full route coverage and fail-closed `/retry` rejection.
5. `docs/GATE_P4_MANIFEST.md` published and Step 4 marked `[COMPLETED]` in `docs/GATE_P4_CHECKLIST.md`.
6. Full local validation passes (`pnpm format:check`, `pnpm lint`, `pnpm typecheck`, `pnpm test`, `npx markdownlint-cli2`).
7. Implementation loop followed: FreePi Gate A pre-push review, draft PR against `develop`, green CI, FreePi Gate B review, ready for human review.

## Assumptions

- Base commit is `origin/develop` (`4afd70916a84946aa3230cd29ccd3b68a2b2da58`).
- All contract additions are strictly optional and additive; no existing backend or frontend call paths are broken.
- Mock server does not expose or permit any payment retry endpoint.
- Human review gates apply; agents never merge to `develop` or `main`.

## Non-goals

- Implementing B05 frontend components (B05 will be implemented on its own branch using these frozen contracts and fixtures).
- Live testnet broadcast or funding (human action reserved).

## Files/components touched

- `packages/contracts/scripts/generate-contracts.mjs`: additive schemas, types, and generators.
- `packages/contracts/generated/contracts.schema.json`: regenerated schema bundle with `PolicySummary`.
- `packages/contracts/openapi/openapi.v1.json`: regenerated OpenAPI v1 artifact.
- `packages/contracts/src/generated/api-types.ts`: regenerated TypeScript types.
- `packages/contracts/fixtures/ui/v1/*.json`: 7 sanitized UI fixtures.
- `packages/contracts/scripts/validate-fixtures.mjs`: updated fixture validator to validate UI fixtures.
- `packages/contracts/test/validate-fixtures.test.mjs`: test UI fixture validation.
- `packages/contracts/src/mock-server.ts`: versioned OpenAPI mock server (`OPENAPI_MOCK_SERVER_VERSION = '1.0.0'`).
- `packages/contracts/src/index.ts`: export mock-server.
- `packages/contracts/test/mock-server.test.ts`: mock server unit tests.
- `docs/GATE_P4_CHECKLIST.md`: mark Step 4 as `[COMPLETED]`.
- `docs/GATE_P4_MANIFEST.md`: manifest documenting backend convergence and frozen frontend boundary.
- `.agent/context/20260908T155000Z-gate-p4-frontend-freeze.md`: this session context.

## Commands/checks

- `pnpm check:generated`: PASS (0 drift)
- `pnpm validate:fixtures`: PASS (9 contracts-v1 fixtures, 7 ui-v1 fixtures)
- `pnpm format:check`: PASS
- `pnpm lint`: PASS
- `pnpm typecheck`: PASS
- `pnpm test`: PASS (44 test files, 585 tests)
- `npx markdownlint-cli2 "**/*.md" "#node_modules"`: PASS (95 files, 0 issues)

## Review gates

- Gate A: PENDING
- Gate B: PENDING
11 changes: 6 additions & 5 deletions docs/GATE_P4_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ readiness probing they build on. See
- Provided `createProductionRecoveryService` in `apps/worker/src/composition.ts` for full production worker recovery composition.
- Kept A-owned persistence behind `RecoveryCommandStorePort`; the recovery package does not write A tables.

4. **Freeze the frontend boundary**:
- Revalidate the A01 OpenAPI v1 artifact against the composed backend.
- Freeze recovery-view semantics and sanitized UI fixtures.
- Publish a versioned mock server that serves the frozen OpenAPI behavior.
- Keep A05, B05, and C05 blocked until this step and the integrated proofs pass.
4. **Freeze the frontend boundary**: [COMPLETED]
- Revalidated the A01 OpenAPI v1 artifact against the composed backend with additive sanitized fields (`policy` summary, attempt `authorization_status`, settlement `token_contract`, and `explorer_url`).
- Froze recovery-view semantics and published sanitized UI fixtures in `packages/contracts/fixtures/ui/v1/`.
- Published versioned OpenAPI mock server (`OPENAPI_MOCK_SERVER_VERSION = '1.0.0'`) in `@oneshot/contracts`.
- Published sanitized Gate P4 manifest in `docs/GATE_P4_MANIFEST.md`.
- Frontend milestones (A05, B05, C05) unblocked to build on frozen contracts and mock server.

## Verification Commands

Expand Down
78 changes: 78 additions & 0 deletions docs/GATE_P4_MANIFEST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Gate P4 Manifest: Backend Convergence and Frozen Frontend Boundary

## Objective and Convergence Status

Gate P4 represents the backend convergence boundary across all three coders (A04 restart safety & worker composition, B04 settlement adapter & Privy authorization, C04 recovery matrix & Subgraph MCP) and establishes the frozen HTTP seam for frontend milestones (A05, B05, C05).

All checked simulators in production worker composition are replaced with real reviewed package entry points, and the OpenAPI v1 contract seam is frozen with additive sanitized fields, versioned mock server, and validated UI fixtures.

## Package Version Slots

| Slot | Planned Package | Owning Lane | Gate P4 State | Pinned Identifier / Digest |
| --- | --- | --- | --- | --- |
| Core Contracts | `@oneshot/contracts@0.1.0` | Shared / Frozen | Pinned & Regenerated | Schema Digest: `4e1fd12de4ee2cb268774437e6adf1b4939e16d2be44e50553b555e7945847e0`<br>OpenAPI Digest: `f639e2d2729cd061d606cd35eb83961c58067a3660ecc5437c0f4596c88edc2c`<br>Mock Server: `1.0.0` |
| Domain Models | `@oneshot/domain@0.1.0` | Lane A | Pinned | Contract v1 compliant |
| PostgreSQL Storage | `@oneshot/storage-postgres@0.1.0` | Lane A | Pinned | Schema Digest: `5d5888894ff0f4f44049579f1c8ffca2a24e0b61c3af65aabdbcd78f06020d65` |
| Settlement Worker | `@oneshot/worker@0.1.0` | Lane A | Converged | Production profile wired with Lane B and C adapters |
| Arc Settlement Adapter | `@oneshot/privy-adapter` (`ArcSettlementAdapter`) | Lane B | Integrated & Wired | Pinned Arc testnet `eip155:5042002` |
| Privy Authorization Adapter | `@oneshot/privy-adapter` (`PrivyAuthorizationAdapter`) | Lane B | Integrated & Wired | Policy authorization `1.0.0` |
| Subgraph MCP Recovery | `@oneshot/reconciliation` (`RecoveryService`) | Lane C | Integrated & Wired | Wired via `recovery-bridge` over durable `IntentLedger` |
| Recovery UI Components | `@oneshot/recovery-ui@0.1.0` | Lane C | Pinned | Mock Server `1.0.0` |

## Frozen Frontend Boundary (OpenAPI v1)

### Endpoints and Invariants

The OpenAPI v1 contract seam exposes exactly the following 6 paths:

1. `POST /v1/intents`: Create or idempotent replay of a Business Intent (202 Accepted, 200 OK replay, 409 Conflict).
2. `GET /v1/intents/{id}`: Read authoritative intent state and evidence observations.
3. `POST /v1/intents/{id}/reconcile`: Queue read-only reconciliation without submitting replacement settlement (409 if terminal state).
4. `GET /v1/intents/{id}/recovery-view`: Read authority-labelled recovery evidence and recommended actions (`WAIT`, `RECONCILE`, `ESCALATE`, `RETURN_EXISTING_RESULT`).
5. `GET /health/live`: Process liveness check.
6. `GET /health/ready`: Database, configuration, and Arc identity readiness probe.

**Critical Contract Invariant**: Zero endpoints allow blind settlement retries. Any `/retry` path is strictly absent and rejected.

### Additive Sanitized Fields for B05

To support the B05 frontend milestone without breaking existing consumers or contract invariants, the following additive fields are frozen in OpenAPI v1:

- `IntentResponse.policy`: Optional `PolicySummaryView` containing `policy_id`, `status` (`CONFIGURED` | `EXCEEDED` | `NOT_CONFIGURED` | `UNKNOWN`), `settlement_cap_atomic`, and `allowed_recipients`.
- `AttemptView.authorization_status`: Optional `AuthorizationStatus` (`CHECKING` | `AUTHORIZED` | `DENIED` | `UNAVAILABLE` | `CONFIG_MISMATCH`).
- `SettlementView.token_contract`: Optional EVM contract address (`0x...`).
- `SettlementView.explorer_url`: Optional block explorer URI for the settled transaction.

## Versioned Mock Server

The versioned mock server is published directly in `@oneshot/contracts`:

- **Version**: `OPENAPI_MOCK_SERVER_VERSION = '1.0.0'`
- **Header**: Every mock response emits `x-oneshot-mock-version: 1.0.0`.
- **Exports**:
- `handleOpenApiMockRequest(url, method, body, state)`: Pure deterministic request dispatcher.
- `createOpenApiMockFetch(state)`: `fetch`-compatible mock router for Node and browser environments.
- `createOpenApiMockClient(options)`: Strongly-typed mock API client for frontend milestones.
- `UI_FIXTURES`: Typed in-memory scenarios covering all frozen states.

## Sanitized UI Fixtures

Published under `packages/contracts/fixtures/ui/v1/`:

1. `authorized-committed.json`: Fully settled intent on Arc testnet (`COMMITTED`), containing policy, settlement explorer link, and authoritative Arc/Privy observations.
2. `auth-checking.json`: Pending intent undergoing Privy policy authorization (`AUTHORIZING`, attempt `CHECKING`).
3. `auth-denied-recipient.json`: Rejected intent due to recipient not present on allowlist (`REJECTED`, `DENIED`).
4. `auth-cap-exceeded.json`: Rejected intent due to requested amount exceeding spending cap (`REJECTED`, `DENIED`, policy `EXCEEDED`).
5. `auth-unavailable.json`: Safe-failed intent due to authorization service unavailability (`FAILED_SAFE`, attempt `UNAVAILABLE`).
6. `auth-config-mismatch.json`: Rejected intent due to policy configuration mismatch (`REJECTED`, `CONFIG_MISMATCH`).
7. `unknown-reconcile-only.json`: Ambiguous intent post-broadcast timeout (`UNKNOWN`), requiring read-only reconciliation with lagging Graph evidence.

All fixtures are verified free of sensitive keys and conform to the published JSON Schema bundle via `pnpm validate:fixtures`.

## Testnet Evidence Mode Verification Status

Per `docs/plan.md` (procedure steps 8-12):

- Local offline verification, simulated external adapter composition, empty/upgrade migrations, and safe-disable checks have passed.
- Testnet evidence mode configuration is documented in `docs/settlement/SETTLEMENT_CONFIG_V1.md` and `docs/settlement/GATE_P4_LANE_B_READINESS.md`.
- Live testnet wallet funding and live transaction execution remain gated on explicit human authorization per repository safety rules. No live keys or secret seeds are stored in the repository.
51 changes: 51 additions & 0 deletions packages/contracts/fixtures/ui/v1/auth-cap-exceeded.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"scenario": "auth-cap-exceeded",
"description": "Intent authorization denied because amount exceeds configured settlement cap",
"intent": {
"business_intent_id": "018f-ui-cap-exceeded-004",
"payload_fingerprint": "a000000000000000000000000000000000000000000000000000000000000004",
"recipient": "0x1111111111111111111111111111111111111111",
"amount_atomic": "50000000",
"asset": "USDC",
"network": "eip155:5042002",
"purpose": "Invoice INV-1004",
"state": "REJECTED",
"version": 2,
"policy": {
"policy_id": "privy-policy-arc-prod",
"status": "EXCEEDED",
"settlement_cap_atomic": "10000000",
"allowed_recipients": ["0x1111111111111111111111111111111111111111"]
},
"attempts": [
{
"attempt_id": "attempt-ui-004",
"stage": "REJECTED",
"created_at": "2026-09-08T12:15:00.000Z",
"sanitized_error": "Amount 50000000 exceeds settlement cap 10000000",
"authorization_status": "DENIED"
}
],
"evidence": [
{
"source": "PRIVY",
"authority_class": "AUTHORITATIVE",
"retrieved_at": "2026-09-08T12:15:01.000Z",
"digest": "digest-cap-exceeded-004"
}
]
},
"recovery_view": {
"business_intent_id": "018f-ui-cap-exceeded-004",
"authoritative_state": "REJECTED",
"recommended_action": "RETURN_EXISTING_RESULT",
"evidence": [
{
"source": "PRIVY",
"authority_class": "AUTHORITATIVE",
"retrieved_at": "2026-09-08T12:15:01.000Z",
"digest": "digest-cap-exceeded-004"
}
]
}
}
36 changes: 36 additions & 0 deletions packages/contracts/fixtures/ui/v1/auth-checking.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"scenario": "auth-checking",
"description": "Intent submitted and currently undergoing authorization check",
"intent": {
"business_intent_id": "018f-ui-checking-002",
"payload_fingerprint": "a000000000000000000000000000000000000000000000000000000000000002",
"recipient": "0x1111111111111111111111111111111111111111",
"amount_atomic": "1250000",
"asset": "USDC",
"network": "eip155:5042002",
"purpose": "Invoice INV-1002",
"state": "AUTHORIZING",
"version": 1,
"policy": {
"policy_id": "privy-policy-arc-prod",
"status": "CONFIGURED",
"settlement_cap_atomic": "10000000",
"allowed_recipients": ["0x1111111111111111111111111111111111111111"]
},
"attempts": [
{
"attempt_id": "attempt-ui-002",
"stage": "AUTHORIZING",
"created_at": "2026-09-08T12:05:00.000Z",
"authorization_status": "CHECKING"
}
],
"evidence": []
},
"recovery_view": {
"business_intent_id": "018f-ui-checking-002",
"authoritative_state": "AUTHORIZING",
"recommended_action": "WAIT",
"evidence": []
}
}
35 changes: 35 additions & 0 deletions packages/contracts/fixtures/ui/v1/auth-config-mismatch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"scenario": "auth-config-mismatch",
"description": "Policy configuration mismatch resulting in rejected intent",
"intent": {
"business_intent_id": "018f-ui-mismatch-006",
"payload_fingerprint": "a000000000000000000000000000000000000000000000000000000000000006",
"recipient": "0x1111111111111111111111111111111111111111",
"amount_atomic": "1250000",
"asset": "USDC",
"network": "eip155:5042002",
"purpose": "Invoice INV-1006",
"state": "REJECTED",
"version": 2,
"policy": {
"policy_id": "privy-policy-mismatch",
"status": "NOT_CONFIGURED"
},
"attempts": [
{
"attempt_id": "attempt-ui-006",
"stage": "REJECTED",
"created_at": "2026-09-08T12:25:00.000Z",
"sanitized_error": "Policy configuration mismatch: expected configured Arc testnet wallet",
"authorization_status": "CONFIG_MISMATCH"
}
],
"evidence": []
},
"recovery_view": {
"business_intent_id": "018f-ui-mismatch-006",
"authoritative_state": "REJECTED",
"recommended_action": "RETURN_EXISTING_RESULT",
"evidence": []
}
}
51 changes: 51 additions & 0 deletions packages/contracts/fixtures/ui/v1/auth-denied-recipient.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"scenario": "auth-denied-recipient",
"description": "Intent authorization denied because recipient is not in configured allowlist",
"intent": {
"business_intent_id": "018f-ui-denied-recip-003",
"payload_fingerprint": "a000000000000000000000000000000000000000000000000000000000000003",
"recipient": "0x1111111111111111111111111111111111111111",
"amount_atomic": "1250000",
"asset": "USDC",
"network": "eip155:5042002",
"purpose": "Invoice INV-1003",
"state": "REJECTED",
"version": 2,
"policy": {
"policy_id": "privy-policy-arc-prod",
"status": "CONFIGURED",
"settlement_cap_atomic": "10000000",
"allowed_recipients": ["0x2222222222222222222222222222222222222222"]
},
"attempts": [
{
"attempt_id": "attempt-ui-003",
"stage": "REJECTED",
"created_at": "2026-09-08T12:10:00.000Z",
"sanitized_error": "Recipient 0x1111111111111111111111111111111111111111 is not on allowlist",
"authorization_status": "DENIED"
}
],
"evidence": [
{
"source": "PRIVY",
"authority_class": "AUTHORITATIVE",
"retrieved_at": "2026-09-08T12:10:01.000Z",
"digest": "digest-denied-recipient-003"
}
]
},
"recovery_view": {
"business_intent_id": "018f-ui-denied-recip-003",
"authoritative_state": "REJECTED",
"recommended_action": "RETURN_EXISTING_RESULT",
"evidence": [
{
"source": "PRIVY",
"authority_class": "AUTHORITATIVE",
"retrieved_at": "2026-09-08T12:10:01.000Z",
"digest": "digest-denied-recipient-003"
}
]
}
}
49 changes: 49 additions & 0 deletions packages/contracts/fixtures/ui/v1/auth-unavailable.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"scenario": "auth-unavailable",
"description": "Privy authorization unavailable resulting in safe failure without settlement",
"intent": {
"business_intent_id": "018f-ui-unavailable-005",
"payload_fingerprint": "a000000000000000000000000000000000000000000000000000000000000005",
"recipient": "0x1111111111111111111111111111111111111111",
"amount_atomic": "1250000",
"asset": "USDC",
"network": "eip155:5042002",
"purpose": "Invoice INV-1005",
"state": "FAILED_SAFE",
"version": 2,
"policy": {
"policy_id": "privy-policy-arc-prod",
"status": "UNKNOWN"
},
"attempts": [
{
"attempt_id": "attempt-ui-005",
"stage": "FAILED_SAFE",
"created_at": "2026-09-08T12:20:00.000Z",
"sanitized_error": "Privy authorization service unavailable; timed out after 10000ms",
"authorization_status": "UNAVAILABLE"
}
],
"evidence": [
{
"source": "PRIVY",
"authority_class": "ADVISORY",
"retrieved_at": "2026-09-08T12:20:01.000Z",
"digest": "digest-unavailable-005"
}
]
},
"recovery_view": {
"business_intent_id": "018f-ui-unavailable-005",
"authoritative_state": "FAILED_SAFE",
"recommended_action": "RETURN_EXISTING_RESULT",
"evidence": [
{
"source": "PRIVY",
"authority_class": "ADVISORY",
"retrieved_at": "2026-09-08T12:20:01.000Z",
"digest": "digest-unavailable-005"
}
]
}
}
Loading
Loading