From b7683c9baf9fdab33104567ccd6316e4eaa2a0ac Mon Sep 17 00:00:00 2001 From: kapustazh <51422901+kapustazh@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:10:12 +0200 Subject: [PATCH 1/2] refactor: remove legacy console and unused helpers --- ...0261008T170745Z-remove-legacy-leftovers.md | 82 ++++++ Dockerfile.api | 29 -- apps/web/src/App.tsx | 258 +----------------- apps/web/src/styles.css | 196 ------------- apps/web/test/app-auth.test.tsx | 31 ++- apps/web/test/app-composition.test.tsx | 62 +---- apps/web/test/composition.test.tsx | 67 +---- apps/worker/src/worker.ts | 9 - docs/RESTART_RUNNER.md | 1 - docs/settlement/B06_SPONSOR_EVIDENCE.md | 2 +- packages/contracts/src/ports.ts | 4 - .../reconciliation/src/recovery-matrix.ts | 25 -- packages/settlement-ui/src/fixtures.ts | 4 - .../testkit-settlement/bin/b06-evidence.js | 2 +- .../test/b06-evidence.test.ts | 2 +- 15 files changed, 115 insertions(+), 659 deletions(-) create mode 100644 .agent/context/20261008T170745Z-remove-legacy-leftovers.md delete mode 100644 Dockerfile.api diff --git a/.agent/context/20261008T170745Z-remove-legacy-leftovers.md b/.agent/context/20261008T170745Z-remove-legacy-leftovers.md new file mode 100644 index 0000000..c1fbe12 --- /dev/null +++ b/.agent/context/20261008T170745Z-remove-legacy-leftovers.md @@ -0,0 +1,82 @@ +# Session Context: remove legacy leftovers + +## Date/time + +- UTC: 2026-10-08T17:07:45Z + +## User goal + +Remove the leftovers identified in the develop audit with minimal changes. + +## Original prompt/request + +"let's try to cut that out $caveman $ponytail" +Prior session instructions: do not reopen closed PRs; omit FreePi. + +## Assumptions + +- Retire the old tabbed console and migrate its coverage to current surfaces. +- Unknown paths use the public landing page, without exposing the old console. +- Preserve payment controls, applied migrations, evidence history, and demos. + +## Plan + +1. Remove the duplicate API Dockerfile and unused helpers. +2. Remove the legacy console and its unused CSS; migrate authentication and + read-only evidence tests to current surfaces. +3. Run checks and create a fresh draft PR against develop. + +## Key decisions + +- Dockerfile remains canonical; evidence tooling and references now use it. +- Removed resumeSafeJobs, assertNever, scenarioNames, and unused Markdown renderer. +- Kept runStartupRecovery, drainOutboxJobs, and all settlement safeguards. +- Current cabinet, landing, and MCP docs routes remain; unmatched paths show landing. +- Standalone components, demos, applied migrations, and historical records remain. + +## Files/components touched + +- Dockerfile.api removed; evidence runner/test and evidence documentation updated. +- App.tsx legacy fallback and orphaned styles removed. +- Web authentication/composition tests migrated to current cabinet and evidence views. +- Worker wrapper, contracts helper, fixture helper, and recovery report helper removed. +- Restart runner documentation and this session record. + +## Commands/checks + +- Node 24.19.0 and pnpm 11.19.0 used for full validation via temporary npx tools. +- pnpm test: PASS, build plus 80 files / 1060 tests. +- Web unit tests: PASS, 17 files / 100 tests. +- pnpm format:check, lint, typecheck: PASS. +- pnpm check:generated and validate:fixtures: PASS. +- Browser acceptance: PASS, 8/8 tests after installing Chromium under goinfre. + Browser check caught a damaged CSS comment from selector deletion; corrected + comment and reran browser and web suites successfully. +- Repository-wide pinned Markdown and diff checks: PASS before commit. +- Test matrix: no settlement algorithm changes; existing root recovery/retry tests + pass. Auth gating and read-only evidence tests cover migrated UI behavior. + +## External-doc findings + +- None; no new dependency or provider integration. + +## Unresolved questions + +- None. + +## Git and PR state + +- Branch: feature/remove-legacy-leftovers. +- Base develop: 55a387abad228d61c7a0a7a911299c103495bda0. +- Commit/PR: pending validation; new draft PR, never reopen a closed PR. +- CI: pending push. + +## Review gates + +- Gate A and B: SKIPPED following user's instruction to omit FreePi. +- No passing independent review claimed; PR remains draft. + +## Handoff/next steps + +1. Finish browser checks, push focused change, and create new draft PR. +2. Human reviews and merges; agent does not merge. diff --git a/Dockerfile.api b/Dockerfile.api deleted file mode 100644 index f833307..0000000 --- a/Dockerfile.api +++ /dev/null @@ -1,29 +0,0 @@ -FROM node:24-bookworm-slim AS builder - -RUN corepack enable && corepack prepare pnpm@11.19.0 --activate -WORKDIR /app - -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json tsconfig.json tsconfig.base.json ./ -COPY apps ./apps -COPY packages ./packages -COPY subgraph ./subgraph - -RUN pnpm install --frozen-lockfile -RUN pnpm build - -FROM node:24-bookworm-slim AS runner - -WORKDIR /app -ENV NODE_ENV=production - -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json tsconfig.json tsconfig.base.json ./ -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/packages ./packages -COPY --from=builder /app/apps ./apps - -WORKDIR /app/apps/api -ENV PORT=8080 -ENV HOST=0.0.0.0 -EXPOSE 8080 - -CMD ["node", "dist/server.js"] diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 4a574c9..d38b26f 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import type { ActivityResponse } from '@oneshot/contracts'; import { createSettlementClient, type SettlementClient } from '@oneshot/settlement-ui'; import type { RecoveryClient } from '@oneshot/recovery-ui'; @@ -15,29 +15,16 @@ import { type UseOperatorSession, type UserWalletSession, } from './auth/session.js'; -import { ErrorBoundary } from './components/ErrorBoundary.js'; import { Hero } from './components/Hero.js'; -import { IntentForm } from './components/IntentForm.js'; -import { IntentStatusView } from './components/IntentStatusView.js'; import { LoginGate } from './components/LoginGate.js'; import { McpDocsPage } from './components/McpDocsPage.js'; import { McpProfile } from './components/McpProfile.js'; import { ReadinessBanner } from './components/ReadinessBanner.js'; import { JobList, JobWorkspace } from './components/JobWorkspace.js'; -import { RecoverySurface, SettlementSurface } from './components/FrontendSurfaces.js'; import { PaymentProtectionPanel } from './components/WorkspacePanels.js'; import { applyTheme, readStoredTheme, type Theme } from './theme.js'; import './styles.css'; -type Tab = 'create' | 'status' | 'settlement' | 'recovery'; -const TAB_ORDER: readonly Tab[] = ['create', 'status', 'settlement', 'recovery']; -const TAB_LABELS: Readonly> = { - create: 'Create request', - status: 'Payment status', - settlement: 'Payment proof', - recovery: 'Recovery control', -}; - export interface AppProps { readonly apiClient?: OneShotApiClient; readonly jobClient?: JobApiClient; @@ -47,7 +34,7 @@ export interface AppProps { readonly userWallet?: UserWalletSession; /** Optional prepared MCP job to open directly in the wallet-signing workspace. */ readonly mcpJobId?: string; - /** main.tsx passes the browser route; omitted preserves legacy test composition. */ + /** Browser path; omitted or unknown paths show the public landing page. */ readonly route?: string; } @@ -337,8 +324,6 @@ function CabinetPage(props: { export function App(props: AppProps = {}) { const useOperatorSession = props.useOperatorSession ?? unconfiguredOperatorSession; const session = useOperatorSession(); - const [activeTab, setActiveTab] = useState('create'); - const [selectedIntentId, setSelectedIntentId] = useState(''); const [machineToken, setMachineToken] = useState(''); const [theme, setTheme] = useState(() => readStoredTheme()); @@ -350,12 +335,6 @@ export function App(props: AppProps = {}) { const credentialRef = useRef(null); credentialRef.current = selectCredential(session, machineToken); const getAuthToken = useCallback(() => credentialRef.current, []); - const tabRefs = useRef>({ - create: null, - status: null, - settlement: null, - recovery: null, - }); const apiBaseUrl = import.meta.env.VITE_ONESHOT_API_BASE_URL ?? ''; const apiClient = useMemo( () => props.apiClient ?? new OneShotApiClient({ baseUrl: apiBaseUrl, getAuthToken }), @@ -396,236 +375,5 @@ export function App(props: AppProps = {}) { ); } - function selectIntent(intentId: string): void { - setSelectedIntentId(intentId); - setActiveTab('status'); - } - - function handleTabKeyDown(event: KeyboardEvent, currentTab: Tab): void { - const currentIndex = TAB_ORDER.indexOf(currentTab); - let nextIndex: number | undefined; - if (event.key === 'ArrowRight') nextIndex = (currentIndex + 1) % TAB_ORDER.length; - if (event.key === 'ArrowLeft') - nextIndex = (currentIndex - 1 + TAB_ORDER.length) % TAB_ORDER.length; - if (event.key === 'Home') nextIndex = 0; - if (event.key === 'End') nextIndex = TAB_ORDER.length - 1; - if (nextIndex === undefined) return; - event.preventDefault(); - const nextTab = TAB_ORDER[nextIndex]; - if (nextTab === undefined) return; - setActiveTab(nextTab); - tabRefs.current[nextTab]?.focus(); - } - - return ( - -
- - -
- -

ONESHOT / ARC TESTNET

-

One job. Many retries. One settlement.

-

- A durable payment workflow with wallet policy checks, retry protection, and read-only - recovery on Arc. -

- -
- -
- -
-
- ARCHITECTURAL GUARANTEES -

Scoped payment safety

-
- -
-
-
01 / PAYMENT SAFETY
-

One payment per request

-

A stable request key keeps retries on one approved payment path.

-
- -
-
02 / WALLET POLICY
-

Approved before sending

-

- Destination, amount and spending rules are checked before the worker can submit a - payment. -

-
- -
-
03 / NETWORK EVIDENCE
-

Read-only recovery

-

- If a response is delayed, OneShot checks the ledger and network observations without - submitting another payment. -

-
- -
-
04 / REQUEST LIFECYCLE
-

Safe hold on uncertainty

-

- When payment proof is incomplete, the request pauses until it is verified. No second - payment is allowed. -

-
-
-
- -
-
- WORKSPACE -

Your payment workspace

-

- Run and protect API payments: create a request, review the exact payment, and inspect - proof only when you need it. -

-
- - -
- Open a request by identifier (advanced) - - setSelectedIntentId(event.target.value)} - placeholder="Create a request or enter its stable identifier" - /> -
- - - - {/* Keyed like the cabinet panel above, so switching tabs remounts - the panel and restarts the fade in `.tab-fade`. */} -
- {activeTab === 'create' ? ( - - ) : activeTab === 'status' ? ( - - ) : activeTab === 'settlement' ? ( - - ) : ( - - )} -
-
-
- -
-
-
-
- - OneShot -
-

- Stablecoin-native payment lifecycle engine with pre-flight policy gating and - subgraph recovery on Arc Testnet. -

-
- -
-
- NETWORK - Arc Testnet -
-
- SETTLEMENT ASSET - USDC -
-
-
- -
- OneShot Protocol · Built for Circle Arc Challenge - -
-
-
-
- ); + return ; } diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index f88a414..e2c2f30 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -393,16 +393,6 @@ a:hover { margin-bottom: 2.5rem; } -.section-eyebrow { - display: block; - margin-bottom: 0.5rem; - font-size: 0.75rem; - font-weight: 300; - letter-spacing: 0.16em; - color: var(--os-accent-ink); - font-family: var(--os-font-mono); -} - .section-header h2 { font-size: clamp(1.6rem, 3.5vw, 2.2rem); font-weight: 300; @@ -430,15 +420,6 @@ a:hover { transform: translateY(-3px); } -.invariant-index { - font-family: var(--os-font-mono); - font-size: 0.72rem; - font-weight: 300; - letter-spacing: 0.14em; - color: var(--os-accent-ink); - margin-bottom: 0.9rem; -} - .invariant-card h3 { font-size: 1.15rem; font-weight: 300; @@ -548,38 +529,6 @@ a:hover { border-top: 1px solid var(--os-line); } -/* ========================================================================== - Console Workspace Container - ========================================================================== */ - -.console-container { - margin: 3rem 0; - padding: 2rem; - border-radius: var(--os-radius-lg); - background: var(--os-panel); - color: var(--os-panel-ink); -} - -.console-header { - margin-bottom: 1.75rem; - padding-bottom: 1.25rem; - border-bottom: 1px solid var(--os-panel-line); -} - -.console-header h2 { - font-size: 1.6rem; - font-weight: 300; - color: var(--os-panel-ink); - margin-bottom: 0.4rem; -} - -.console-subtitle { - color: var(--os-panel-ink-muted); - font-size: 0.92rem; - line-height: 1.5; - margin-bottom: 0; -} - /* ========================================================================== Login Gate & Operator Authentication ========================================================================== */ @@ -798,47 +747,6 @@ a:hover { color: var(--os-ink-muted); } -/* ========================================================================== - Active Intent Context Bar - ========================================================================== */ - -.intent-context { - display: grid; - grid-template-columns: auto minmax(200px, 1fr); - align-items: center; - gap: 1rem; - margin: 1.25rem 0; - padding: 0.85rem 1.25rem; - background: var(--os-surface); - border: 1px solid var(--os-line); - border-radius: var(--os-radius-lg); - color: var(--os-ink); -} - -.intent-context label { - font-size: 0.85rem; - font-weight: 300; - color: var(--os-ink); - white-space: nowrap; -} - -.intent-context input { - width: 100%; - min-height: 42px; - padding: 0.65rem 0.9rem; - border: 1px solid var(--os-line); - border-radius: 999px; - background: var(--os-surface); - color: var(--os-ink); - font-family: var(--os-font-mono); - font-size: 0.9rem; - transition: border-color 0.2s ease; -} - -.intent-context input:focus { - border-color: var(--os-accent-ink); -} - /* ========================================================================== Tabs ========================================================================== */ @@ -1387,62 +1295,6 @@ a.secondary:hover { font: inherit; } -/* ========================================================================== - Footer - ========================================================================== */ - -.app-footer { - margin-top: 5rem; - padding: 3rem 1.5rem 1.5rem; - border-top: 1px solid var(--os-line); - color: var(--os-ink-muted); - font-size: 0.85rem; -} - -.footer-top { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 2.5rem; - margin-bottom: 2.5rem; -} - -.footer-brand { - max-width: 360px; - display: grid; - gap: 0.75rem; -} - -.footer-desc { - line-height: 1.6; - color: var(--os-ink-muted); - margin-bottom: 0; -} - -.footer-meta { - display: flex; - flex-wrap: wrap; - gap: 2rem; -} - -.meta-col { - display: grid; - gap: 0.3rem; -} - -.meta-label { - font-size: 0.7rem; - font-weight: 300; - letter-spacing: 0.12em; - color: var(--os-ink-muted); - font-family: var(--os-font-mono); -} - -.meta-value { - color: var(--os-ink); - font-weight: 300; -} - .meta-code { font-family: var(--os-font-mono); color: var(--os-accent-ink); @@ -1452,30 +1304,6 @@ a.secondary:hover { border: 1px solid var(--os-line); } -.footer-bottom { - display: flex; - align-items: center; - justify-content: space-between; - gap: 1rem; - padding-top: 1.5rem; - border-top: 1px solid var(--os-line); - font-size: 0.8rem; - color: var(--os-ink-muted); -} - -.footer-links { - display: flex; - gap: 1.25rem; -} - -.footer-links a { - color: var(--os-ink-muted); -} - -.footer-links a:hover { - color: var(--os-accent-ink); -} - /* ========================================================================== Theme Toggle, Hero Cut & Wallet Picker ========================================================================== */ @@ -1606,9 +1434,7 @@ a.secondary:hover { body, .top-nav, .panel, - .console-container, .login-gate, - .intent-context, .job-list li, .advanced-fields, .composed-surface, @@ -1683,14 +1509,6 @@ a.secondary:hover { grid-template-columns: 1fr; } - .console-container { - padding: 1.25rem 1rem; - } - - .intent-context { - grid-template-columns: 1fr; - } - .payment-grid { grid-template-columns: 1fr; } @@ -1709,11 +1527,6 @@ a.secondary:hover { .fixture-toolbar select { width: 100%; } - - .footer-bottom { - flex-direction: column; - align-items: flex-start; - } } /* ======================================================================== @@ -2036,7 +1849,6 @@ a.secondary:hover { } /* Match ink to its actual surface, including cards nested in dark panels. */ -.console-container, .login-gate, .invariant-card, .panel, @@ -2046,14 +1858,6 @@ a.secondary:hover { --os-accent-ink: var(--os-signal); } -.console-container .tabs button { - color: var(--os-panel-ink); -} - -.console-container .tabs button[aria-selected='true'] { - color: var(--os-on-signal); -} - .hero-plain h1, .hero-copy h1, .hero-plain .btn-hero-secondary, diff --git a/apps/web/test/app-auth.test.tsx b/apps/web/test/app-auth.test.tsx index 9c4538e..933c47d 100644 --- a/apps/web/test/app-auth.test.tsx +++ b/apps/web/test/app-auth.test.tsx @@ -41,8 +41,10 @@ describe('App operator gating', () => { headers: { 'content-type': 'application/json' }, }), ); - render( fakeSession()} />); - expect(screen.queryByRole('tab', { name: 'Create request' })).toBeNull(); + render( + fakeSession()} />, + ); + expect(screen.queryByRole('tab', { name: 'Payment services' })).toBeNull(); expect(screen.getByRole('button', { name: 'Sign in with Privy' })).toBeTruthy(); }); @@ -54,20 +56,23 @@ describe('App operator gating', () => { headers: { 'content-type': 'application/json' }, }), ); - render( signedInSession()} />); - expect(screen.getByRole('tab', { name: 'Create request' })).toBeTruthy(); + render( + signedInSession()} + />, + ); + expect(screen.getByRole('tab', { name: 'Payment services' })).toBeTruthy(); }); it('sends the Privy access token on an authenticated request', async () => { const seen: string[] = []; vi.stubGlobal('fetch', respondingFetch(seen)); - const user = userEvent.setup(); - render( signedInSession('did:privy:x', 'aaa.bbb.ccc')} />); - - await user.click(screen.getByRole('tab', { name: 'Payment status' })); - await user.type(screen.getByPlaceholderText('Request identifier'), 'intent-1'); - await user.click(screen.getByRole('button', { name: 'Look up' })); + render( + signedInSession('did:privy:x', 'aaa.bbb.ccc')} />, + ); await waitFor(() => expect(seen).toContain('Bearer aaa.bbb.ccc')); }); @@ -77,14 +82,12 @@ describe('App operator gating', () => { vi.stubGlobal('fetch', respondingFetch(seen)); const user = userEvent.setup(); - render( fakeSession({ status: 'UNCONFIGURED' })} />); + render( fakeSession({ status: 'UNCONFIGURED' })} />); await user.click(screen.getByText('Machine token (advanced)')); await user.type(screen.getByLabelText('Machine token'), 'service-token'); - await user.click(screen.getByRole('tab', { name: 'Payment status' })); - await user.type(screen.getByPlaceholderText('Request identifier'), 'intent-1'); - await user.click(screen.getByRole('button', { name: 'Look up' })); + await user.click(screen.getByRole('tab', { name: 'Payment proof' })); await waitFor(() => expect(seen).toContain('Bearer service-token')); }); }); diff --git a/apps/web/test/app-composition.test.tsx b/apps/web/test/app-composition.test.tsx index 319daed..6796c1d 100644 --- a/apps/web/test/app-composition.test.tsx +++ b/apps/web/test/app-composition.test.tsx @@ -1,4 +1,4 @@ -import { createInMemoryRecoveryClient, recoveryScenarioPages } from '@oneshot/recovery-ui'; +import { createInMemoryRecoveryClient } from '@oneshot/recovery-ui'; import { createInMemorySettlementClient, SETTLEMENT_SCENARIO_INTENTS, @@ -310,63 +310,11 @@ describe('Gate P5 shell composition', () => { expect(loadedFade).not.toBe(waitingFade); cabinet.unmount(); - - // The console route's own tab panel was the one that never faded at all. - const { container } = render( - signedInSession()} - apiClient={ - new OneShotApiClient({ - fetchFn: async () => - new Response(JSON.stringify({ status: 'ok' }), { - status: 200, - headers: { 'content-type': 'application/json' }, - }), - }) - } - settlementClient={createInMemorySettlementClient(SETTLEMENT_SCENARIO_INTENTS)} - recoveryClient={createInMemoryRecoveryClient('lagging')} - />, - ); - expect(container.querySelector('main[role="tabpanel"]')?.className).toContain('tab-fade'); }); - it('mounts A05, B05, and C05 without a settlement bypass', async () => { - const settlementIntent = Object.values(SETTLEMENT_SCENARIO_INTENTS)[0]; - if (!settlementIntent) throw new Error('Settlement fixture missing'); - const apiClient = new OneShotApiClient({ - fetchFn: async () => - new Response(JSON.stringify({ status: 'ok' }), { - status: 200, - headers: { 'content-type': 'application/json' }, - }), - }); - const user = userEvent.setup(); - render( - signedInSession()} - />, - ); - expect(screen.getByRole('heading', { name: 'Your payment workspace', level: 2 })).toBeTruthy(); - - await user.type( - screen.getByLabelText('Request identifier'), - settlementIntent.business_intent_id, - ); - await user.click(screen.getByRole('tab', { name: 'Payment proof' })); - expect(await screen.findByText('Authorization')).toBeTruthy(); - - await user.clear(screen.getByLabelText('Request identifier')); - await user.type( - screen.getByLabelText('Request identifier'), - recoveryScenarioPages.lagging[0]?.businessIntentId ?? '', - ); - await user.click(screen.getByRole('tab', { name: 'Recovery control' })); - expect(await screen.findByText('Subgraph MCP')).toBeTruthy(); - expect(screen.getByText('LAGGING')).toBeTruthy(); - expect(screen.queryByRole('button', { name: /force|pay|submit settlement/iu })).toBeNull(); + it('unknown routes show the public landing instead of the retired console', () => { + render(); + expect(screen.getByRole('main', { name: 'OneShot public landing page' })).toBeTruthy(); + expect(screen.queryByRole('tablist')).toBeNull(); }); }); diff --git a/apps/web/test/composition.test.tsx b/apps/web/test/composition.test.tsx index 7035439..f44a2cb 100644 --- a/apps/web/test/composition.test.tsx +++ b/apps/web/test/composition.test.tsx @@ -1,5 +1,4 @@ import { cleanup, render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { SETTLEMENT_SCENARIO_INTENTS, @@ -7,77 +6,21 @@ import { } from '@oneshot/settlement-ui'; import { createInMemoryRecoveryClient, recoveryScenarioPages } from '@oneshot/recovery-ui'; -import { App } from '../src/App.js'; -import { SettlementSurface } from '../src/components/FrontendSurfaces.js'; -import { signedInSession } from './support/fake-session.js'; +import { RecoverySurface, SettlementSurface } from '../src/components/FrontendSurfaces.js'; afterEach(() => { cleanup(); vi.unstubAllGlobals(); }); -function json(status: number, body: unknown): Response { - return new Response(JSON.stringify(body), { - status, - headers: { 'content-type': 'application/json' }, - }); -} - describe('composed frontend shell', () => { - it('exposes A05, B05, and C05 surfaces without a payment action', async () => { - vi.stubGlobal('fetch', async (input: RequestInfo | URL) => { - if (String(input).endsWith('/health/ready')) return json(200, { status: 'ok' }); - return json(404, { code: 'INTENT_NOT_FOUND', message: 'Fixture lookup is empty.' }); - }); - - const user = userEvent.setup(); + it('keeps recovery evidence read-only', async () => { render( - signedInSession()} + , ); - - expect(screen.getByRole('tab', { name: 'Create request' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Payment status' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Payment proof' })).toBeTruthy(); - expect(screen.getByRole('tab', { name: 'Recovery control' })).toBeTruthy(); - - const createTab = screen.getByRole('tab', { name: 'Create request' }); - createTab.focus(); - await user.keyboard('{ArrowRight}'); - expect(screen.getByRole('tab', { name: 'Payment status' }).getAttribute('aria-selected')).toBe( - 'true', - ); - expect(document.activeElement).toBe(screen.getByRole('tab', { name: 'Payment status' })); - - await user.keyboard('{ArrowLeft}'); - expect(screen.getByRole('tab', { name: 'Create request' }).getAttribute('aria-selected')).toBe( - 'true', - ); - expect(document.activeElement).toBe(screen.getByRole('tab', { name: 'Create request' })); - - await user.keyboard('{End}'); - expect( - screen.getByRole('tab', { name: 'Recovery control' }).getAttribute('aria-selected'), - ).toBe('true'); - expect(document.activeElement).toBe(screen.getByRole('tab', { name: 'Recovery control' })); - - await user.keyboard('{Home}'); - expect(screen.getByRole('tab', { name: 'Create request' }).getAttribute('aria-selected')).toBe( - 'true', - ); - expect(document.activeElement).toBe(screen.getByRole('tab', { name: 'Create request' })); - - await user.click(screen.getByRole('tab', { name: 'Payment proof' })); - expect(await screen.findByText(/Select a request to inspect payment proof/u)).toBeTruthy(); - expect(screen.queryByRole('button', { name: /pay|retry|resend|force/iu })).toBeNull(); - - await user.click(screen.getByRole('tab', { name: 'Recovery control' })); - await user.type( - screen.getByLabelText('Request identifier'), - recoveryScenarioPages.lagging[0]?.businessIntentId ?? '', - ); expect(await screen.findByText('LAGGING')).toBeTruthy(); expect(screen.getByText('Subgraph MCP')).toBeTruthy(); expect(screen.queryByRole('button', { name: /pay|retry|resend|force/iu })).toBeNull(); diff --git a/apps/worker/src/worker.ts b/apps/worker/src/worker.ts index f1b54e0..1e8d743 100644 --- a/apps/worker/src/worker.ts +++ b/apps/worker/src/worker.ts @@ -173,15 +173,6 @@ export async function runStartupRecovery( return recovered.length; } -export async function resumeSafeJobs( - options: WorkerOptions, - maxJobs = 100, -): Promise<{ readonly recoveredOrphans: number; readonly drainedJobs: number }> { - const recoveredOrphans = await runStartupRecovery(options); - const drainedJobs = await drainOutboxJobs(options, maxJobs); - return { recoveredOrphans, drainedJobs }; -} - export async function executeReconcileIntent( businessIntentId: string, options: WorkerOptions, diff --git a/docs/RESTART_RUNNER.md b/docs/RESTART_RUNNER.md index 630572b..02a349e 100644 --- a/docs/RESTART_RUNNER.md +++ b/docs/RESTART_RUNNER.md @@ -26,5 +26,4 @@ flowchart TD ## Methods - `runStartupRecovery(options, leaseDurationMs)`: Scans for orphaned `SUBMITTING` records older than the lease threshold (default 30 seconds), transitions them to `UNKNOWN`, and enqueues a `reconcile_intent` outbox job. -- `resumeSafeJobs(options, maxJobs)`: Combines startup recovery and outbox draining in one call. - `RestartRunner.start()`: Runs startup recovery on initialization and starts a non-blocking background timer for ongoing lease enforcement. diff --git a/docs/settlement/B06_SPONSOR_EVIDENCE.md b/docs/settlement/B06_SPONSOR_EVIDENCE.md index 9a451b7..1e49d94 100644 --- a/docs/settlement/B06_SPONSOR_EVIDENCE.md +++ b/docs/settlement/B06_SPONSOR_EVIDENCE.md @@ -110,7 +110,7 @@ Activation requires all of: Deployment and rollback artifacts verified present: `docs/SAFE_DISABLE_RUNBOOK.md`, `docs/SERVER_RUNTIME.md`, `docs/settlement/SETTLEMENT_CONFIG_V1.md`, -`docs/settlement/PROVIDER_SETUP.md`, and `Dockerfile.api`. +`docs/settlement/PROVIDER_SETUP.md`, and `Dockerfile`. ## B06.5 — Sanitization audit diff --git a/packages/contracts/src/ports.ts b/packages/contracts/src/ports.ts index 6a11531..e7dd713 100644 --- a/packages/contracts/src/ports.ts +++ b/packages/contracts/src/ports.ts @@ -156,7 +156,3 @@ export function parseRecoveryAction(value: unknown): RecoveryAction { throw new ContractValidationError(`unknown recovery action: ${String(value)}`); } } - -export function assertNever(value: never, context: string): never { - throw new ContractValidationError(`${context}: ${String(value)}`); -} diff --git a/packages/reconciliation/src/recovery-matrix.ts b/packages/reconciliation/src/recovery-matrix.ts index e10fc0a..6d315de 100644 --- a/packages/reconciliation/src/recovery-matrix.ts +++ b/packages/reconciliation/src/recovery-matrix.ts @@ -213,28 +213,3 @@ export async function runRecoveryMatrix(): Promise return [...(await runServiceRows()), ...chaosRows]; } - -export function renderRecoveryMatrixMarkdown(rows: readonly RecoveryMatrixRow[]): string { - const header = - '| Scenario | Stable intent | Start | Final | Evidence | Authority | Freshness | Decision | External submissions | Pass |'; - const divider = '| --- | --- | --- | --- | --- | --- | --- | --- | ---: | --- |'; - const body = rows.map((row) => - [ - row.scenario, - row.stableIntent, - row.startingState, - row.finalState, - row.evidenceSources.join(' + ') || 'NONE', - row.authorityClasses.join(' + ') || 'NONE', - row.freshness, - row.decision, - String(row.externalSubmissionCount), - row.passed ? 'PASS' : 'FAIL', - ] - .map((cell) => cell.replaceAll('|', '\\|')) - .join(' | ') - .replace(/^/u, '| ') - .replace(/$/u, ' |'), - ); - return [header, divider, ...body].join('\n'); -} diff --git a/packages/settlement-ui/src/fixtures.ts b/packages/settlement-ui/src/fixtures.ts index c47d8bf..58579d0 100644 --- a/packages/settlement-ui/src/fixtures.ts +++ b/packages/settlement-ui/src/fixtures.ts @@ -238,7 +238,3 @@ export const SETTLEMENT_SCENARIO_INTENTS: Readonly): SanitizedSettlementProof { From d8fa8827a008083aeeabcd3ce742496e55340f2e Mon Sep 17 00:00:00 2001 From: kapustazh <51422901+kapustazh@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:10:59 +0200 Subject: [PATCH 2/2] docs: record cleanup PR handoff --- .agent/context/20261008T170745Z-remove-legacy-leftovers.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.agent/context/20261008T170745Z-remove-legacy-leftovers.md b/.agent/context/20261008T170745Z-remove-legacy-leftovers.md index c1fbe12..8694b28 100644 --- a/.agent/context/20261008T170745Z-remove-legacy-leftovers.md +++ b/.agent/context/20261008T170745Z-remove-legacy-leftovers.md @@ -68,8 +68,9 @@ Prior session instructions: do not reopen closed PRs; omit FreePi. - Branch: feature/remove-legacy-leftovers. - Base develop: 55a387abad228d61c7a0a7a911299c103495bda0. -- Commit/PR: pending validation; new draft PR, never reopen a closed PR. -- CI: pending push. +- Implementation commit: b7683c9. +- PR: [#151](https://github.com/SWOFART/OneShot/pull/151), new draft against develop. +- CI: triggered on pushed head; pending at creation. ## Review gates @@ -78,5 +79,5 @@ Prior session instructions: do not reopen closed PRs; omit FreePi. ## Handoff/next steps -1. Finish browser checks, push focused change, and create new draft PR. +1. Local checks pass; draft PR created. Monitor remote CI. 2. Human reviews and merges; agent does not merge.