Skip to content

refactor(coil): one scope-auth helper for every fork route - #131

Merged
radroid merged 2 commits into
mainfrom
coil/loops-phase0
Sep 2, 2026
Merged

refactor(coil): one scope-auth helper for every fork route#131
radroid merged 2 commits into
mainfrom
coil/loops-phase0

Conversation

@radroid

@radroid radroid commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Phase 0 of the loops plan (docs/coil/loops-v2/PLAN.md §5, Phase 0): pay down two small fork-owned debts the feature would otherwise duplicate. Zero upstream files touched.

Problem. The fork carried two independent mirrors of upstream's private HTTP scope-auth path — autoResume/http.ts (authenticateWithOperateScope, scope hardcoded, forwards the DPoP failure reason) and webPush/http.ts (authenticateWithScope(scope), parameterised, drops the DPoP reason). The loop routes would have been the third paste. Separately, isClaudeThread only accepted a full OrchestrationThread, so a reactor holding an OrchestrationThreadShell could not use it.

Fix.

  • New apps/server/src/coil/http/auth.ts exporting authenticateWithScope(scope) and routeAuthErrorTags; both route modules call it and their local copies are gone. The promoted helper is the union of the two mirrors: it forwards dpopFailureReason (as auto-resume did since 3bdf109) and returns the session (as web-push did). The one observable change: a DPoP-rejected credential on /api/coil/push/* now carries dpopFailureReason in its 401 body, matching the auto-resume route and upstream's own authenticateRawRouteWithScope.
  • isClaudeThread takes Pick<OrchestrationThread, "session">; a shell is structurally assignable with no cast, and the test literal is cast-free so reverting the widening fails typecheck.
  • Tests: new http/auth.test.ts pins all three typed failures (401 / 403 / 500 shapes); new webPush/http.test.ts pins the push routes at the route level (the first test to import them); the shared test scaffolding moved into http/testAuth.ts; autoResume/http.test.ts now asserts exact statuses instead of 401 || 403.
  • docs/coil/SEAMS.md: the logic-mirror row names the single mirror and its three intentional deltas from upstream.

Verified in a worktree: vp test run src/coil → 17 files, 140 tests pass; tsgo --noEmit → 0 errors; vp lint on apps/server/src/coil clean; vp fmt --check clean.

Work done by Claude Fable 5.1 orchestrating Claude Opus 5 subagents in Claude Code.

radroid and others added 2 commits September 2, 2026 13:29
Both fork route modules carried their own paste of upstream's private
`authenticateRawRouteWithScope`, and the two had already drifted: the
auto-resume copy forwards the DPoP failure reason, the Web Push copy
dropped it. Promote the parameterised form into `coil/http/auth.ts` and
re-point both, so the next fork route calls the mirror instead of pasting
a third one.

Reconciled to the union of the two behaviours, which is also what upstream
does: the shared helper forwards `dpopFailureReason` (previously only on
auto-resume) and returns the session (previously only on Web Push). The
error-tag map that renders the three typed failures moved with it, since
it exists only because of them. Statuses, bodies and scopes are otherwise
unchanged, and `CoilRoutesLive` is untouched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The predicate reads one field, `session`, which an `OrchestrationThreadShell`
declares with the same `OrchestrationSession | null` type the full thread
does. Asking for `Pick<OrchestrationThread, "session">` lets a shell-only
caller reuse it instead of pasting a second copy of the driver-slug compare.
Every other guard still takes the full thread, since they read `messages`
and `activities`, which no shell carries.

Behaviour is unchanged. Also drops two drifted line-number citations from
the doc comment.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@radroid
radroid merged commit 15f27d6 into main Sep 2, 2026
2 checks passed
@radroid
radroid deleted the coil/loops-phase0 branch September 2, 2026 17:42
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.

1 participant