Skip to content

id: design: jurisdiction-aware per-user store routing (signup jurisdiction field, DO/blob/directory pinning) #2283

Closed

Description

@dezren39

Follow-up A from the Durable Object jurisdiction investigation on #2061
(doc: doc/2026-10-29T11-43-02Z_investigation_do_jurisdiction_pinning/).

Parent epic: #2056. Context: #2044 (Cloudflare Workers fit), §3 and §7.

What to design

Make the per-user hosted store jurisdiction-aware from the first request, without exposing a user-facing region choice yet.

  1. A jurisdiction field on the user record, written at account creation (default us, policy constant), immutable in the app layer from the first Durable Object creation.
  2. One ID-derivation function userObjectId(sub, jurisdiction) with no default argument — because idFromName("google:"+sub) and jurisdiction("eu").idFromName("google:"+sub) are different objects, a routing bug that drops the jurisdiction silently creates a second, empty user store (investigation §4.1).
  3. Restricted-namespace binding: select env.USERS.jurisdiction(<stored>) at runtime rather than using the unrestricted binding, so a mismatched ID throws instead of working (the unrestricted namespace "will not run into an error").
  4. A ctx.id.jurisdiction assertion on every identity-touching entry point, failing closed — including the two undefined cases (unrestricted namespace; alarm scheduled before 2026-03-15).
  5. R2 bucket per jurisdiction, bound with the jurisdiction field repeated in wrangler config; content-addressed dedupe becomes jurisdiction-local.
  6. The shared D1 directory's residency story: it has one jurisdiction for all users, so it must be data-minimal (hashed subject, public keys, public server records — never graph content) and documented as the single residency exception.
  7. The migration path as a first-class state, not an ops script: jurisdiction_pending + export → create in target → import → verify → switch directory record → delete. Signatures survive unchanged.

Out of scope

The user-facing region choice UI (design the field and routing now; ship the control when a customer needs it). Cross-jurisdiction shared worlds — that is follow-up B. Vendor-guarantee confirmation — follow-up C.

Acceptance

  • Design doc under doc/ covering the seven points above, with the failure modes named.
  • A concrete migration runbook sketch for a single account.
  • Follow-on implementation issues for whatever is buildable.

Acceptance criteria

  • Design doc under doc/ covers all seven numbered points in the body, with the silent-second-store failure mode (dropping jurisdiction in ID derivation) named and designed out
  • The ctx.id.jurisdiction assertion covers both undefined cases and fails closed
  • Migration path specified as a first-class state (jurisdiction_pending → export → create → import → verify → switch → delete)
  • A single-account migration runbook sketch is included
  • Follow-on implementation issues filed for the buildable parts

Activity

  1. added
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/mMedium: expected under 1 day of work
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Oct 29, 2026
  2. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  3. added
    priority/normalOrdinary priority (the default)
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 29, 2026
  4. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: #2061 (investigation), #2044 (§3/§7), #2284/#2285 (siblings B/C), epic #2056

    Notes: Design-only issue; the field/routing design is deliberately ahead of any user-facing region UI (out of scope per body).

    Risks: The unrestricted-namespace silent-accept behaviour is the trap: any path that bypasses the restricted binding creates split-brain user stores.

    Suggested approach: Design the ID-derivation function and assertion first; R2/D1 residency stories follow from them.

    🤖 Agent note · filed

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: repo-fleet-monitor run 2026-10-29T12:12Z (07:12 CDT)
    • Found via: monitor reconciliation
    • Task: Duty 2 intake enrichment — acceptance criteria appended (original body preserved verbatim above it), labels normalized, meta/enriched applied. Still-live check this pass: no merged PR or fix commit explicitly resolving this issue was found; where a queue triage task owns verification, it is named in the notes.
    • Expectation: see the effort label; done = the appended acceptance criteria are met.
    • Links: this issue
  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  6. 32 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    queue/queuedHas a queued task in the Supabase agent queue
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done — closing with evidence

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

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions