Spec routing leaves the system: a drafted issue in the Project's repo (#163) - #169
Merged
Conversation
…hread (#163) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
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
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
repository(owner/repo):sync_projectscolumn, both repositories (Neon + memory), theProjecttype, and the creation/list seam (POST /api/sync/projectsaccepts and validatesrepository; passing it for an existing name sets it, omitting keeps it).IssueDrafterseam invoked from/api/sync/reviewafter the filing write.spec_handoffrecord on the Thread is the guard —draftedis permanent; the stable keyspec:<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.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.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 inlib/spec/issue-drafter.ts: add it to fnox + Vercel). Without the token, spec routing settles asskipped/no_credential— recorded and visible, retried automatically by a later routing once the token exists. A fabricated success was rejected deliberately:draftedis 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
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 --noEmitgreen; eslint green on every changed file (the 7 pre-existing errors onmain— thread-chat, trail-cleanup, install-app-prompt, attachment-drafts, desk-workspace — remain untouched, none added).trash-repository.spec.tsseedstrashedAt: 2026-07-01with 30-day retention against the real clock, red onmainsince 2026-07-31.🤖 Generated with Claude Code
https://claude.ai/code/session_0193moUKw7KiVLfSfuDsRknd
Generated by Claude Code