Skip to content

docs: record AF-CTR-03 parts A1b and A2 (error catalogue, Android Custom Tab decision, receipts and step-up, center account pages) - #45

Merged
deku2026 merged 6 commits into
mainfrom
design/af-ctr-03-companion-1
Oct 31, 2026
Merged

deku2026 merged 6 commits into
mainfrom
design/af-ctr-03-companion-1

Conversation

@deku2026

@deku2026 deku2026 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Records the Design companions of AF-CTR-03 parts A1b and A2 (Plan milestone MC), delivered by Cloud #120 (5ee9ea1), #121 (204f47a) and
the hosted-path hotfix #122 (2f2a3b3). AF-CTR-03 stays active: part B, the live mail adapters and the Plan record follow, so this PR
marks only what is delivered and leaves the target text of later parts as it is.

Changes (seven files)

  • contracts/errors.md
    • UNKNOWN never pairs with AFTER_TIME. The Contracts rule arcError (cohort 1.0.0-ci.416.1, enforced by every generated validator)
      rejects an ArcError whose effect is UNKNOWN and whose retry mode is AFTER_TIME, and the rule retryAdvice requires a reconciliation
      operation exactly for RECONCILE. Four rows contradicted them and now follow them: STATE/peer_unreachable and STATE/cloud_unreachable
      advise AFTER_TIME with DID_NOT_HAPPEN and, with UNKNOWN, RECONCILE reading a named operation that needs no ID the lost reply would have carried, or
      SAME_COMMAND for the methods that create an ID (BeginPairing, BeginSignIn, CreatePhonePairing; idempotent by command_id);
      EXECUTION/provider_error advises RECONCILE (StoreBillingService.GetBillingStatus); INTERNAL/internal advises NEVER when the
      effect is UNKNOWN and AFTER_TIME once when it is DID_NOT_HAPPEN or HAPPENED. NEVER with UNKNOWN advises against an automatic
      resend; a command under a receipt may still be resent. (This is the "E4-INTERNAL" item of the #120 review.)
    • Duplicate delivery (the "N1" item): effect describes this delivery. RESOURCE/overloaded answers a duplicate only while the first
      execution holds a CompletePasskeyRegistration flow attempt, or when the receipt lookup failed after the first delivery committed; any other duplicate of a
      committed command is answered with the stored receipt; an unanswered COMMIT of the call's own write is INTERNAL/internal UNKNOWN NEVER.
    • Reply rules: every StateFailure carries state (the object's kind) and reason (the code), a resource only with a real 16-byte non-zero
      ID (the caller's own or the one it named), retry_at on every AFTER_TIME refusal, a named read on every RECONCILE, and no personal data from a receipt.
    • Delivered against target: Cloud through #122 still answers AFTER_TIME with UNKNOWN for unexpected failures and has no reconciliation field; the follow-up
      is an AF-PROD-01 prerequisite carried by the Plan record; the Contracts fixture is regenerated in the next Contracts window with an explicit pair form.
    • The Worker's own domain replies carry no ResponseMeta (a known exception until a Contracts window).
  • data/cloud-store.md §6: the A1b data model: platform.command_receipt (migration ownership, one row per principal and command ID, the request-bytes
    digest without RequestMeta.correlation_id, which writes have receipts, no token and no e-mail address in a result, 90-day retention, the sweep owner,
    personal data), single-use step-up evidence (operation ID and target, evidence lifetime), the device revocation cascade (none registered yet) and
    admin revoke-sessions.
  • experience/web.md: a new section for the center's own account pages (Cloud #121): routes (/connect and /activate are not served until AF-CTR-04),
    the __Host-af_session cookie (defaults 12 h absolute, 30 min idle, with the policy bounds), seven of ten WebBrowserSession routes, CSRF and Origin rules, the
    return path in the fragment, the constraints (no external asset, one textContent-only script, exactly seven security headers on page routes), the contract
    gap (the error body, the status mapping, the Worker's own plain-text refusals), the dark production state, the evidence, and the two hosted-only findings of
    Cloud #122
    (no-transform against the edge's Web Analytics injection; the Worker's requests to the Container must not follow redirects).
  • contracts/reuse-map.md and experience/android.md: the Android Custom Tab decision (open since docs: record AF-CTR-03 part A1a (identity and device store, ingress refusals, native token documents) #44): AF-CTR-04 supplies a mobile native
    authorization (browser PKCE on the center's own page, the verified app-link redirect https://arcforges.com/app/callback, an additive Contracts document that
    admits arcforges-mobile; the version-1 document stays unserved); AF-AND-01 depends on AF-CTR-04; serving /app/callback and assetlinks.json is not yet assigned.
  • architecture/10-cloud.md: the pages surface in the surface list and the Core activation row, center.surfaces and the Container restart (delivered), a disabled
    pages surface is the Worker's 404, rows 36, 37 and 95 follow the delivered behaviour. architecture/11-security-privacy.md §5: rows for command receipts and for
    flow and rate-limit digests.

Evidence and review

  • Cloud #120 merged at 5ee9ea199ebdf48a2283c0116b437d9aeecde9d3, #121 at 204f47aefe163bcf47674e4a1063ed3e13be4cae, #122 at
    2f2a3b3ff87599d434d8e084e864d579a4047eda. Their review records are comments on those PRs.
  • Production (run 41118664418): artifact 0.1.0-ci.481.1, center.surfaces none; proof (run 41118713200): artifact 0.1.0-ci.482.1,
    center.surfaces identity,pages; the real-browser acceptance (Chromium 153 with a virtual authenticator, MOCKED hardware in a real browser) passed on proof, and a
    real Windows Hello passkey (AR-23) is the owner's remaining step.
  • Statements were written from the merged Cloud code and docs and verified by three reviews (records as comments on this PR): round 1 (changes required, one blocking),
    the round-1 delta (two regressions, fixed) and the round-2 delta (approve, no blocking finding). Host statuses arcforges/linux and arcforges/windows: success on the head.
  • python3 tools/check_design.py --require-protoc: 0 errors.
  • Deferred and recorded: the Plan record (AF-CTR-04 scope, R-AUTH-002, AF-AND-01 depends_on, the owner of the app-link hosting, the AF-PROD-01 prerequisite), the
    reuse-map §2 row, a row-level check_design gate for the pair rule, and the non-blocking residue of the round-2 review (listed in the review comment).

🤖 Generated with Claude Code

https://claude.ai/code/session_01H6Cf6m33VJNzs4rRjpdgys

deku2026 and others added 5 commits October 30, 2026 22:08
…cord the Android Custom Tab decision

- errors.md: an effect of UNKNOWN never pairs with AFTER_TIME (the Contracts rule arcError rejects it): peer_unreachable and cloud_unreachable
  advise RECONCILE with UNKNOWN, provider_error advises RECONCILE, INTERNAL/internal advises NEVER with UNKNOWN. Reply rules (valid
  details, a real resource ID, retry_at on every AFTER_TIME refusal, no personal data from receipts) and the documented meaning of
  RESOURCE/overloaded for a duplicate delivery (effect describes this delivery, not the command).
- reuse-map.md and android.md: the Android Custom Tab sign-in is supplied by AF-CTR-04 as a mobile native authorization (browser PKCE,
  verified app link, an additive Contracts document admitting arcforges-mobile); AF-AND-01 depends on AF-CTR-04.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6m33VJNzs4rRjpdgys
…d the revocation cascade

cloud-store.md section 6 gains the delivered A1b behaviour of Cloud #120 (merged 5ee9ea1): the receipt table and its digest rule, retention and
personal-data statement, the single-use step-up evidence and the device revocation cascade with the operator command.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6m33VJNzs4rRjpdgys
…F-CTR-03 part A2

web.md gains the section for the center's own pages (routes, the WebBrowserSession cookie, CSRF and Origin rules, the constraints and seven
security headers, the contract gap for the browser error body, the dark production state and the evidence); reuse-map.md states that the
WebBrowserSession document has been served since Cloud #121 (merged 204f47a).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6m33VJNzs4rRjpdgys
…the acceptance environment

web.md: page replies carry Cache-Control no-store, no-transform (the Cloudflare edge otherwise injects its Web Analytics beacon into the HTML) and the
Worker's requests to the Container must not follow redirects (a Durable Object stub follows a 303 by default and turned every protected page into
the Worker's 503). Delivered by Cloud #122 (merged 2f2a3b3).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H6Cf6m33VJNzs4rRjpdgys
…y, reconciliation operations and served pages

errors.md: overloaded is the answer to a duplicate only while the first delivery holds a passkey-registration flow attempt or when the receipt
lookup fails; any other duplicate of a committed command replays the stored receipt; an unanswered COMMIT of the call's own write is
INTERNAL/internal UNKNOWN NEVER. The RECONCILE rows (peer_unreachable, cloud_unreachable, provider_error) name their read operations; the
INTERNAL row gains the HAPPENED advice; one-use calls are not resent; the reply rules cover every StateFailure and the caller's own
objects; delivered-against-target and the fixture regeneration are recorded; the Worker's replies without ResponseMeta are a known exception.
web.md: /connect and /activate are not served until AF-CTR-04; seven of ten WebBrowserSession routes are served; policy defaults are
defaults; the seven headers belong to page routes; the JSON error shape, status mapping and Worker refusals are stated; AF-ID-01 becomes
AF-CTR-03. cloud-store.md: migration ownership, receipt retention and sweep owner, step-up operation IDs and targets, no cascade participant
registered yet. Also: reuse-map wording, android.md app-link owner, architecture 10 pages surface and center.surfaces, architecture 11
privacy rows for receipts and flow digests.

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

Copy link
Copy Markdown
Contributor Author

Review record, round 1 (head 79d8ac3)

Method: one independent reviewer and two adversarial fact-check lenses (errors, docs), 21 deduplicated findings, three skeptics per finding (reproduce, refute, impact), and a completeness critic. 68 agents; both host statuses were success on the head; check_design --require-protoc reported 0 errors and the 47 tool tests passed.

Result: changes required.

Reporter Verdict
Independent reviewer changes required (2 blocking wording defects)
Lens errors changes required
Lens docs approve (10 non-blocking findings; F1 closest to blocking)
Critic changes required (confirms errors-1; reclassifies docs-1 as blocking under the literal rule)

The two decisions themselves held: the UNKNOWN/AFTER_TIME rewrite matches the Contracts rule arcError (the four rewritten rows are exactly the four that contradicted it), and the Android Custom Tab decision is consistent with AD-0011 §3, AD-0021, architecture 10/11/12 and the additive-only Contracts rule.

Findings confirmed by at least two of three skeptics: 21 of 21. Confirmed blocking by the skeptics: 1.

Id Finding Class
errors-1 A duplicate of a committed command is answered with the stored receipt, not RESOURCE/overloaded (overloaded only for a held passkey-registration flow attempt and a failed second receipt lookup) BLOCKING (3/3)
errors-2 The RECONCILE rows name no read operation, so no valid ArcError can be built from them lens: blocking; skeptics: non-blocking; treated as blocking
docs-1 / C-3 /connect and /activate listed in the delivered-pages table, but not served reviewer and critic: blocking; skeptics: non-blocking; treated as blocking
errors-3 … errors-9, docs-2 … docs-11, reviewer-8, C-1 … C-6 Imprecise or missing statements (policy defaults as invariants, receipt retention and sweep owner, migration ownership, step-up operation IDs, header scope, Worker refusals and error shape, served routes, resend rule, reply rules, delivered-against-target, privacy table rows, ingress exception, surface list, deferred Plan alignment) NON-BLOCKING

Disposition: all blocking and all one-phrase fixes are applied in the next commit of this branch; Plan alignment (AF-CTR-04 scope, R-AUTH-002, design refs, the assetlinks owner), the remaining architecture/10 rows and a row-level check_design gate are deferred to the Plan-record companion and are listed in the fix spec.


Generated by Claude Code

…dings of its delta review

errors.md: a row that names only state.resource sets state to the object's kind (not the category); the three RECONCILE reads that need an ID only the
lost reply would carry (BeginPairing, BeginSignIn, CreatePhonePairing) advise SAME_COMMAND with UNKNOWN instead; the Effect rule and the pair rule name
retryAdvice and the resend of a command under a receipt; the duplicate sentence notes the credential check; the Cloud follow-up is an AF-PROD-01
prerequisite. architecture/10: a disabled pages surface is the Worker's 404, not not_activated; pages joins the Core activation row; the surface names are
target names fixed by AF-PLAT-01; rows 36, 37 and 95 follow the delivered AF-CTR-03 behaviour. web.md: 413 and 415 in the status mapping, the Worker's
statuses that can follow a started call, its refusals' other headers. reuse-map.md: the app-link hosting is not yet assigned.

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

Copy link
Copy Markdown
Contributor Author

Review record, round 1 delta (head 36cfdd8)

Fix commit 36cfdd8 addressed the round-1 findings. Both host statuses were success on it. Method: independent delta reviewer, two lenses (errors, docs), 11 deduplicated findings, three skeptics per finding, and a critic (41 agents).

Result: changes required. The round fixed 23 of the 25 spec ids, and introduced two regressions that all three skeptics confirmed as blocking:

Finding Class
The new Reply rules said a refusal that names only state.resource sets state to "the category". The merged center sets state to the object's kind (center/internal/arc/arc.go, docs/center-identity.md). BLOCKING (3/3)
architecture/10 §8 now listed pages among the surfaces and kept "a disabled surface is answered with STATE/not_activated"; a disabled pages surface gets the Worker's plain-text 404 (and web.md already said so). BLOCKING (3/3)

Non-blocking, all confirmed (3/3 unless noted): three named RECONCILE reads need an ID that only the lost reply carries (BeginPairing, BeginSignIn, CreatePhonePairing); the Effect rule and retryAdvice/arcError attribution; "only Cache-Control: no-store" for the Worker's refusals; the duplicate-receipt sentence omits the credential check; the status mapping omits 413/415; "before the Container" is wrong for 499/503/504; pages has no activation row; surface names versus the Plan; architecture/10 rows 36, 37, 95; the Cloud follow-up had no owner; the PR body is stale. One finding (reuse-map versus android.md) was not confirmed (1 of 3).

Disposition: every finding above, including the non-blocking ones, is addressed in the next commit (round 2); a second delta review follows. The remaining deferrals (Plan record, reuse-map §2 row, row-level check_design gate) are unchanged.


Generated by Claude Code

@deku2026

Copy link
Copy Markdown
Contributor Author

Review record, round 2 delta (head 42f047c)

Fix commit 42f047c (four files) addressed the two regressions of the first fix round and the non-blocking findings of its delta review. Both host statuses are success on it. Method: independent delta reviewer, two lenses (errors, docs), 11 deduplicated findings, three skeptics per finding, and a critic (38 agents).

Result: approve. Reviewer, lens errors and lens docs approve; the critic raised no blocking gap. No finding was confirmed blocking (0 of 11; each was confirmed real by at least two of three skeptics except one lens-docs item at 1 of 3, and none was rated blocking by any skeptic).

Both round-1 regressions are fixed: the Reply rules say state is the object's kind (matches center/internal/arc/arc.go and the Cloud tests), and architecture/10 §8 names the pages exception (the Worker's plain-text 404). Every RECONCILE read exists in the named Contracts service and needs no ID the lost reply carried; SAME_COMMAND with UNKNOWN is a valid ArcError (only AFTER_TIME with UNKNOWN is forbidden); BeginPairing, BeginSignIn and CreatePhonePairing are idempotent by command_id. check_design --require-protoc reports 0 errors, the 47 tool tests pass, links and tables are intact.

Non-blocking residue, carried to the next Design companion with the Plan record (none changes a statement about delivered behaviour in a way that yields wrong behaviour; they are imprecisions or forward references): the Worker's start-failure 503 and Retry-After versus "499, 503 and 504 never mean the center did not see the request"; the credential-check parenthetical names credential_revoked for a native bearer only; row 37 names AF-ID-02 for the remaining cascade participants where Cloud names AF-CTR-07 and AF-CLD-06, and credits DeviceService.List to #120 (delivered by #118); "#118 to #122" spans an unrelated PR; the decision tree is not reconciled with the INTERNAL/internal row; "the Plan record carries it" is a forward reference until the Plan PR lands; the fleet.proto gloss "passkey or recent authentication"; older Design documents with superseded task owners. The PR body is rewritten for the head before merge.


Generated by Claude Code

@deku2026
deku2026 merged commit 8b0aa6b into main Oct 31, 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