Skip to content

finding: context.authGate is read by REST's enforceAuth but is not declared on ExecutionContextSchema — an undeclared field outside every closure gate #7280

Closed

Description

@os-zhuang

Found while implementing #6216 (PR #7259). Filed unassigned; deliberately not fixed there, because declaring a field on ExecutionContextSchema is a spec change with its own review surface, not a refactor rider.

The fact

The ADR-0069 authentication-policy gate rides on the execution context:

  • written in packages/rest/src/rest-server.ts computeExecCtx — the assembled envelope is spread with ...(authGate ? { authGate } : {}) behind an as any;
  • read in the same file's enforceAuth (const gate = context?.authGate;), which blocks protected resources for a gated user;
  • not declared anywhere in packages/spec/src/kernel/execution-context.zod.ts — grep -n authGate packages/spec/src returns nothing.

Why it matters now specifically

#6216's whole point is that the ExecutionContext field set is closed by type, so a field cannot reach one transport and miss another. That closure is derived from keyof ExecutionContext, i.e. from the schema. A field that lives only in an as any spread is, by construction, outside the closure: ENTRY_EXECUTION_CONTEXT_FIELDS cannot list it, ExecutionContextEntryFields cannot demand it, and the runtime pin that reconciles the closed set against ExecutionContextSchema.shape cannot see it either. It is exactly the blind spot the new gate is meant to remove, sitting one as any outside the gate.

Nothing is broken today: the producer and the consumer are ten lines apart in one file, so they cannot drift the way #6071's two files did. The cost is that a second transport wiring up the ADR-0069 gate has nothing to tell it the field exists.

Suggested shape if it is taken up

Declare authGate on ExecutionContextSchema (shape: { code, message } per packages/core/src/security/auth-gate.ts), drop the as any, and let #6216's closed set pick it up — at which point every face must decide it, which is the intended outcome. Note the ADR-0087 / authorable-surface consequences of adding a key: pnpm --filter @objectstack/spec build regenerates packages/spec/authorable-surface/kernel.json, and that regeneration is itself gated.

Related: #6216 / PR #7259, ADR-0069.

Activity

  1. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    Findings triage — route repair only: domain:spec appended. finding grade unchanged, no ownership taken.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 10, 2026
  3. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    CLAIM — spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2. Branch: claude/issue-7280-declare-auth-gate. Dispatching a cloud dev session (model: Opus) under the maintainer's standing acceleration instructions (2026-08-10, latest verbatim: 「再看看有没有新任务可以批量派」).

    Direction (the card's own suggested shape, adopted): declare authGate on ExecutionContextSchema (shape { code, message } per packages/core/src/security/auth-gate.ts), drop the as any spread in computeExecCtx, and let #6216's closed field set pick it up — at which point every transport face must decide it, which the card names as the intended outcome. The field is live (written and read ten lines apart in rest-server.ts); declaring it is the ENFORCE leg on a field the closure gate was built to see. Premise-first guards: re-measure that authGate is still undeclared and still spread behind as any; census every face the #6216 closed set forces a decision on and decide each explicitly in the PR (no silent undefined pass-through without a stated reason). ADR-0087/authorable-surface consequences per the card: build before regen, gated regeneration.


    Generated by Claude Code

  4. removed their assignment
    on Aug 10, 2026
  5. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    CLAIM WITHDRAWN — held to the recorded restart condition. Two facts the race-check surfaced against my claim: (1) triage's routing comment names the natural restart as "#6216/PR #7259 landing makes the closed-set pin the enforcement channel this key would join" — PR #7259 is still open, so the closed set this declaration is meant to join is not on main yet; (2) #7259 itself touches rest-server.ts's computeExecCtx region from another seat — dispatching this now would collide mid-flight with the very PR that creates the enforcement channel. Assignee cleared; the claim comment above is void. This seat re-claims when PR #7259 merges (recorded on the seat post #6017 as a gated card, same treatment as #7297).


    Generated by Claude Code

  6. self-assigned this
    on Aug 10, 2026
  7. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    RE-CLAIM — recorded restart condition met. Spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2. Branch: claude/issue-7280-declare-auth-gate. Dispatching a local dev agent (model: Opus — well-scoped declaration + face census; the #6216 closed-set machinery this key joins is now on main).

    The 06:56Z withdrawal held this card to "re-claims when PR #7259 merges". PR #7259 MERGED 2026-08-10T05:41:32Z (verified by direct read), so both blockers are gone: the closed-set enforcement channel exists on main, and the computeExecCtx region is no longer being edited mid-flight by another seat.

    Direction unchanged from the 06:55Z claim: declare authGate on ExecutionContextSchema (shape { code, message } per packages/core/src/security/auth-gate.ts), drop the as any spread in computeExecCtx, and let #6216's closed field set force every transport face to decide it explicitly — no silent undefined pass-through without a stated reason at the call site (the accessToken precedent in PR #7259's body is the template). Premise-first: re-measure that authGate is still undeclared (git grep authGate packages/spec/src = zero hits) and still spread behind as any — all line numbers post-#7259 will have moved, re-anchor by content. ADR-0087/authorable-surface consequences: build before regen, gated regeneration, dual-snapshot rule if exports move.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions