Skip to content

docs: record AF-CTR-03 part A1a (identity and device store, ingress refusals, native token documents) - #44

Merged
deku2026 merged 3 commits into
mainfrom
design/af-ctr-03-a1a
Oct 29, 2026
Merged

deku2026 merged 3 commits into
mainfrom
design/af-ctr-03-a1a

Conversation

@deku2026

@deku2026 deku2026 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Records the Design companions of AF-CTR-03 part A1a (Plan milestone MC), delivered by Cloud #118 at d4e1110. AF-CTR-03 stays
active: A1b, A2 and B follow, so this PR marks only A1a's delivered behaviour and leaves the target text of later parts as it is.

Changes

  • contracts/errors.md, "Center ingress transport statuses":

    • two rows for a known native bearer, both gRPC 16 UNAUTHENTICATED:
      • auth.token_expired: its access token, or its session's absolute lifetime, has expired;
      • auth.credential_revoked: its session, device or installation is revoked;
    • a note that an expired, idle or revoked browser cookie session is answered as auth.unauthenticated, because the browser
      signs in again in either case. This was checked against session/verify.go at the merge.
    • AUTHENTICATION/token_expired: when a refresh call itself answers it (RefreshSession, later RefreshNodeSession), the
      refresh credential has expired and the client signs in again. This is wording only; the catalogue's retry advice is
      unchanged. It is item F10 of #118's adversarial review.
  • data/cloud-store.md §6: a new "Identity and device" block for migration 0002_identity_device.sql, applied to production on 2026-10-29
    (run 40840154517). It also gives:

    • device retention per 11 §5 (revoked + 30 days, the device's sessions and installations deleted with it; these identity
      periods are maximums, not holds);
    • the full list of differences from D1, including the nine D1 tables not yet carried;
    • identity.bootstrap and platform.rate_limit as new tables. It records the
      differences from the D1 model:
    • no realm_id;
    • the user's locale, time zone and WebAuthn handle;
    • the credential subject bounds: up to 1023 bytes for a passkey ID, up to 320 characters for an address;
    • session scope without an agent scope, and no csrf_hash;
    • device and installation binding;
    • auth_flow replacing the two D1 flow tables;
    • nullable installation keys and client_installation_id;
    • trust level 3 = revoked;
    • the stale browser-device rule.

    It also records:

    • the NO ACTION foreign keys and the child-first purge order;
    • retention under AF-PLAT-01's sweeps;
    • personal data: addresses in clear only as an e-mail identity's subject; unsalted address and prefix digests are personal
      data;
    • the acceptance environment, which shares the production Neon project, and its proof-only anonymous-flow ceiling, including
      what that ceiling does not bound.
  • contracts/reuse-map.md: the version-1 native token documents (public/http/v1/native-auth.schema.json) and BrowserSession
    document (browser.schema.json) stay published but are not served by the Go center.

    • An arcforges-mobile installation signs in through IdentityService.
    • Node sign-in is fleet.v1.NodeEnrollmentService (AF-CTR-04); AF-CLD-02 is QR pairing only.
    • The Android Custom Tab sign-in (reused native authorization) has no center-served document yet. This is open:
      AF-AND-01 depends on it, and the AF-CTR-03 Plan record registers the owning task.
    • Browsers will use the new WebBrowserSession document (/session/v1/web/*), served from part A2.

Evidence

  • Reviews: an independent review of bb0a7c9 (changes required: 2 blocking, 5 non-blocking), a delta review of 8b5635d
    (approve, plus 2 non-blocking wording findings fixed in e22907a) and a final check of e22907a (approve). The records are
    posted as comments.
  • Cloud #118, merged at d4e111091535b3f59ce652eb1cf21c552955794b, head bd655a6.
    • Migration 0002 has sha256 c7406aae8669a0422ab33b7d5afecbda88b0860a1c9bdd8f3791a50f96c46317 on main.
    • Both host legs succeeded at the head: linux 11 steps in 377 s, windows 5 steps in 141 s.
    • Five review records are on the PR: an independent review, an adversarial review with 29 confirmed findings that were fixed,
      a delta review, a delta adversarial review with 10 confirmed findings that were fixed, and a round-2 review.
  • Production, main-push run 40840154517, artifact 0.1.0-ci.459.1:
    • the gated migration step applied 0002 to neondb;
    • health reports revision d4e1110, runtime go and helloBackend postgresql-runtime;
    • the published C# gRPC-Web client probe passes (Hello unchanged);
    • identity stays dark: ListAuthProviders, BeginAuthentication and DeviceService.List each answer the domain refusal
      STATE/not_activated (reason identity) from the Worker, where before the merge they answered 404.
  • python3 tools/check_design.py --require-protoc: 0 errors.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H6Cf6jwiVwD6XtQ5VR1vLq

deku2026 and others added 3 commits October 29, 2026 16:10
…refusals and native token documents

Cloud #118 (merged at d4e1110) delivered AF-CTR-03 part A1a. Record its Design companions:

- errors.md: the center ingress rows auth.token_expired and auth.credential_revoked (gRPC 16) for a
  known native bearer, with the browser-cookie behaviour; token_expired answered by a refresh call
  itself means sign in again (adversarial review F10).
- data/cloud-store.md §6: the identity and device store of migration 0002 and its differences from
  the D1 model (no realm_id, session scope and device binding, auth_flow replacing the two D1 flow
  tables, nullable installation keys, client_installation_id, trust level 3, NO ACTION foreign keys
  with the child-first purge order, retention, personal data, the stale browser device rule and the
  acceptance environment's opt-in ceiling).
- contracts/reuse-map.md: the version-1 native token documents stay published but unserved by the
  Go center; browser sessions use WebBrowserSession.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6jwiVwD6XtQ5VR1vLq
- cloud-store.md §6: device retention follows 11 §5 (revoked + 30 days, the device's sessions and
  installations deleted with it, children first); the revocation cascade is A1b's; the owner's
  account purge is AF-ID-02's decision; the acceptance audits grow with prefixes times windows; the
  further D1 differences (dropped step_up_classes and password_hash, new aaguid and
  attestation_format, the reshaped step-up challenge, revoke_reason and installation user_id, the
  nine D1 tables not yet carried, bootstrap and rate_limit without a D1 counterpart); 0002 applied
  to production by run 40840154517.
- reuse-map.md: node sign-in is NodeEnrollmentService and AF-CLD-02 is QR pairing only; the Android
  Custom Tab sign-in has no center-served document yet (open; AF-AND-01 depends on it);
  WebBrowserSession is served from part A2, and the version-1 BrowserSession document is retained
  unserved.
- errors.md: only the Go center produces the two rows, and only methods that require a session read
  a credential.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6jwiVwD6XtQ5VR1vLq
The identity periods are storage limits, not holds; billing records keep their statutory minimum.
The reuse of identity_native_authorization needs its later PostgreSQL migration.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6jwiVwD6XtQ5VR1vLq
@deku2026

Copy link
Copy Markdown
Contributor Author

Review record: ArcForges-Design PR #44 at bb0a7c9

Reviewer: independent reviewer agent, not the author. Head bb0a7c99990f6f7bd86ae973e8d27f2d4874af27, base main 3392d02.

Verdict: changes required. 2 BLOCKING and 5 NON-BLOCKING findings, all fixable in text only.

Findings

  • B1 (BLOCKING): device retention (docs/data/cloud-store.md:105, :107–113).
    • The text invents a "stale browser device" sweep with no rule behind it.
    • The retention list has no rule for devices or installations, and three sources disagree:
      • 11 §5 says "until revoked + 30 days";
      • Cloud postgres-store.md says "with the account";
      • Cloud device.go says "until the account's retention".
    • "Set only by the revocation cascade" sits in a block marked delivered, but the cascade is part A1b's.
  • B2 (BLOCKING): the mobile flow is attributed to the wrong task (docs/contracts/reuse-map.md:46).
    • AF-CLD-02 is QR phone pairing only.
    • Android Custom Tab sign-in (AF-AND-01) is described as reused native authorization, and the PR now says the Go center does
      not serve that document. Nothing in the Plan supplies a replacement, so the gap is hidden.
  • N1: WebBrowserSession is described as served today. At d4e1110 the center serves no /session/v1 route; the browser
    routes are part A2's. The version-1 browser.schema.json is retained but not served, and the PR does not say so.
  • N2: "on every call" is inaccurate (errors.md:104). Anonymous methods, such as RefreshSession, read no credential, and
    the C# host only ever emits auth.unauthenticated.
  • N3: the owner's account can never be purged. The bootstrap row is kept permanently and names that account through a
    NO ACTION foreign key. Purging it is AF-ID-02's decision.
  • N4: the acceptance audits are understated. They grow with prefixes times windows.
  • N5: the list of differences from D1 is incomplete, and platform.rate_limit has no D1 source.
    • step_up_classes and password_hash are dropped.
    • identity.auth_identity gains aaguid and attestation_format.
    • The step-up challenge is reshaped.
    • device.device gains revoke_reason, and device.installation gains user_id.
    • identity.bootstrap is new.
    • Nine D1 tables are not carried over.

Checks run

  • Diff: git diff 3392d02..bb0a7c9.
  • Design check: check_design --require-protoc reports 0 errors.
  • Host statuses: both success (windows 23 s, linux 48 s).
  • Fact-checked against Cloud d4e1110:
    • ingress pipeline.go and errors.go, session/verify.go and session.go;
    • migration 0002 (every column, constraint, foreign key and index);
    • the D1 manifests;
    • postgres-store.md, center-identity.md, config/identity.go, signin.go, wrangler.json, device.go and bootstrap.go;
    • the Contracts schemas native-auth, browser and web-browser, and the AF-CON-01 catalogue pin;
    • the Plan scopes of AF-CTR-03, AF-CLD-02, AF-AND-01 and AF-PLAT-01;
    • AD-0021 §7, AD-0011 §5 and §7, and 11 §5.

Residual risks

  • §6 does not record that 0002 was applied to production.
  • When RefreshSession answers token_expired, the error's retry advice is still SAME_COMMAND. The wording mitigates this.
  • Cloud postgres-store.md still disagrees with 11 §5 on devices; this needs a Cloud follow-up.

Generated by Claude Code

@deku2026

Copy link
Copy Markdown
Contributor Author

Delta review record: ArcForges-Design PR #44 at 8b5635d

Reviewer: independent reviewer agent, not the author. Range: bb0a7c9..8b5635d (one commit, 3 files, +8/−6). Base: main 3392d02.

Verdict: approve. All 7 earlier findings are resolved. Two new NON-BLOCKING wording issues were found; the author fixed them in e22907a.

Earlier findings

  • B1: resolved, and the reading holds.
    • 11 §5 already decides devices: "until revoked + 30 days". AD-0011 sets no retention periods.
    • The child-first order works with 0002's NO ACTION foreign keys: a session's children, then the session, then the
      installations, then the device.
    • Deleting a revoked device's sessions before their own 90 days breaks no Design rule; audit events are kept separately.
    • The Devices bullet now names A1b's cascade.
  • B2 and N1: resolved.
    • Mobile sign-in is through IdentityService (ValidateNativeClaim).
    • Node sign-in is NodeEnrollmentService, and AF-CLD-02 is QR pairing only.
    • The Custom Tab gap is stated as open, with AF-AND-01 depending on it.
    • WebBrowserSession is served from A2, and browser.schema.json is retained but not served.
  • N2–N5: resolved. N5's list matches 0002 and the D1 manifests.
  • Extra: 0002 applied to production, confirmed.
    • Cloud run 40840154517 concluded success, and its gated PostgreSQL migrate step succeeded.
    • Identity is off in production; only env.proof sets identity.

New findings, both fixed in e22907a

  • N-A (NON-BLOCKING): "retention periods are maximums" read as a general rule.
    • Billing retention is a statutory minimum, and the general wording could make AF-PLAT-01 delete billing records early.
    • Scoped to "these identity periods are maximums (storage limits, not holds)"; "all revoked by then".
  • N-B (NON-BLOCKING): "applies to the D1 baseline only" contradicted its own sentence. Changed to "needs that later
    migration on PostgreSQL".

Checks run

  • the diff, in a fresh worktree;
  • check_design: 0 errors, and the new links resolve;
  • host statuses at 8b5635d: both success (windows 20 s, linux 43 s);
  • re-checked against Cloud d4e1110: 0002, device.go, center-identity.md, the Contracts schemas, the Plan scopes and 11 §5;
  • Cloud run 40840154517 and its jobs.

Residual risks

  • Cloud postgres-store.md still says devices are kept "with the account". The coordinator routed the fix to A1b.
  • A revoked native installation ID becomes usable again once the sweep deletes its device at revoked + 30 days, so revocation
    of the ID lasts 30 days. The ID is not a credential; A1b and AF-PLAT-01 should state this (routed to A1b).
  • The acceptance environment was not redeployed by run 40840154517. Its statements describe the configuration; the proof deploy
    is a separate dispatch.

Generated by Claude Code

@deku2026

Copy link
Copy Markdown
Contributor Author

Final delta check: ArcForges-Design PR #44 at e22907a

Reviewer: independent reviewer agent, not the author. Verdict: approve. Nothing is wrong at this head.

  • Diff 8b5635d..e22907a: one commit, docs/data/cloud-store.md (+2/−2). It makes exactly the N-A and N-B edits the
    reviewer proposed, and nothing else.
  • Design check: python3 tools/check_design.py --require-protoc in a fresh worktree reports 0 errors.
  • Host statuses at e22907a: both success.
    • arcforges/windows: 3 steps in 14 s.
    • arcforges/linux: 3 steps in 34 s.
  • Base: main is still 3392d02. The PR is 3 files, +29/−1.
  • The two earlier records stand otherwise: all 9 findings are resolved, and the delta record's residual risks still apply.

Generated by Claude Code

@deku2026
deku2026 merged commit 44a86a9 into main Oct 29, 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.

1 participant