diff --git a/.claude/rules/backend_contract_migration.md b/.claude/rules/backend_contract_migration.md index 1e9addf8c..be1192de5 100644 --- a/.claude/rules/backend_contract_migration.md +++ b/.claude/rules/backend_contract_migration.md @@ -1,9 +1,9 @@ --- paths: - - "convex/**/*.ts" - - "server/**/*.ts" + - "backend/convex/**/*.ts" + - "workers/node/**/*.ts" - "public/proto/*.html" - - "src/**/*.{ts,tsx}" + - "apps/web/src/**/*.{ts,tsx}" related_: [live_dom_verification, agentic_reliability, owner_mode_end_to_end, completion_traceability] --- @@ -41,7 +41,7 @@ contract, ship in **three PRs**, not one: - Old callers keep working; new callers can opt in. - For a rename: export both names, both pointing at the same handler. ```ts - // convex/events.ts + // backend/convex/events.ts const composeAnswerHandler = mutation({ /* ... */ }); export const composeAnswer = composeAnswerHandler; export const askAgent = composeAnswerHandler; // legacy alias @@ -101,9 +101,9 @@ If verification fails at any step, do not proceed to the next step. ## Contract path discipline (added 2026-05-27) -**Every Convex contract MUST specify the deployed path as `:`, not just the export name.** Convex resolves paths by filename — putting `requestSignInLink` in `convex/users.ts` deploys it at `users:requestSignInLink`, not `events:requestSignInLink`, regardless of what the contract doc says. +**Every Convex contract MUST specify the deployed path as `:`, not just the export name.** Convex resolves paths by filename — putting `requestSignInLink` in `backend/convex/users.ts` deploys it at `users:requestSignInLink`, not `events:requestSignInLink`, regardless of what the contract doc says. -Case study — PR #407/#409 hotfix (2026-05-27): the Step 8 contract specified mutations as `events:requestSignInLink` / `events:verifySignInToken` / `events:listMyEvents` to match the existing scratchnode namespace. The implementing agent put them in `convex/users.ts` (sensible — `events.ts` was overloaded). Deployed paths became `users:*`. Frontend and dogfood script kept calling `events:*` — silent function-not-found at runtime. Convex's HTTP API masks this as a generic "Server Error" message, hiding the mismatch from CI. +Case study — PR #407/#409 hotfix (2026-05-27): the Step 8 contract specified mutations as `events:requestSignInLink` / `events:verifySignInToken` / `events:listMyEvents` to match the existing scratchnode namespace. The implementing agent put them in `backend/convex/users.ts` (sensible — `events.ts` was overloaded). Deployed paths became `users:*`. Frontend and dogfood script kept calling `events:*` — silent function-not-found at runtime. Convex's HTTP API masks this as a generic "Server Error" message, hiding the mismatch from CI. ### Required contract format @@ -113,13 +113,13 @@ events:requestSignInLink({ email }) → { ok } // ✅ GOOD — deployed path is explicit users:requestSignInLink({ email }) → { ok } -// implemented in convex/users.ts as `export const requestSignInLink = mutation({...})` +// implemented in backend/convex/users.ts as `export const requestSignInLink = mutation({...})` ``` If the contract author wants the path to be `events:*` despite the implementation living in another file, the implementing PR must add an explicit re-export: ```ts -// convex/events.ts +// backend/convex/events.ts export { requestSignInLink, verifySignInToken, listMyEvents } from "./users"; ``` diff --git a/.claude/rules/dogfood_verification.md b/.claude/rules/dogfood_verification.md index f0029436c..582196bbf 100644 --- a/.claude/rules/dogfood_verification.md +++ b/.claude/rules/dogfood_verification.md @@ -88,9 +88,9 @@ Runs a full Scribe-like dogfood session locally and makes it UI-verifiable at `/ | Layer | Changes to | Deployed via | Visible when | |-------|-----------|-------------|--------------| -| React components | `.tsx` in `src/` | `vite build` | Preview server restarted | -| Convex functions | `.ts` in `convex/` | `npx convex deploy` | Backend redeployed | -| Convex schema | `convex/schema.ts` | `npx convex deploy` | Backend redeployed | +| React components | `.tsx` in `apps/web/src/` | `vite build` | Preview server restarted | +| Convex functions | `.ts` in `backend/convex/` | `npx convex deploy` | Backend redeployed | +| Convex schema | `backend/convex/schema.ts` | `npx convex deploy` | Backend redeployed | | MCP tools | `packages/mcp-local/` | `npx tsc` in package | MCP server restarted | | Stored data | DB records | Data migration or mutation | After migration runs | | Dashboard HTML | `briefHtml.ts` / `html.ts` | Inline — restart server | Server restarted | diff --git a/.claude/rules/eval_flywheel.md b/.claude/rules/eval_flywheel.md index 319a89cab..de0bec8c2 100644 --- a/.claude/rules/eval_flywheel.md +++ b/.claude/rules/eval_flywheel.md @@ -3,7 +3,7 @@ Continuous self-improving eval loop for the NodeBench search pipeline. The system judges itself, diagnoses failures, fixes them, and loops until 100%. ## When to activate -- After any change to `server/routes/search.ts` or search-related tools +- After any change to `workers/node/routes/search.ts` or search-related tools - User says "run eval", "flywheel", "judge loop", "reach 100%" - After completing any implementation sprint touching search, entity enrichment, or result rendering - Automatically after deploying search changes @@ -109,10 +109,10 @@ Always do deep research before declaring a blocker permanent. The system should ## Key files - `packages/mcp-local/src/benchmarks/searchQualityEval.ts` — Eval harness (100+ queries, Gemini judge) - `packages/mcp-local/src/benchmarks/llmJudgeEval.ts` — Chained pipeline eval (tool A → tool B) -- `server/routes/search.ts` — Search route with 4-layer grounding pipeline +- `workers/node/routes/search.ts` — Search route with 4-layer grounding pipeline - `packages/mcp-local/src/tools/entityEnrichmentTools.ts` — Entity enrichment MCP tools - `packages/mcp-local/src/tools/webTools.ts` — web_search implementation -- `convex/tools/media/linkupSearch.ts` — Linkup search (Convex-side) +- `backend/convex/tools/media/linkupSearch.ts` — Linkup search (Convex-side) ## Anti-patterns - Declaring done at 80% because "the remaining 20% is hard" diff --git a/.claude/rules/forecasting_os.md b/.claude/rules/forecasting_os.md index 8e44ae437..7f4b4baa2 100644 --- a/.claude/rules/forecasting_os.md +++ b/.claude/rules/forecasting_os.md @@ -1,12 +1,12 @@ --- paths: - - "convex/domains/forecasting/**" - - "convex/workflows/dailyLinkedInPost.ts" - - "src/features/research/components/Forecast*" - - "src/features/research/components/CalibrationPlot*" - - "src/features/research/components/BrierTrendChart*" - - "src/features/research/components/EvidenceTimeline*" - - "src/features/research/components/TraceBreadcrumb*" + - "backend/convex/domains/forecasting/**" + - "backend/convex/workflows/dailyLinkedInPost.ts" + - "apps/web/src/features/research/components/Forecast*" + - "apps/web/src/features/research/components/CalibrationPlot*" + - "apps/web/src/features/research/components/BrierTrendChart*" + - "apps/web/src/features/research/components/EvidenceTimeline*" + - "apps/web/src/features/research/components/TraceBreadcrumb*" - "packages/mcp-local/src/tools/forecastingTools.ts" related_: [reexamine_process, analyst_diagnostic, completion_traceability, reexamine_resilience] --- @@ -32,13 +32,13 @@ related_: [reexamine_process, analyst_diagnostic, completion_traceability, reexa ## Key files | File | Purpose | |------|---------| -| `convex/domains/forecasting/forecastManager.ts` | CRUD + 6 public dashboard queries | -| `convex/domains/forecasting/signalMatcher.ts` | Deterministic signal↔forecast cross-reference | -| `convex/domains/forecasting/traceWrapper.ts` | TRACE-wrapped forecast refresh (6 audit steps) | -| `convex/domains/forecasting/scoringEngine.ts` | Brier + log scoring, proper scoring rules | -| `convex/domains/forecasting/schema.ts` | 5 tables: forecasts, forecastEvidence, forecastResolutions, forecastUpdateHistory, forecastCalibrationLog | -| `convex/workflows/dailyLinkedInPost.ts` | LinkedIn pipeline with Δ badges, evidence links, TRACE | -| `src/features/research/components/ForecastCockpit.tsx` | Dashboard assembler (CalibrationPlot, BrierTrendChart, ForecastCard) | +| `backend/convex/domains/forecasting/forecastManager.ts` | CRUD + 6 public dashboard queries | +| `backend/convex/domains/forecasting/signalMatcher.ts` | Deterministic signal↔forecast cross-reference | +| `backend/convex/domains/forecasting/traceWrapper.ts` | TRACE-wrapped forecast refresh (6 audit steps) | +| `backend/convex/domains/forecasting/scoringEngine.ts` | Brier + log scoring, proper scoring rules | +| `backend/convex/domains/forecasting/schema.ts` | 5 tables: forecasts, forecastEvidence, forecastResolutions, forecastUpdateHistory, forecastCalibrationLog | +| `backend/convex/workflows/dailyLinkedInPost.ts` | LinkedIn pipeline with Δ badges, evidence links, TRACE | +| `apps/web/src/features/research/components/ForecastCockpit.tsx` | Dashboard assembler (CalibrationPlot, BrierTrendChart, ForecastCard) | | `packages/mcp-local/src/tools/forecastingTools.ts` | 9 MCP tools | ## Conventions diff --git a/.claude/rules/gemini_qa_loop.md b/.claude/rules/gemini_qa_loop.md index 1a5bae4c0..a510311fb 100644 --- a/.claude/rules/gemini_qa_loop.md +++ b/.claude/rules/gemini_qa_loop.md @@ -20,7 +20,7 @@ npx vite build npx vite preview --host 127.0.0.1 --port 4173 & # 3. Capture screenshots via e2e test -BASE_URL=http://127.0.0.1:4173 npx playwright test tests/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 +BASE_URL=http://127.0.0.1:4173 npx playwright test evals/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 # 4. Publish screenshots to public/dogfood/ npm run dogfood:publish @@ -92,9 +92,9 @@ Pattern: **Pro → Flash → Flash → Flash → Pro → Flash → Flash → Fla - 60% cost reduction while maintaining Pro-quality baseline analysis ### Config files -- `convex/domains/dogfood/screenshotQa.ts` — Screenshot QA action -- `convex/domains/dogfood/videoQa.ts` — Video QA action -- `convex/domains/dogfood/videoQaQueries.ts` — `getLatestProAnalysis` query for reference injection +- `backend/convex/domains/dogfood/screenshotQa.ts` — Screenshot QA action +- `backend/convex/domains/dogfood/videoQa.ts` — Video QA action +- `backend/convex/domains/dogfood/videoQaQueries.ts` — `getLatestProAnalysis` query for reference injection ## Multi-Variant Coverage @@ -125,12 +125,12 @@ This returns the step-by-step workflow chain with tool references and shell comm | File | Purpose | |------|---------| -| `convex/domains/dogfood/screenshotQa.ts` | Screenshot QA action (Gemini Flash + Jony Ive prompts) | -| `convex/domains/dogfood/videoQa.ts` | Video QA action (Gemini Flash + Jony Ive prompts) | +| `backend/convex/domains/dogfood/screenshotQa.ts` | Screenshot QA action (Gemini Flash + Jony Ive prompts) | +| `backend/convex/domains/dogfood/videoQa.ts` | Video QA action (Gemini Flash + Jony Ive prompts) | | `scripts/ui/runDogfoodGeminiQa.mjs` | CLI orchestrator for QA pipeline | | `scripts/ui/recordDogfoodWalkthrough.mjs` | Playwright video recorder | | `scripts/ui/publishDogfoodGallery.mjs` | Screenshot publisher (variant-aware manifest) | -| `tests/e2e/full-ui-dogfood.spec.ts` | E2e 4-variant screenshot capture test | +| `evals/e2e/full-ui-dogfood.spec.ts` | E2e 4-variant screenshot capture test | | `public/dogfood/qa-results.json` | QA score history | | `.tmp/dogfood-gemini-qa/*.json` | Latest QA results (screens + video) | | `shared/llm/modelCatalog.ts` | Model catalog with Gemini defaults | diff --git a/.claude/rules/grounded_eval.md b/.claude/rules/grounded_eval.md index 963046971..9b31414fa 100644 --- a/.claude/rules/grounded_eval.md +++ b/.claude/rules/grounded_eval.md @@ -16,7 +16,7 @@ Before extraction, check source quality: - **medium**: 1-2 snippets — extract conservatively, flag as limited - **low**: 0 snippets — return "insufficient data" template, do NOT generate -Implementation: `retrievalConfidence` in `server/routes/search.ts` +Implementation: `retrievalConfidence` in `workers/node/routes/search.ts` ### Layer 2: Claim-Level Grounding Filter After Gemini extraction, verify each claim against source text: @@ -57,7 +57,7 @@ Implementation: `sourceIdx` field on signals, changes, risks in response - If judge variance exceeds 10% across runs, use majority vote (3x calls) ## Key files -- `server/routes/search.ts` — Layers 1-2 and 4 (retrieval, filter, citations) +- `workers/node/routes/search.ts` — Layers 1-2 and 4 (retrieval, filter, citations) - `packages/mcp-local/src/benchmarks/searchQualityEval.ts` — Layer 3 (grounded judge) - `packages/mcp-local/src/benchmarks/llmJudgeEval.ts` — Chain coherence criterion diff --git a/.claude/rules/live_dom_verification.md b/.claude/rules/live_dom_verification.md index 7da2f2470..6a03c6b8c 100644 --- a/.claude/rules/live_dom_verification.md +++ b/.claude/rules/live_dom_verification.md @@ -61,7 +61,7 @@ hydrates + Convex queries resolve. That means: return 200 not 404. Catches landmines (a) and (c). Does NOT prove: routes actually render the right component. -- **Tier B (tests/e2e/live-smoke.spec.ts via `npm run live-smoke`)** — +- **Tier B (evals/e2e/live-smoke.spec.ts via `npm run live-smoke`)** — Playwright loads each URL in a real browser, waits for hydration, asserts DOM nodes exist (e.g. "Link not found" on `/share/dummy`, `

` on landing, recovery CTAs visible). diff --git a/.claude/rules/pipeline_operational_standard.md b/.claude/rules/pipeline_operational_standard.md index bda9a7001..b10b8816c 100644 --- a/.claude/rules/pipeline_operational_standard.md +++ b/.claude/rules/pipeline_operational_standard.md @@ -34,7 +34,7 @@ instrument → judge → persist → surface → measure → regress. `reportsTokenCounts`, `capturedSources`, `emitStatusIsTerminal`. Order is stable — dashboards rely on it. Add a gate by extending `GATE_ORDER` -in `server/pipeline/diligenceJudge.ts`. +in `workers/node/pipeline/diligenceJudge.ts`. ## Verdict tiers (bounded enum) - `verified` — 0 failures, ≤ 2 skipped @@ -45,7 +45,7 @@ in `server/pipeline/diligenceJudge.ts`. ## Verification floor 1. `npx convex codegen` 2. `npx tsc --noEmit` -3. `npx vitest run server/pipeline/diligenceJudge.test.ts server/pipeline/diligenceProjectionWriter.test.ts` +3. `npx vitest run workers/node/pipeline/diligenceJudge.test.ts workers/node/pipeline/diligenceProjectionWriter.test.ts` 4. `npm run build` 5. `npm run dogfood:verify:smoke` when the UI changed diff --git a/.claude/rules/pre_release_review.md b/.claude/rules/pre_release_review.md index 59e117c1d..be1e18305 100644 --- a/.claude/rules/pre_release_review.md +++ b/.claude/rules/pre_release_review.md @@ -106,7 +106,7 @@ If Convex is NOT deployed: - [ ] "Sign in" messages appear where expected ### Layer 10: WebSocket Gateway (< 3 min) -If gateway is running (`npx tsx server/index.ts`): +If gateway is running (`npx tsx workers/node/index.ts`): - [ ] `GET /health` returns 200 - [ ] `GET /mcp/health` returns session count - [ ] WebSocket connects with valid API key @@ -133,8 +133,8 @@ Test in at least one non-Chrome browser (Safari, Firefox, or Edge): ### Layer 13: Regression Risks (< 2 min) Check these known fragile areas: -- [ ] Voice server: if `server/index.ts` was modified, verify voice WebSocket still works -- [ ] Schema changes: if `convex/schema.ts` was modified, verify migration compatibility +- [ ] Voice server: if `workers/node/index.ts` was modified, verify voice WebSocket still works +- [ ] Schema changes: if `backend/convex/schema.ts` was modified, verify migration compatibility - [ ] Tool count: grep for hardcoded "289", "297", "304" — must all match current reality - [ ] Print: if Decision Memo or Postmortem was modified, verify print stylesheet (if exists) - [ ] OG tags: if `index.html` was modified, verify meta tags are correct diff --git a/.claude/rules/product_design_dogfood.md b/.claude/rules/product_design_dogfood.md index ec9747767..e5f0a5bf7 100644 --- a/.claude/rules/product_design_dogfood.md +++ b/.claude/rules/product_design_dogfood.md @@ -1,8 +1,8 @@ --- paths: - - "src/**/*.tsx" - - "src/**/*.css" - - "tests/e2e/**/*.ts" + - "apps/web/src/**/*.tsx" + - "apps/web/src/**/*.css" + - "evals/e2e/**/*.ts" - "scripts/ui/**/*.mjs" related_: [analyst_diagnostic, dogfood_verification, reexamine_design_reduction, completion_traceability] --- diff --git a/.claude/rules/reference_attribution.md b/.claude/rules/reference_attribution.md index 841257b88..d6fdfb57f 100644 --- a/.claude/rules/reference_attribution.md +++ b/.claude/rules/reference_attribution.md @@ -58,7 +58,7 @@ from topic files rather than persisting it directly." Honest > embellished. ## What this rule enforces - New architecture docs have a "Prior art" section or the PR is rejected -- New server/pipeline/ or convex/domains/ modules have a file header comment linking their doc +- New workers/node/pipeline/ or backend/convex/domains/ modules have a file header comment linking their doc - When copying a Claude Code skill, cite `.claude/skills/` in the new skill's frontmatter ## Anti-patterns diff --git a/.claude/rules/self_improvement_loop.md b/.claude/rules/self_improvement_loop.md index 82c605019..62db0ebeb 100644 --- a/.claude/rules/self_improvement_loop.md +++ b/.claude/rules/self_improvement_loop.md @@ -1,13 +1,13 @@ # Self-Improvement Loop — Operating Manual The agent brain for NodeBench's continuous improvement flywheel. Read this on every loop cycle -(manual or scheduled). The deterministic substrate is `scripts/improvement-loop/`; this rule is +(manual or scheduled). The deterministic substrate is `adw/improvement-loop/`; this rule is how the agent drives it. Canonical design: `docs/architecture/SELF_IMPROVEMENT_LOOP.md`. ## Operating model: bounded + goal-driven (NOT "never stop") -This loop is governed by the Self-Directed Development OS in [`goals/README.md`](../../goals/README.md) -and the hard gates in [`goals/HARD_GATES.md`](../../goals/HARD_GATES.md). The lesson is **not** +This loop is governed by the Self-Directed Development OS in [`adw/goals/README.md`](../../goals/README.md) +and the hard gates in [`adw/goals/HARD_GATES.md`](../../goals/HARD_GATES.md). The lesson is **not** "let the agent run forever" — it is: closed goal, reviewable definition of done, focused subagents, hard gates, batch feedback. @@ -18,7 +18,7 @@ hard gates, batch feedback. - **Cadence:** daily small-loop (propose ONE bounded next step; only tiny CI-gated detector fixes auto-ship, ≤3/day) + weekly self-review (propose issues/cuts/goals, never auto-add features). - Substantive work becomes a Goal Card (`goals//NNN-slug.md`) the founder approves. + Substantive work becomes a Goal Card (`adw/goals//NNN-slug.md`) the founder approves. - **Operating rule:** Human sets the *why* + boundary; agent explores the *how*; tests decide; docs preserve. - **Hard gates:** prod deploy, destructive migrations, auth, billing, public/private permission rules, data deletion, legal/privacy copy, wiki publish, host/mod privileges, secrets → propose only. @@ -32,7 +32,7 @@ hard gates, batch feedback. ### 1. OBSERVE + SCORE ```bash -node scripts/improvement-loop/run-cycle.mjs --effort-budget 3 +node adw/improvement-loop/run-cycle.mjs --effort-budget 3 ``` This runs `scan.mjs`, writes `backlog.latest.json`, selects the top auto-safe opportunity, and appends a cycle to `ledger.json`. @@ -84,7 +84,7 @@ If the change would touch any of these, it is **human-gated** — queue it, do N - Shipping a fix for a false-positive scanner hit (validate first). - Auto-shipping a human-gated change. - Claiming "live" on a green build (live-DOM verify first — `live_dom_verification.md`). -- Building a parallel loop instead of extending `scripts/improvement-loop/` + the existing dogfood/eval scripts. +- Building a parallel loop instead of extending `adw/improvement-loop/` + the existing dogfood/eval scripts. ## Related rules - `flywheel_continuous` · `self_building_loop` · `eval_flywheel` · `analyst_diagnostic` diff --git a/.claude/rules/telemetry_trajectory.md b/.claude/rules/telemetry_trajectory.md index b176f5b3e..f794d568f 100644 --- a/.claude/rules/telemetry_trajectory.md +++ b/.claude/rules/telemetry_trajectory.md @@ -10,7 +10,7 @@ Make telemetry and agent step trajectories measurable, debuggable, and beautiful ## Dev-side telemetry (internal) -### Search trace (server/routes/search.ts) +### Search trace (workers/node/routes/search.ts) Every search request emits a `trace` array with structured steps: ```typescript interface TraceStep { @@ -83,13 +83,13 @@ Every search result should be traceable back to: 5. What the user should verify independently ## Key files -- `src/features/controlPlane/components/SearchTrace.tsx` — User-facing trace UI -- `src/features/agents/components/FastAgentPanel/StepTimeline.tsx` — Agent step timeline -- `src/features/agents/components/FastAgentPanel/FastAgentPanel.ParallelTaskTimeline.tsx` — Parallel execution -- `src/features/monitoring/views/AgentTelemetryDashboard.tsx` — Telemetry dashboard -- `src/features/trajectory/types.ts` — Trajectory score types -- `convex/domains/agents/traceTypes.ts` — TRACE framework types -- `server/routes/search.ts` — Search trace emission +- `apps/web/src/features/controlPlane/components/SearchTrace.tsx` — User-facing trace UI +- `apps/web/src/features/agents/components/FastAgentPanel/StepTimeline.tsx` — Agent step timeline +- `apps/web/src/features/agents/components/FastAgentPanel/FastAgentPanel.ParallelTaskTimeline.tsx` — Parallel execution +- `apps/web/src/features/monitoring/views/AgentTelemetryDashboard.tsx` — Telemetry dashboard +- `apps/web/src/features/trajectory/types.ts` — Trajectory score types +- `backend/convex/domains/agents/traceTypes.ts` — TRACE framework types +- `workers/node/routes/search.ts` — Search trace emission - `packages/mcp-local/src/benchmarks/searchQualityEval.ts` — Eval harness ## Related rules diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a675d14e1..75bac6b05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: run: npx tsc --noEmit --pretty false - name: Convex typecheck - run: npx tsc -p convex --noEmit --pretty false + run: npx tsc -p backend/convex --noEmit --pretty false runtime-smoke: name: Runtime smoke @@ -79,31 +79,31 @@ jobs: - name: Runtime smoke tests run: > npx vitest run - server/lib/jsonObjectParser.test.ts - server/agentHarnessStructuredOutput.test.ts - src/features/product/lib/captureRouter.test.ts - src/features/workspace/lib/eventWorkspacePersistence.test.ts - src/features/workspace/data/eventWorkspaceMemory.test.ts - convex/__tests__/scratchnode.events.test.ts - server/searchRoute.test.ts - convex/workflows/ainewsBriefFormat.test.ts - convex/__tests__/agentRuntimeTierFallback.test.ts - src/features/agents/components/FastAgentPanel/__tests__/RunState.test.tsx - convex/domains/agents/autonomy/autonomy.integration.test.ts - convex/domains/agents/autonomy/autonomyTasteBench.integration.test.ts - convex/domains/evaluation/tasteBench.integration.test.ts - convex/domains/evaluation/tasteBenchPolicy.test.ts - convex/domains/product/diligenceTenantIsolation.test.ts - src/features/entities/components/notebook/entityNotebookAuthorityHelpers.test.ts - src/features/agents/authority/AuthorityControl.test.tsx - src/features/agents/authority/DelegatedReceiptRow.test.tsx - src/features/dogfood/components/TasteBenchPanel.test.tsx - src/features/evaluation/data/tasteBenchScenario.test.ts + workers/node/lib/jsonObjectParser.test.ts + workers/node/agentHarnessStructuredOutput.test.ts + apps/web/src/features/product/lib/captureRouter.test.ts + apps/web/src/features/workspace/lib/eventWorkspacePersistence.test.ts + apps/web/src/features/workspace/data/eventWorkspaceMemory.test.ts + backend/convex/__tests__/scratchnode.events.test.ts + workers/node/searchRoute.test.ts + backend/convex/workflows/ainewsBriefFormat.test.ts + backend/convex/__tests__/agentRuntimeTierFallback.test.ts + apps/web/src/features/agents/components/FastAgentPanel/__tests__/RunState.test.tsx + backend/convex/domains/agents/autonomy/autonomy.integration.test.ts + backend/convex/domains/agents/autonomy/autonomyTasteBench.integration.test.ts + backend/convex/domains/evaluation/tasteBench.integration.test.ts + backend/convex/domains/evaluation/tasteBenchPolicy.test.ts + backend/convex/domains/product/diligenceTenantIsolation.test.ts + apps/web/src/features/entities/components/notebook/entityNotebookAuthorityHelpers.test.ts + apps/web/src/features/agents/authority/AuthorityControl.test.tsx + apps/web/src/features/agents/authority/DelegatedReceiptRow.test.tsx + apps/web/src/features/dogfood/components/TasteBenchPanel.test.tsx + apps/web/src/features/evaluation/data/tasteBenchScenario.test.ts scripts/__tests__/releaseWorkflowContracts.test.ts - convex/domains/redesign/chatRuns.responseShape.test.ts - convex/domains/redesign/chatRuns.contract.test.ts - src/features/redesign/components/UniversalComposer.test.tsx - src/features/redesign/surfaces/ScratchnodeEventsSurface.test.tsx + backend/convex/domains/redesign/chatRuns.responseShape.test.ts + backend/convex/domains/redesign/chatRuns.contract.test.ts + apps/web/src/features/redesign/components/UniversalComposer.test.tsx + apps/web/src/features/redesign/surfaces/ScratchnodeEventsSurface.test.tsx scratchnode-launch-gates: name: ScratchNode launch gates @@ -126,9 +126,9 @@ jobs: - name: Verify demo route gate and live route honesty run: > npx playwright test - tests/e2e/vercel-preview-security.spec.ts - tests/e2e/scratchnode-demo-route-gate.spec.ts - tests/e2e/scratchnode-live-route-honesty.spec.ts + evals/e2e/vercel-preview-security.spec.ts + evals/e2e/scratchnode-demo-route-gate.spec.ts + evals/e2e/scratchnode-live-route-honesty.spec.ts --project=chromium --workers=1 --reporter=list diff --git a/.github/workflows/convex-deploy.yml b/.github/workflows/convex-deploy.yml index 4671bbd0a..b1149997d 100644 --- a/.github/workflows/convex-deploy.yml +++ b/.github/workflows/convex-deploy.yml @@ -24,7 +24,7 @@ on: branches: - main paths: - - "convex/**" + - "backend/convex/**" - "shared/**" - "package.json" - "package-lock.json" diff --git a/.github/workflows/daily-tool-gen.yml b/.github/workflows/daily-tool-gen.yml index 77ba1278e..88426c1b0 100644 --- a/.github/workflows/daily-tool-gen.yml +++ b/.github/workflows/daily-tool-gen.yml @@ -80,7 +80,7 @@ jobs: if: steps.typecheck.outcome == 'success' working-directory: packages/mcp-local run: | - npx vitest run src/__tests__/tools.test.ts 2>&1 | tee /tmp/vitest-output.txt + npx vitest run apps/web/src/__tests__/tools.test.ts 2>&1 | tee /tmp/vitest-output.txt exit ${PIPESTATUS[0]} - name: Create pull request @@ -129,7 +129,7 @@ jobs: ### Test Plan - Review the generated tool schema and handler logic - Verify the tool follows existing patterns - - Run `npx vitest run src/__tests__/tools.test.ts` locally + - Run `npx vitest run apps/web/src/__tests__/tools.test.ts` locally - Test via stdio: `echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"${TOOL_NAME}","arguments":{}}}' | node dist/index.js` --- diff --git a/.github/workflows/delta-dogfood-gate.yml b/.github/workflows/delta-dogfood-gate.yml index 3fd126748..1f94e4f9b 100644 --- a/.github/workflows/delta-dogfood-gate.yml +++ b/.github/workflows/delta-dogfood-gate.yml @@ -4,8 +4,8 @@ on: pull_request: paths: - "packages/mcp-local/**" - - "server/routes/search.ts" - - "server/searchRoute.test.ts" + - "workers/node/routes/search.ts" + - "workers/node/searchRoute.test.ts" - ".github/workflows/delta-dogfood-gate.yml" workflow_dispatch: @@ -31,8 +31,8 @@ jobs: - name: Typecheck Delta tool slice working-directory: packages/mcp-local - run: npx tsc --noEmit --module Node16 --moduleResolution Node16 --target ES2022 --lib ES2022 --strict --esModuleInterop --skipLibCheck --types node,vitest src/tools/deltaTools.ts src/__tests__/deltaDogfoodGate.test.ts src/__tests__/deltaTools.test.ts src/__tests__/founderDirectionAssessment.test.ts + run: npx tsc --noEmit --module Node16 --moduleResolution Node16 --target ES2022 --lib ES2022 --strict --esModuleInterop --skipLibCheck --types node,vitest apps/web/src/tools/deltaTools.ts apps/web/src/__tests__/deltaDogfoodGate.test.ts apps/web/src/__tests__/deltaTools.test.ts apps/web/src/__tests__/founderDirectionAssessment.test.ts - name: Run Delta self-dogfood gate working-directory: packages/mcp-local - run: npx vitest run src/__tests__/deltaDogfoodGate.test.ts src/__tests__/deltaTools.test.ts src/__tests__/founderDirectionAssessment.test.ts + run: npx vitest run apps/web/src/__tests__/deltaDogfoodGate.test.ts apps/web/src/__tests__/deltaTools.test.ts apps/web/src/__tests__/founderDirectionAssessment.test.ts diff --git a/.github/workflows/dogfood-qa-gate.yml b/.github/workflows/dogfood-qa-gate.yml index 5322cfa59..b033b5f81 100644 --- a/.github/workflows/dogfood-qa-gate.yml +++ b/.github/workflows/dogfood-qa-gate.yml @@ -6,11 +6,11 @@ on: - ".github/workflows/dogfood-qa-gate.yml" - "scripts/overstory/**" - "scripts/ui/**" - - "tests/e2e/**" - - "src/**/*.tsx" - - "src/**/*.ts" - - "src/**/*.css" - - "src/features/**" + - "evals/e2e/**" + - "apps/web/src/**/*.tsx" + - "apps/web/src/**/*.ts" + - "apps/web/src/**/*.css" + - "apps/web/src/features/**" - "public/dogfood/**" schedule: - cron: "0 6 * * *" @@ -61,7 +61,7 @@ jobs: - name: Capture screenshots + publish gallery run: | - npm run test:e2e -- tests/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 + npm run test:e2e -- evals/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 npm run dogfood:publish - name: Capture Scribe how-to diff --git a/.github/workflows/nightly-design-loop.yml b/.github/workflows/nightly-design-loop.yml index b4c914a79..e3a718fb9 100644 --- a/.github/workflows/nightly-design-loop.yml +++ b/.github/workflows/nightly-design-loop.yml @@ -46,13 +46,13 @@ jobs: - name: Execute surface contracts (fails on drift) env: BASE_URL: http://127.0.0.1:4173 - run: npx playwright test tests/e2e/ui-contract-runner.spec.ts --project=chromium --workers=1 --reporter=line + run: npx playwright test evals/e2e/ui-contract-runner.spec.ts --project=chromium --workers=1 --reporter=line - name: Capture 4-variant screenshot set env: BASE_URL: http://127.0.0.1:4173 DOGFOOD_SCREENSHOT_DIR: nightly-captures - run: npx playwright test tests/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 --reporter=line + run: npx playwright test evals/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 --reporter=line - name: Upload screenshots if: always() diff --git a/.github/workflows/tier-b-preview.yml b/.github/workflows/tier-b-preview.yml index 2e689db25..11f409ac4 100644 --- a/.github/workflows/tier-b-preview.yml +++ b/.github/workflows/tier-b-preview.yml @@ -1,7 +1,7 @@ name: Tier B regression (preview) # The single highest-leverage check in this repo. Runs the full -# Tier B Playwright suite (tests/e2e/exact-kit-parity-prod.spec.ts) +# Tier B Playwright suite (evals/e2e/exact-kit-parity-prod.spec.ts) # against the Vercel PR preview URL BEFORE merge. # # Why this matters: A9 took 4 separate PRs to land on prod earlier @@ -98,7 +98,7 @@ jobs: # tests, __tests__/__mocks__ fixtures, and *.stories never reach the Vercel # bundle, so a PR that ONLY touches them cannot change the preview — and # must NOT burn the ~10-min preview-resolve poll. Without this, a - # convex/__tests__/*.test.ts PR matches the broad `convex` path and waits + # backend/convex/__tests__/*.test.ts PR matches the broad `convex` path and waits # the full 10 min to skip-green (the "why is Tier B taking forever" case). SHIPPING=$(echo "$CHANGED" | grep -vE '(\.test\.[cm]?tsx?$|\.spec\.[cm]?tsx?$|(^|/)__tests__/|(^|/)__mocks__/|\.stories\.[cm]?tsx?$)' || true) if [ -z "$SHIPPING" ]; then @@ -303,9 +303,9 @@ jobs: fi # exact-kit-parity-prod: visual selector parity (per-PR canonical-component check) # one-flow-regression: full surface tour + A9 fallback + interactive chip behavior - # ui-contract-runner: executes docs/design/ui-contract/surfaces/*.contract.json + # ui-contract-runner: executes proof/ui-contract/surfaces/*.contract.json # (anchors, computed geometry, theme wiring, state copy) against the preview - npx playwright test tests/e2e/vercel-preview-security.spec.ts tests/e2e/exact-kit-parity-prod.spec.ts tests/e2e/one-flow-regression.spec.ts tests/e2e/ui-contract-runner.spec.ts --project=chromium --reporter=line + npx playwright test evals/e2e/vercel-preview-security.spec.ts evals/e2e/exact-kit-parity-prod.spec.ts evals/e2e/one-flow-regression.spec.ts evals/e2e/ui-contract-runner.spec.ts --project=chromium --reporter=line - name: Upload Playwright artifacts on failure if: failure() diff --git a/AGENTS.md b/AGENTS.md index d13250978..e23983059 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ `AGENT_COORDINATION.md` (repo root) is the live ledger of **who is editing what right now** and **what backend contracts are ready to call**. Before editing a hot file -(`public/proto/home-v5.html`, `convex/events.ts`, `convex/schema/eventsSchema.ts`): scan +(`public/proto/home-v5.html`, `backend/convex/events.ts`, `backend/convex/schema/eventsSchema.ts`): scan **Active claims**, **claim your region** before you start, and **hand off** new backend contracts there. **Never** `convex deploy`/`deploy:prod` out-of-band to the shared prod deployment — it pushes un-reviewed schema/functions and breaks the other agent's next @@ -635,8 +635,8 @@ Rules: - The browser flow may prepare a handoff prompt for Claude Code or OpenClaw, but the prompt is a consequence of the shared packet and task id, not a replacement for them. - After changes to these routes or the control-plane handoff UI, run: - `npx tsc --noEmit` - - `npx vitest run server/searchRoute.test.ts server/sharedContextRoute.test.ts` - - `npx vitest run src/features/controlPlane/views/ControlPlaneLanding.test.tsx src/features/controlPlane/components/SyncProvenanceBadge.test.tsx src/features/mcp/components/SharedContextProtocolPanel.test.tsx src/features/mcp/components/SyncBridgeAccountPanel.test.tsx` + - `npx vitest run workers/node/searchRoute.test.ts workers/node/sharedContextRoute.test.ts` + - `npx vitest run apps/web/src/features/controlPlane/views/ControlPlaneLanding.test.tsx apps/web/src/features/controlPlane/components/SyncProvenanceBadge.test.tsx apps/web/src/features/mcp/components/SharedContextProtocolPanel.test.tsx apps/web/src/features/mcp/components/SyncBridgeAccountPanel.test.tsx` - `npm run build` ## Self maintenance (nightly, autonomous) @@ -693,7 +693,7 @@ npx convex run --push "domains/operations/selfMaintenance:getLatestSelfMaintenan ``` Cron: -- `convex/crons.ts` schedules `domains/operations/selfMaintenance:runNightlySelfMaintenanceCron` daily. +- `backend/convex/crons.ts` schedules `domains/operations/selfMaintenance:runNightlySelfMaintenanceCron` daily. ## Flywheel mode (UI dogfood + Gemini QA) @@ -766,7 +766,7 @@ Full pipeline for any coding agent (Claude Code, Cursor, Windsurf, Codex): ```bash # Full cycle: build → capture → publish → record → score npx vite build -BASE_URL=http://127.0.0.1:4173 npx playwright test tests/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 +BASE_URL=http://127.0.0.1:4173 npx playwright test evals/e2e/full-ui-dogfood.spec.ts --project=chromium --workers=1 npm run dogfood:publish node scripts/ui/recordDogfoodWalkthrough.mjs --baseURL http://127.0.0.1:4173 --publish static BASE_URL=http://127.0.0.1:4173 node scripts/ui/runDogfoodGeminiQa.mjs @@ -800,7 +800,7 @@ Goal: errors become deduped cards, humans approve, agent does legwork, humans re Card substrate: `agentTaskSessions` rows with `metadata.kind='bug_card'` and deterministic `metadata.signature`. Client capture (prod only): -- `src/main.tsx` reports `window.error` and `unhandledrejection` to `domains/operations/bugLoop:reportClientError` with local rate limit. +- `apps/web/src/main.tsx` reports `window.error` and `unhandledrejection` to `domains/operations/bugLoop:reportClientError` with local rate limit. Manual triage: @@ -1015,7 +1015,7 @@ Spawned as a local process by the MCP client. No HTTP server, no port, no auth t "mcpServers": { "nodebench": { "command": "npx", - "args": ["tsx", "mcp_tools/gateway_server/stdioServer.ts"], + "args": ["tsx", "mcp_tools/gateway_workers/node/stdioServer.ts"], "env": { "CONVEX_URL": "https://formal-shepherd-851.convex.site", "MCP_SECRET": "" @@ -1032,7 +1032,7 @@ Spawned as a local process by the MCP client. No HTTP server, no port, no auth t "mcpServers": { "nodebench": { "command": "npx", - "args": ["tsx", "mcp_tools/gateway_server/stdioServer.ts"], + "args": ["tsx", "mcp_tools/gateway_workers/node/stdioServer.ts"], "env": { "CONVEX_URL": "https://formal-shepherd-851.convex.site", "MCP_SECRET": "" @@ -1049,7 +1049,7 @@ Spawned as a local process by the MCP client. No HTTP server, no port, no auth t "mcpServers": { "nodebench": { "command": "npx", - "args": ["tsx", "mcp_tools/gateway_server/stdioServer.ts"], + "args": ["tsx", "mcp_tools/gateway_workers/node/stdioServer.ts"], "env": { "CONVEX_URL": "https://formal-shepherd-851.convex.site", "MCP_SECRET": "" @@ -1067,7 +1067,7 @@ Spawned as a local process by the MCP client. No HTTP server, no port, no auth t Run the HTTP server locally if you prefer the HTTP transport or need to test the same protocol used in production. -**1. Set environment variables** (create `mcp_tools/gateway_server/.env` or export): +**1. Set environment variables** (create `mcp_tools/gateway_workers/node/.env` or export): ```bash CONVEX_URL=https://formal-shepherd-851.convex.site # .convex.site, NOT .convex.cloud @@ -1342,10 +1342,10 @@ npx convex run domains/social/linkedinScheduleGrid:scheduleNextApprovedPost '{"t ### Key files -- `convex/domains/social/linkedinContentQueue.ts` — Queue CRUD, dedup, stats -- `convex/domains/social/linkedinQualityJudge.ts` — LLM judge + batch processor -- `convex/domains/social/linkedinScheduleGrid.ts` — Time slots, scheduling, backfill -- `convex/domains/social/linkedinPosting.ts` — Queue processor (`processQueuedPost`) +- `backend/convex/domains/social/linkedinContentQueue.ts` — Queue CRUD, dedup, stats +- `backend/convex/domains/social/linkedinQualityJudge.ts` — LLM judge + batch processor +- `backend/convex/domains/social/linkedinScheduleGrid.ts` — Time slots, scheduling, backfill +- `backend/convex/domains/social/linkedinPosting.ts` — Queue processor (`processQueuedPost`) ### Founder voice & writing style guide @@ -1425,13 +1425,13 @@ npx convex run --prod domains/social/linkedinScheduleGrid:scheduleNextApprovedPo npx convex run --prod domains/social/linkedinContentQueue:listQueueItems '{"status":"approved","limit":5}' ``` -**Key file**: `convex/workflows/founderPostGenerator.ts` — `generateFounderPost` + `weeklyFounderBatch` +**Key file**: `backend/convex/workflows/founderPostGenerator.ts` — `generateFounderPost` + `weeklyFounderBatch` ### Pre-post verification pipeline Every post goes through 4 verification checks before hitting LinkedIn. Runs inside `processQueuedPost` before the actual API call. -**File**: `convex/domains/social/linkedinPrePostVerification.ts` — `verifyBeforePosting` internalAction +**File**: `backend/convex/domains/social/linkedinPrePostVerification.ts` — `verifyBeforePosting` internalAction **4 checks (run in order, cheapest first):** @@ -1449,7 +1449,7 @@ Every post goes through 4 verification checks before hitting LinkedIn. Runs insi - Claim contradiction → status set to `failed` → held for manual review - Search/LLM errors → soft warning, non-blocking (post proceeds) -**Auto-regeneration**: `convex/workflows/founderPostGenerator.ts` — `regenerateFailedPersonalPosts` queries `needs_rewrite` items with persona FOUNDER, generates fresh replacements, marks old ones as rejected. +**Auto-regeneration**: `backend/convex/workflows/founderPostGenerator.ts` — `regenerateFailedPersonalPosts` queries `needs_rewrite` items with persona FOUNDER, generates fresh replacements, marks old ones as rejected. **Manual commands:** ```bash @@ -1751,7 +1751,7 @@ After every implementation — before moving to the next task — answer these 3 Real-world evaluation of MCP tool orchestration using open-source software engineering tasks from the SWE-bench Verified dataset (500 human-validated GitHub issues from princeton-nlp). -**→ Quick Refs:** Run dataset bench: `cd packages/mcp-local && npx vitest run src/__tests__/evalDatasetBench.test.ts` | Run tool coverage: `npx vitest run src/__tests__/evalHarness.test.ts` | Dataset: [SWE-bench Verified](https://huggingface.co/datasets/princeton-nlp/SWE-bench_Verified) | See [AI Flywheel](#how-the-two-loops-compose-the-ai-flywheel-verification--eval) | See [Eval-Driven Development Loop](#eval-driven-development-loop) | See [6-Phase Verification](#6-phase-iterative-deep-dive-verification-process) +**→ Quick Refs:** Run dataset bench: `cd packages/mcp-local && npx vitest run apps/web/src/__tests__/evalDatasetBench.test.ts` | Run tool coverage: `npx vitest run apps/web/src/__tests__/evalHarness.test.ts` | Dataset: [SWE-bench Verified](https://huggingface.co/datasets/princeton-nlp/SWE-bench_Verified) | See [AI Flywheel](#how-the-two-loops-compose-the-ai-flywheel-verification--eval) | See [Eval-Driven Development Loop](#eval-driven-development-loop) | See [6-Phase Verification](#6-phase-iterative-deep-dive-verification-process) ### What it tests @@ -1820,13 +1820,13 @@ Beyond per-task pipelines, 3 cross-task tests prove the flywheel loops connect: ```bash # Full dataset bench (20 tasks, 473 tool calls) -cd packages/mcp-local && npx vitest run src/__tests__/evalDatasetBench.test.ts --reporter=verbose +cd packages/mcp-local && npx vitest run apps/web/src/__tests__/evalDatasetBench.test.ts --reporter=verbose # Tool-level coverage (47 tools, 76 calls) -cd packages/mcp-local && npx vitest run src/__tests__/evalHarness.test.ts --reporter=verbose +cd packages/mcp-local && npx vitest run apps/web/src/__tests__/evalHarness.test.ts --reporter=verbose # Both together -cd packages/mcp-local && npx vitest run src/__tests__/evalDatasetBench.test.ts src/__tests__/evalHarness.test.ts --reporter=verbose +cd packages/mcp-local && npx vitest run apps/web/src/__tests__/evalDatasetBench.test.ts apps/web/src/__tests__/evalHarness.test.ts --reporter=verbose ``` ### Latest results diff --git a/AGENT_COORDINATION.md b/AGENT_COORDINATION.md index 88d9bc724..4be625d4a 100644 --- a/AGENT_COORDINATION.md +++ b/AGENT_COORDINATION.md @@ -5,7 +5,7 @@ gracefully instead of clobbering each other. This is the **single source of trut "who is touching what right now"** and "what's been built that you can call." > **Why this exists:** during the ScratchNode push, two agents edited -> `public/proto/home-v5.html` and `convex/` at the same time. It caused a real prod +> `public/proto/home-v5.html` and `backend/convex/` at the same time. It caused a real prod > incident (a Convex schema-validation failure from a `lastActivityAt` field one agent's > `deploy:prod` stamped onto rows the other agent's schema didn't declare), plus constant > line-churn / "file modified since read" fights. A 30-second note prevents all of it. @@ -13,7 +13,7 @@ gracefully instead of clobbering each other. This is the **single source of trut ## How to use it (the whole protocol) 1. **Read before you edit a hot file.** Hot files = `public/proto/home-v5.html`, - `convex/events.ts`, `convex/schema/eventsSchema.ts`, `convex/schema.ts`, and the + `backend/convex/events.ts`, `backend/convex/schema/eventsSchema.ts`, `backend/convex/schema.ts`, and the ScratchNode e2e specs. Scan **Active claims** below. 2. **Claim your region** before editing: append a bullet to **Active claims** — `agent · file:region · intent · branch/PR`. Region matters: `home-v5.html#directory` @@ -44,7 +44,7 @@ deploy happened, then something clobbered it. **Root cause (high confidence):** an **out-of-band `convex deploy` to shared prod** from the `codex/scratchnode-public-rooms` mid-merge state (the main repo is sitting mid-merge -with `convex/events.ts` in conflict). This is the exact collision this ledger exists to +with `backend/convex/events.ts` in conflict). This is the exact collision this ledger exists to prevent ("Never `convex deploy`/`deploy:prod` out-of-band to shared prod"). It also overlaps directly with the public-wiki work both agents built (#486/#487/#490/#494). @@ -57,8 +57,17 @@ Server Error) for an unknown slug. ## Active claims (who is editing what RIGHT NOW) -- **2026-06-03 · Claude →** `convex/*#handoff-token`, `src/.../ScratchnodePrivateBridge`, - `src/App.tsx#events-private-route`, `public/proto/home-v5.html#private-handoff` · +> **STANDARD-TREE MIGRATION (2026-07-19, feat/standard-tree-migration): repo paths moved.** +> `convex/` → `backend/convex/` (convex.json `functions` added; function identifiers unchanged), +> `src/` + `index.html` → `apps/web/` (`@convex` alias replaces relative `../convex` imports), +> `server/` → `workers/node/`, `tests/` → `evals/`, `scripts/improvement-loop` + `goals/` → `adw/`, +> `docs/design/ui-contract/` → `proof/ui-contract/`. `public/`, `api/`, env files, `dist/` stay at +> repo root. Hot files are now `public/proto/home-v5.html` (unchanged), `backend/convex/events.ts`, +> `backend/convex/schema/eventsSchema.ts`, and the ScratchNode e2e specs under `evals/e2e/`. +> Update any stale path references before editing; old paths no longer exist. + +- **2026-06-03 · Claude →** `backend/convex/*#handoff-token`, `apps/web/src/.../ScratchnodePrivateBridge`, + `apps/web/src/App.tsx#events-private-route`, `public/proto/home-v5.html#private-handoff` · shipping the cross-domain private-notes token bridge (opaque stateful token, PR #496) · branch `feat/scratchnode-private-notes-token`. **No collision** — Codex DEFERRED this (see their verification hand-off below: "private-note token bridge … keep @@ -71,20 +80,20 @@ Server Error) for an unknown slug. - **2026-07-17 · Claude → any agent building UI contracts / `.well-known/agent-ui.json`** · The runtime UI-contract substrate ALREADY EXISTS — do not create a parallel `.ui/contract.json`. PR #575 (auto-merge armed) ships: - `docs/design/ui-contract/surfaces/*.contract.json` (schema + `proof/ui-contract/surfaces/*.contract.json` (schema `nodebench-surface-contract-v1`: anchors, computed-geometry invariants, `theme.storageKey` wiring, deep-link-forced states with expect/forbid copy) + - `tests/e2e/ui-contract-runner.spec.ts` (generic runner, one spec for every + `evals/e2e/ui-contract-runner.spec.ts` (generic runner, one spec for every manifest, theme × viewport) + Tier B wiring in `tier-b-preview.yml` (CI-on-drift is DONE). Reversion-proved: wrong `gridTracks` fails exactly the mobile variants. **The open delta for you**: (1) a build-time generator that PROJECTS the repo contracts into a served `public/.well-known/agent-ui.json` — public affordance view only (surfaces, routes, anchors/testids, actions), NOT internal QA clauses - like forbidText; single source of truth stays in `docs/design/ui-contract/surfaces/`, + like forbidText; single source of truth stays in `proof/ui-contract/surfaces/`, the served file is generated, never hand-edited; (2) a `version` bump discipline on the schema const; (3) contracts for the replay page (`/r/:hash`) and mobile - shell. Read `docs/design/ui-contract/README.md` ("Runtime surface contracts") - first. Claim `docs/design/ui-contract/surfaces/*` + `vite.config.ts` (or the + shell. Read `proof/ui-contract/README.md` ("Runtime surface contracts") + first. Claim `proof/ui-contract/surfaces/*` + `vite.config.ts` (or the generator script) in Active claims before starting. **HARD REQUIREMENT — fail-closed hash binding.** This repo has a documented history of prod serving stale bundles while CI reads green (see @@ -95,7 +104,7 @@ Server Error) for an unknown slug. `generatedAt` into `agent-ui.json`, and the manifest MUST tell consumers to cross-check that fingerprint against the actually-served bundle and DISTRUST the contract on mismatch. Detection is not enough; the contract must instruct - fail-closed. Also note: `tests/e2e/ui-contract-runner.spec.ts` accepts + fail-closed. Also note: `evals/e2e/ui-contract-runner.spec.ts` accepts `BASE_URL`, so any independent party can replay the full contract against production — preserve that property (no CI-only assumptions). @@ -183,8 +192,8 @@ Server Error) for an unknown slug. with a copyable `/wiki` URL; wiki sheet has open/copy public actions. - Answer cards: live answer `Share` copies a real addressable URL `/e/:slug#answer-` instead of only showing a toast. - - Verification: `npx vitest run convex/__tests__/scratchnode.publicWikiRead.test.ts`, - `npx playwright test tests/e2e/scratchnode-live-route-honesty.spec.ts --project=chromium --workers=1`, + - Verification: `npx vitest run backend/convex/__tests__/scratchnode.publicWikiRead.test.ts`, + `npx playwright test evals/e2e/scratchnode-live-route-honesty.spec.ts --project=chromium --workers=1`, `npx tsc --noEmit --pretty false`, `npm run build`. - **2026-06-03 - Codex verification after #494** - Current ScratchNode viral loop @@ -319,7 +328,7 @@ Server Error) for an unknown slug. do not expose session ids, private notes, anchors, or tokens in public links. - **Claude** — directory viral slice (`home-v5.html#directory`): flyer cards + "● N inside" presence cue + policy-aware action (open → "Join now"; request → "Request to join" `