Skip to content

Spec routing leaves the system: a drafted issue in the Project's repo (#163) - #169

Merged
wschenk merged 5 commits into
mainfrom
cursor/spec-routing-issue-163
Aug 8, 2026
Merged

Spec routing leaves the system: a drafted issue in the Project's repo (#163)#169
wschenk merged 5 commits into
mainfrom
cursor/spec-routing-issue-163

Conversation

@wschenk

@wschenk wschenk commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Spec routing leaves the system (docs/desk.md, D3). Opens with ADR 0018 — committed before any seam code — settling idempotency (one Thread, one drafted issue, ever), failure visibility (a draft that doesn't land is recorded on the Thread, never silently, and never fails the filing itself), and undo (un-routing orphans the record; external writes are never deleted).

What shipped:

  • Project gains an optional repository (owner/repo): sync_projects column, both repositories (Neon + memory), the Project type, and the creation/list seam (POST /api/sync/projects accepts and validates repository; passing it for an existing name sets it, omitting keeps it).
  • Routing a spec Thread to a Project with a repository drafts a ticket-shaped issue there — title from the Thread, body from the Enrichment's idea-shaped report (newest idea-kind report, falling back to the newest report, then the walker's own words) — via a server-side IssueDrafter seam invoked from /api/sync/review after the filing write.
  • Idempotency: a spec_handoff record on the Thread is the guard — drafted is permanent; the stable key spec:<threadId> travels in the issue body so the GitHub drafter can find a prior draft (via the issues listing, not the lag-prone Search API) across the crash window where the issue landed but the record write didn't. Re-routing, retrying, or routing from a second device never drafts twice.
  • Graceful degradation: routing to a Project without a repository (or with no Project) records skipped/no_repository — no external write, and the Thread says plainly the handoff is not live. A later routing retries past it once a repository exists.
  • Receipt: the filing surface shows "Issue drafted in owner/repo" linking the issue (kept, with an orphan note, after re-routing away), the not-live message for skipped, and the reason for failed. The record syncs and hydrates like the Route, so other devices read the same receipt.

Said plainly: no server-side GitHub credential path existed in this codebase, so the handoff is not live in production yet. The drafter sits behind an interface with a memory implementation wired for tests and a real REST implementation gated on SPEC_HANDOFF_GITHUB_TOKEN (TODO noted in lib/spec/issue-drafter.ts: add it to fnox + Vercel). Without the token, spec routing settles as skipped/no_credential — recorded and visible, retried automatically by a later routing once the token exists. A fabricated success was rejected deliberately: drafted is the permanent guard and pretending would block the real issue forever (ADR 0018).

The repo's two-axis review (Standards + Spec) ran before this PR; its blocker (the no-credential fallback originally recorded a fake drafted) and should-fixes (handoff throw could 500 a committed filing; half-recorded draft handling; Search API index lag; PRs matching the dedup search) are fixed in the final commit.

Closes #163

Test plan

  • Acceptance criteria from the ticket covered at the named seams
    • ADR committed before the seam (commit order in this branch).
    • tests/spec-handoff.spec.ts: Project carries a repository through create/list; spec routing drafts with the report as body and the key in the body; routing twice / re-route+return / retry-after-failure never duplicates; no-repository skips with no external write and goes live later; no-credential skips visibly and never fabricates; a draft that lands but fails to record still answers drafted; hydration adopts the record; GitHub drafter dedups by key from the issues listing (ignoring PRs) and surfaces HTTP failures.
    • tests/thread-filing-ui.spec.ts: the receipt links the drafted issue with its repo named; the skipped receipt says the handoff is not live.
  • pnpm exec tsc --noEmit green; eslint green on every changed file (the 7 pre-existing errors on main — thread-chat, trail-cleanup, install-app-prompt, attachment-drafts, desk-workspace — remain untouched, none added).
  • Neighboring suites green: thread-filing, thread-filing-ui, sync-hydrate, sync-repository, sync-cycle, local-capture-store, local-threads, sql-tables, enrichment-project-proposals. Known pre-existing failure unrelated to this branch: trash-repository.spec.ts seeds trashedAt: 2026-07-01 with 30-day retention against the real clock, red on main since 2026-07-31.

🤖 Generated with Claude Code

https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd


Generated by Claude Code

claude added 5 commits August 8, 2026 01:08
The locked installer wrote PHASE-BOUNDARIES.md into the tracked
.agents/skills/ask-matt directory during environment bootstrap; committed
so the working tree stays clean.

No-ticket: true

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
No credential never fabricates a draft: getIssueDrafter returns null and
the settle records skipped/no_credential, retryable once the token
exists — a fake drafted record would arm the permanent guard forever.
The handoff can no longer fail an already-committed filing (the review
route answers a failed-shaped record instead of a 500), a draft that
lands but fails to record still answers drafted, the GitHub dedup reads
the issues listing instead of the lag-prone Search API and ignores pull
requests, owner/repo refuses dot-only segments, and the skipped receipt
no longer asserts a Project that is not there. ADR 0018 amended to
match, and to answer desk.md's batching question outright.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
walking-thoughts Building Building Preview Aug 8, 2026 1:31am

Request Review

@wschenk
wschenk merged commit 47ef68e into main Aug 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec routing leaves the system: a drafted issue in the Project's repo

2 participants