Repository navigation
docs(adr): ADR-0138 D2 gains class 6, the acl public_read file download; the G2 result recorded (still Proposed) - #22433
Conversation
…ad; the G2 result recorded (still Proposed) Record revision under the G2 ruling (letter A): D2's closed list names the ADR-0104 opt-in file download as a sixth door class, with its admission, what it runs as and its enforcer. Every count of the door classes, the adoption rule, the enforcement map, acceptance criterion 2, the quoted ADR-0056 back-pointer text and E2 follow. The G2 sweep's class-level result is recorded: classes 1 to 5 match, the everything-else class does not (three families, named at function level), and acceptance waits on their three defect cards and a re-measurement. Status stays Proposed. Claude-Session: https://claude.ai/code/session_01VZqqwTj2wsihZEbfT6yyYN Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: PR #22433 (draft, base ① Derived judgmentsNo accept set, public surface, export or stored shape moves: the diff is one
Check-runs on the head at the read time above: 35 runs, none failed. ② Semver level
③ Boundary flagsDev flags (
Landing: Tier H. This record is the at-tier contract review the claim Implemented-by: VERDICT: PASS |
Part of #22146
Clause-②: no
What this PR is
Round 4 of #22146: a record revision of
docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.mdunder the G2 ruling6074960686(batch #300 item 1, letter A, maintainer 「同意」). Status stays Proposed.packages/**,content/docs/**,skills/**or any other record. No back-pointer line is written into ADR-0090 or ADR-0056.docs/adr/**, so this PR stays draft and lands only on the maintainer's approval.Part of. What remains on design(v18): the complete guest model in one ADR — identity, doors, grants channel, organization, public-site binding, disclosure, rate limits, and each declared guest key's fate (ADR-0090 D9 enforce-or-remove) #22146: the three defect cards, the re-measurement of the everything-else class, and the acceptance PR.What the revision records
D2 gains class 6, the
acl: 'public_read'file download (ADR-0104 D3 wave 2). The row uses the table's existing columns:acl: 'public_read'(packages/services/service-storage/src/objects/system-file.object.ts#acl). It is an explicit opt-in, because the upload routes create every file asprivate.packages/services/service-storage/src/storage-routes.ts#registerStorageRoutes, at the download gateauthorizeDownload, which both download routes call.origin/maine02833c240: a file markedpublic_readskips the parent-record authorizer and gets the stable URL.authorizeDownloadis a closure insideregisterStorageRoutes. So the row anchors the function and names the gate as a same-line continuation anchor, and both resolve as declarations.The adoption rule now reads: classes 4 and 5 take the guest envelope; classes 1 to 3 and 6 take their own declaration; nothing else serves a guest.
The G2 result and the ruling, at class level only. The full record is under acceptance criterion 2, with short pointers in the Status line, D2 and the enforcement map.
public_readdownload was served anonymously, as ADR-0104 rules, while D2 did not yet name it. The ruling adds it as class 6./i18ndispatcher domain (packages/runtime/src/domains/i18n.ts#handleI18nRequestmakes noshouldDenyAnonymouscall);packages/rest/src/rest-server.ts#RestServer.registerOpenApiEndpoints);/i18ndispatcher domain answers an anonymous caller —handleI18nRequestmakes noshouldDenyAnonymouscall, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page #22432, rest: the API-description endpoints (RestServer.registerOpenApiEndpoints) answer an anonymous caller with the whole object model; ADR-0056 D2 and ADR-0138 D2 require 401 #22430 and service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431 and on a re-measurement. The record quotes the ruling's sentence on that verbatim.Consistency edits that the ruling forced:
packages/**… changes before acceptance" is now "no change this record decides …", followed by one sentence explaining why the three defect cards land first: they enforce ADR-0056 D2 and ADR-0104, which are both Accepted.@objectstack/service-storage.Every count and class-number site
Line numbers are base
e02833c240(identical to27a8b33decfor this file) → head024872cb90.:63→:77):215→:238):248):244–:245→:268–:270):249→:274), not in the dispatch's lead list:487→:519):578→:624):592→:665):607→:682)Sites deliberately left as they are:
:74→:88). It says "the closed list of five door classes", and it is a verbatim quote of6054113537, so editing it would rewrite a ruling. A new paragraph under it (:101–:106) records the G2 ruling and says why the quote still says five.:207);:330);:449);:504);:681).:254). It is still two: class 6 takes no guest envelope.7b926f7600" (:122) is a dated reading, so it stays as measured.6058198880read it as met by the approval on PR docs(adr): ADR-0138 the guest model (Proposed) — doors, grants channel, organization, ownership, and every guest key's fate #22239. This revision is itself a Tier H approval, so whether to mark it met is the seat's call.Verification at
024872cb90I derived the gate list with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree. The change set is 1 path, +121 / −37 against merge basee02833c24, and the tool gave 19 commands. I ran every one at024872cb90and captured each exit code before any pipe:node scripts/check-adr-links.mjs(and--self-test)node scripts/check-adr-symbol-anchors.mjs(and--self-test)node scripts/check-ci-filter-parity.mjsnode scripts/check-closing-keyword-parity.mjs(and--self-test)node scripts/check-comment-mask-corpus.mjspnpm --filter @objectstack/lint run check:doc-formula-expressionspnpm check:adr-anchorspnpm check:cross-package-test-inputspnpm check:doc-authoringpnpm check:driver-memory-censuspnpm check:gitlink-declaredpnpm check:nul-bytespnpm check:pm-governed-mergespnpm check:pm-prior-rulingspnpm check:refd-timer-probepnpm check:watch-hint-literalcheck-adr-symbol-anchorsreports "2232 anchors across 141 records resolve".system-file.object.ts#acl,storage-routes.ts#registerStorageRoutestwice, the#authorizeDownloadcontinuation,i18n.ts#handleI18nRequestandrest-server.ts#RestServer.registerOpenApiEndpoints. All six resolve as declarations.authorizeDownloadNopereads as absent.check-adr-linksreports "715 relative link destination(s) under docs/adr/ resolve".check:doc-formula-expressions. The first run exited 3 (PREREQUISITE NOT MET:@objectstack/formulanot built in the new worktree), which measured nothing. I built the formula and lint closure underos-verify-lock.sh(VERDICT command-exit 0), and the rerun exited 0.check:nul-bytesis OK. A separate control-byte grep on the record exited 1, meaning no hits.dispatch-gates.mjs --ranwith the recorded exit codes reports "19 derived, 19 run, 0 NOT-MEASURED, 0 UNRUN".check-issue-citationswas named by the dispatch but is not in the derived set. I ran it anyway and it exited 0, but it read 0 files, becausedocs/adr/**is one of its deferred surfaces. So it measured nothing for this diff. Instead I checked by REST that rest: the API-description endpoints (RestServer.registerOpenApiEndpoints) answer an anonymous caller with the whole object model; ADR-0056 D2 and ADR-0138 D2 require 401 #22430, service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431 and runtime: the/i18ndispatcher domain answers an anonymous caller —handleI18nRequestmakes noshouldDenyAnonymouscall, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page #22432 are open issues and not pull requests.Changeset
None.
docs/adr/**ships in no package'sfiles[], and this PR adds or changes no.changeset/*.md. The label isskip-changeset, the opt-out that the Check Changeset job inpr-automation.ymlreads.Acceptance notes
public_readopt-in has no in-repo producer.registerStorageRoutescreate everysys_filerow asprivate, and copy-on-claim copies the source row'sacl.FieldSchemadeclares no fileacl, so ADR-0104's "the field/file explicitly declares" exists today only on the file-row side, as thesys_file.aclselect.acl: 'public_read'stays anonymous (ADR-0104) #22431: once an unclaimed upload, such as an organization logo, requires a signed-in caller, nothing in the repository marks that filepublic_read.acl: 'public_read'stays anonymous (ADR-0104) #22431, whose acceptance already asks the dev to measure the in-repo producers of unclaimed uploads. Noted, not filed.维护者速读(草稿)
public_read后的匿名下载(头像、Logo 这类),这是 ADR-0104 早已裁定的做法,这里只是把它写进清单。/i18ndispatcher domain answers an anonymous caller —handleI18nRequestmakes noshouldDenyAnonymouscall, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page #22432、rest: the API-description endpoints (RestServer.registerOpenApiEndpoints) answer an anonymous caller with the whole object model; ADR-0056 D2 and ADR-0138 D2 require 401 #22430、service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431)落地后,重测"其余"一类,全部返回 401,再开验收 PR。public_read这扇合法的门写进清单,把还开着的三扇门和验收条件写清楚,不然下一次重测会把合法的门误判为漏洞,或者把漏洞当成已经关好。public_read文件今天本来就能匿名下载,service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431 修复后仍然可以。public_read(上传一律是private)。service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431 收紧"无归属上传"之后,像组织 Logo 这类文件,如果没人手动标成public_read,未登录时就看不到了。这一点交给 service-storage: a file with no scope and no field owner is downloadable by an anonymous caller who has its id; the download should require a signed-in caller, whileacl: 'public_read'stays anonymous (ADR-0104) #22431 实测。Generated by Claude Code