You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
storage/public forms: an anonymous public-form submission cannot carry a file — /storage/upload answers 404 to the guest principal, so a required attachment field is impossible on a public form #25572
Ruled: 6377887908 · batch #9 item 1 (#25496, 6377842908) · letter B · 2026-10-24T00:43:45Z (ADR-0138 guest-upload addendum first, implementation after it lands)
Filed from the objectstack-ai/hotsrm v0.1 platform evaluation, 2026-10-23, spec 18.0.0.
What was measured
Anonymous submission through a public form works: forged status, supplier, duplicate_check and owner values are stripped, the record flow fires.
A file field needs an existing sys_file id. POST /storage/upload returns 404 for the guest principal, so no public form can take an attachment, and a required file field makes the form unsubmittable.
Supplier registration in China needs the business licence scan on the first contact; the app had to move the upload to after the portal account exists, which changes the registration process the customer signs off on.
Wanted
A guest upload door bound to the public form: the file is accepted only for the form's declared file fields, size and type limited by the field, stored unattached under the form's organisation (ADR-0138 D4), and either attached by the submission that follows or garbage-collected after a short TTL if no submission arrives.
The same anti-abuse posture as the form itself (rate limit per address, no listing, no read-back of other guests' files).
Acceptance
A public form with a required file field can be submitted by an anonymous visitor; the record is created with the attachment; an upload that is never followed by a submission disappears after the TTL.
Dedupe words: public form guest anonymous file upload storage/upload 404 required file field attachment TTL.
Re-filed as objectstack-fleet[bot] from #25445, same body and labels. #25445 was written off the fleet relay, under the maintainer's personal account, by a project-thread session through GitHub MCP; pm-dispatch allows content writes only through the relay. #25445's thread (triage, ruling, comments) stays there for reference; this card replaces it in the queue.
Session: session_018fnREjMeK9XQeHDwkJXKMW
Claim: PM loop round 1
Session: session_01JVTd3PprStGa26aez5omLB
Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-25572-adr-0138-guest-upload
Worktree: objectstack-issue-25572
Domain: domain:server
Seat: domain:server#2
File surface: phase 1 of the ruling only, the ADR amendment: docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.md, plus any ADR index or anchor file the repo's ADR process requires. ⛔ No implementation in this dispatch; that is phase 2, after the ADR lands. Governed (Tier H): draft PR, waits for the maintainer's approval (stop on breach; explain in the report)
Container & model: S (the ADR; the implementation is M–L later), mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"; the governed-text review owed before landing is CONTRACT_REVIEW_TIER), effort: xhigh (security)
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Serial constraints cleared: none. No open PR touches docs/adr/0138-* (13 open PRs read this fire).
Premise: the ruling is letter B of 6377731715 (#25496), carried on #25445 (the card this one re-files): the director's 6377853567 and the maintainer account's 6377887908 「先派 ADR …ADR 落后再实现」. ADR-0138 on origin/maine649c2d91 names no guest upload door.
{
"issue": 25572,
"status": "done",
"branch": "claude/issue-25572-adr-0138-guest-upload",
"pr": "https://github.com/objectstack-ai/objectstack/pull/25619",
"session": "session_01JVTd3PprStGa26aez5omLB — subagent run, so the parent's harness-stamped id; the claim 6382646973 names it and this branch",
"premise_still_valid": true,
"summary": "Phase 1 only, as dispatched: ADR-0138 gains D2 class 7, the guest upload door bound to a public form. Every constraint of letter B of ruling 6377731715 (records 6377853567 and 6377887908) is written as one of eight rules, each cited by symbol on origin/main. The status line, TL;DR, Enforcement map, Consequences, the unsettled items (4 and 5), an Execution-plan row E5 (#25572) and References were updated to match, and ADR-0056 gained a dated back-pointer line. No code changed. The premise holds. The card's POST /storage/upload is not a route (it was retired, so it answers 404 to everyone). The real upload doors (presigned/complete/chunked) refuse a guest with 401 AUTH_REQUIRED, so a public form cannot take a file. Two places where I departed from the dispatch: (1) file surface: the ADR-0056 back-pointer line is beyond the claim's literal list. I added it on the precedent of the D3 item 5 amendment, which gave ADR-0090 and ADR-0086 their own lines. (2) os-dev.md wants `Part of #25572` as the PR body's first line, while the dispatch asked the body to open with the 维护者速读. I followed os-dev.md: line 1, then the 速读. The relay's read-back row lists assignees but no labels, so the label leg reads FAILED by that rule; a REST read of the PR shows skip-changeset present (with size/m), draft true, assignee sunhaolin, reviewers hotlong and os-zhuang requested.",
"tests": "None owed: the diff is docs only (two ADR files), touches no package and changes no tested behaviour, so there is no ablation. Anchor proof: a scratch run of scripts/symbol-anchors.mjs extractAnchors over both ADRs, diffed against 10b8250ad5, lists 21 anchors this diff adds. Each resolves with class declaration (requireUploadSession, resolveFormBySlug, FILE_REFERENCE_TYPES, maxSize, accept, uploadSizeRefusal, assertFileConstraints, ref_object, ref_id, ref_field, claimFile, LifecycleService, createSysFileReapGuard, findFileHolder, lifecycle, createInboundRateLimitMiddleware, ServerRateLimitConfigSchema, resolveRateLimitKey, requireDownloadSession, DOOR_CLASSES), plus one file-level anchor (stranded-orphan-inventory.ts). Control-byte self-scan of both files: zero hits.",
"gates": "Local, on final head 4285f5e455, derived by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: 20 commands. Exit codes were captured with output redirected, before any pipe. Each is exit 0: check-adr-links (773 relative link destinations resolve), check-adr-links --self-test, check-adr-symbol-anchors (2408 anchors across 142 records resolve), its --self-test, check-ci-filter-parity, check-closing-keyword-parity and its --self-test, check-comment-mask-corpus, lint check:doc-formula-expressions, check:adr-anchors (OK), check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes (OK, no raw ASCII control bytes), check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal. One rerun: check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET, formula/lint dist absent). I built `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2` under os-verify-lock (VERDICT command-exit 0), and the rerun was 0. --ran reconciliation: 20 derived, 20 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero: all 20 recorded an exit code). Outside the derived list: check-issue-citations exit 0, but it read 0 files (docs/adr is not on its surface), so it is NOT MEASURED for this diff. `pnpm lint`: not applicable, because no package was touched. CI on PR 25619 at report time: 42 check-runs, 8 success, 13 skipped, 21 in_progress. Governed Surface Queue Guard is in_progress; Build Core is skipped (paths); Lint & Repo Gates, TypeScript Type Check and Test Core were not yet listed. Convergence belongs to the seat.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)",
"mcp_calls": "0 — no MCP GitHub tool was called",
"api_writes": "2 — (1) relay op pr_create: POST /repos/objectstack-ai/objectstack/dispatches, fleet-write run 40084979968, which opened PR 25619 as a draft with assignee sunhaolin and label skip-changeset (the relay's governed follow-up requested reviewers); (2) this os-dev-report comment on #25572 via scripts/pm/post-stamped.mjs. git push is not counted. REST reads only otherwise.",
"files_changed": [
"docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.md (+176 / -10)",
"docs/adr/0056-permission-model-landing-verification.md (+1)"
],
"line_budget": "n/a — no skills/** file and no ratcheted ledger touched; diff 187 changed lines, under the 3000 human-merge threshold",
"deviations": "(1) file surface: added the ADR-0056 back-pointer line, beyond the claim's literal list, on the precedent named in summary. (2) PR body: line 1 is `Part of #25572` and the 维护者速读 follows it; this follows os-dev.md over the dispatch's opening request. (3) gate rerun: check:doc-formula-expressions first exited 3; I built its prerequisites under the lock and reran it to 0. (4) merged origin/main (10b8250ad5) into the branch before opening the PR, because dispatch-gates refused the stale tree; there were no conflicts and no lockfile change.",
"open_questions": [
{
"question": "Class 7's two empty states (ADR-0138 'What the ruling did not settle', item 4). The first is a deployment whose per-address inbound limiter is unarmed: server.security.rateLimit is opt-in, no examples/ app arms it, and hotcrm at 8a14b56 documents none. The second is a file field that declares neither maxSize nor accept. Does the guest upload door open in these two cases? The text as written opens it in both.",
"options": [
"A (as written): the door opens in both, exactly as the form doors do today. Cost: zero further text. Under A the door is unmetered on every measured deployment, and a field with no maxSize is bounded only by the deployment upload limit (max_upload_mb, 100 MB default).",
"B: the door stays shut until the limiter is armed and the field declares maxSize and accept, which is the ADR-0121 D6 shape for anonymous endpoints, and the form's existing intake-advisory channel states why. Cost: one paragraph of ADR text now (item 4 and the two empty-state sentences in rules 3 and 7) and one admission check in E5. hotsrm must arm server.security.rateLimit and declare its file field's limits."
],
"recommendation": "B. 实际业务需求: hotsrm's supplier-registration form is served either way; under B it costs two config lines. Under A, the named constraint 'rate limit per address' holds on no measured deployment. 项目长远合理性: B keeps ADR-0049 (declared = enforced): the ADR says the door is rate-limited, and it is. A records a limit that does not exist by default. ADR-0121 D6 is the anonymous-door precedent. 防 AI 犯错: under B, an AI that adds a file field to a public form without limits gets a closed door and a stated reason, never an unmetered anonymous byte write that reads green. 创业阶段不扩散: B adds no key and no gate script; it reuses server.security.rateLimit and the field's existing accept/maxSize, plus one admission check. Trade-off, stated as it is: B withholds a door that the ruling's 「与表单同样」 can be read to open, so it is the maintainer's call."
}
],
"out_of_scope_findings": [
"carrier: the seat, off GitHub · a security-family finding on the submit path, redacted from this comment under the disclosure discipline and routed privately; the fix is PR #25682",
"carrier: #25572 (E5) · noted, not filed. Code text still says six door classes: the module doc of packages/core/src/security/assemble-execution-context.ts, the anonymous-door-sweep classification and test headers, and ADR_0138_D2_DOOR_CLASS_ROWS in authz-conformance.test.ts. E5 updates them with the door.",
"carrier: the maintainer (open question above) · noted, not filed. The form doors carry no limiter of their own. The one per-address limiter is the server-wide createInboundRateLimitMiddleware, opt-in, and no examples/ app arms it."
]
}
Tier H seat record → PR #25619 comment 6383110676 (phase 1, the ADR-0138 amendment; contract-tier review PASS; awaits the maintainer's letter C / B / A and approval) · domain:server seat 2 · session_01JVTd3PprStGa26aez5omLB
Ruled: C · the maintainer, verbatim, in domain:server seat 2's session (session_01JVTd3PprStGa26aez5omLB), 2026-10-24T13:04Z: 「25619 C 25495 B」 · recorded by domain:server seat 2 · sunhaolin (the full record is on PR #25619)
C replaces letter B of 6377731715 for this card: no guest upload door. A supplier registers and signs in, then fills the form and uploads through the authenticated upload doors that exist today. PR #25619 (phase 1, the ADR amendment) is closed unmerged; ADR-0138 keeps its door list as it is.
This card's scope under C (the title's ask becomes the rule "an anonymous public-form submission carries no file"):
Claim: PM loop round 1 · server half under ruling C, folded into #25622's dispatch
Session: session_01JVTd3PprStGa26aez5omLB
Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-25622-guest-submit-file-refusal
Worktree: objectstack-issue-25622
Domain: domain:server
Seat: domain:server#2
File surface: the anonymous public-form submit door in packages/rest/src/form-routes.ts (refuse a file field's value, naming the field), its tests; the chain-head claim on #25622 carries the full surface (stop on breach; explain in the report)
Container & model: M, security, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"), effort: xhigh
Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6384562453
Serial constraints cleared: as on #25622's claim (open PR #25641 on form-routes.ts).
Premise: ruling C (the ruling records on PR #25619 and on this card, above). The protocol half is #25650 (domain:spec), not in this dispatch.
merged: true, merge commit e2b40a264bc3dec751bfda500571d3edbcb161c1, merged 2026-10-25T04:00:16Z through the merge queue
origin/main
e2b40a264 is origin/main's tip, single parent
queue branch
no gh-readonly-queue/main/* head for PR 25682 remains
State: closed completed by Fixes #25622 and Fixes #25572 on merge (the folded dispatch). pm:dispatched stripped from both cards in this act.
Delivered (the rule only): under ruling C, an anonymous public-form submission carries no file: the submit door refuses a value in a declared file field, naming it, before anything is written; and a record write takes up a referenced file only within the organization it acts in. Declared Clause-②: no (narrowing), patch, BREAKING; the CONTRACT_REVIEW_TIER review was the director seat's (record 6386760176, PASS).
Activity
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1
Session:
session_01JVTd3PprStGa26aez5omLBAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25572-adr-0138-guest-uploadWorktree:
objectstack-issue-25572Domain:
domain:serverSeat:
domain:server#2File surface: phase 1 of the ruling only, the ADR amendment:
docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.md, plus any ADR index or anchor file the repo's ADR process requires. ⛔ No implementation in this dispatch; that is phase 2, after the ADR lands. Governed (Tier H): draft PR, waits for the maintainer's approval (stop on breach; explain in the report)Container & model:
S(the ADR; the implementation is M–L later),mode:subagent,model: TIER_DEFAULT(dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"; the governed-text review owed before landing isCONTRACT_REVIEW_TIER),effort: xhigh(security)Clause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: none
Serial constraints cleared: none. No open PR touches
docs/adr/0138-*(13 open PRs read this fire).Premise: the ruling is letter B of 6377731715 (#25496), carried on #25445 (the card this one re-files): the director's 6377853567 and the maintainer account's 6377887908 「先派 ADR …ADR 落后再实现」. ADR-0138 on
origin/maine649c2d91names no guest upload door.Generated by Claude Code
docs(adr): ADR-0138 amendment — D2 class 7, the guest upload door bou…
objectstack-fleet commentedon Oct 24, 2026
os-dev-report
{ "issue": 25572, "status": "done", "branch": "claude/issue-25572-adr-0138-guest-upload", "pr": "https://github.com/objectstack-ai/objectstack/pull/25619", "session": "session_01JVTd3PprStGa26aez5omLB — subagent run, so the parent's harness-stamped id; the claim 6382646973 names it and this branch", "premise_still_valid": true, "summary": "Phase 1 only, as dispatched: ADR-0138 gains D2 class 7, the guest upload door bound to a public form. Every constraint of letter B of ruling 6377731715 (records 6377853567 and 6377887908) is written as one of eight rules, each cited by symbol on origin/main. The status line, TL;DR, Enforcement map, Consequences, the unsettled items (4 and 5), an Execution-plan row E5 (#25572) and References were updated to match, and ADR-0056 gained a dated back-pointer line. No code changed. The premise holds. The card's POST /storage/upload is not a route (it was retired, so it answers 404 to everyone). The real upload doors (presigned/complete/chunked) refuse a guest with 401 AUTH_REQUIRED, so a public form cannot take a file. Two places where I departed from the dispatch: (1) file surface: the ADR-0056 back-pointer line is beyond the claim's literal list. I added it on the precedent of the D3 item 5 amendment, which gave ADR-0090 and ADR-0086 their own lines. (2) os-dev.md wants `Part of #25572` as the PR body's first line, while the dispatch asked the body to open with the 维护者速读. I followed os-dev.md: line 1, then the 速读. The relay's read-back row lists assignees but no labels, so the label leg reads FAILED by that rule; a REST read of the PR shows skip-changeset present (with size/m), draft true, assignee sunhaolin, reviewers hotlong and os-zhuang requested.", "tests": "None owed: the diff is docs only (two ADR files), touches no package and changes no tested behaviour, so there is no ablation. Anchor proof: a scratch run of scripts/symbol-anchors.mjs extractAnchors over both ADRs, diffed against 10b8250ad5, lists 21 anchors this diff adds. Each resolves with class declaration (requireUploadSession, resolveFormBySlug, FILE_REFERENCE_TYPES, maxSize, accept, uploadSizeRefusal, assertFileConstraints, ref_object, ref_id, ref_field, claimFile, LifecycleService, createSysFileReapGuard, findFileHolder, lifecycle, createInboundRateLimitMiddleware, ServerRateLimitConfigSchema, resolveRateLimitKey, requireDownloadSession, DOOR_CLASSES), plus one file-level anchor (stranded-orphan-inventory.ts). Control-byte self-scan of both files: zero hits.", "gates": "Local, on final head 4285f5e455, derived by `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: 20 commands. Exit codes were captured with output redirected, before any pipe. Each is exit 0: check-adr-links (773 relative link destinations resolve), check-adr-links --self-test, check-adr-symbol-anchors (2408 anchors across 142 records resolve), its --self-test, check-ci-filter-parity, check-closing-keyword-parity and its --self-test, check-comment-mask-corpus, lint check:doc-formula-expressions, check:adr-anchors (OK), check:closed-ceremony-text, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes (OK, no raw ASCII control bytes), check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal. One rerun: check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET, formula/lint dist absent). I built `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2` under os-verify-lock (VERDICT command-exit 0), and the rerun was 0. --ran reconciliation: 20 derived, 20 run, 0 NOT-MEASURED, 0 UNRUN (a derived zero: all 20 recorded an exit code). Outside the derived list: check-issue-citations exit 0, but it read 0 files (docs/adr is not on its surface), so it is NOT MEASURED for this diff. `pnpm lint`: not applicable, because no package was touched. CI on PR 25619 at report time: 42 check-runs, 8 success, 13 skipped, 21 in_progress. Governed Surface Queue Guard is in_progress; Build Core is skipped (paths); Lint & Repo Gates, TypeScript Type Check and Test Core were not yet listed. Convergence belongs to the seat.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (Clause-②: no)", "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "2 — (1) relay op pr_create: POST /repos/objectstack-ai/objectstack/dispatches, fleet-write run 40084979968, which opened PR 25619 as a draft with assignee sunhaolin and label skip-changeset (the relay's governed follow-up requested reviewers); (2) this os-dev-report comment on #25572 via scripts/pm/post-stamped.mjs. git push is not counted. REST reads only otherwise.", "files_changed": [ "docs/adr/0138-guest-model-anonymous-principal-doors-grants-and-organization.md (+176 / -10)", "docs/adr/0056-permission-model-landing-verification.md (+1)" ], "line_budget": "n/a — no skills/** file and no ratcheted ledger touched; diff 187 changed lines, under the 3000 human-merge threshold", "deviations": "(1) file surface: added the ADR-0056 back-pointer line, beyond the claim's literal list, on the precedent named in summary. (2) PR body: line 1 is `Part of #25572` and the 维护者速读 follows it; this follows os-dev.md over the dispatch's opening request. (3) gate rerun: check:doc-formula-expressions first exited 3; I built its prerequisites under the lock and reran it to 0. (4) merged origin/main (10b8250ad5) into the branch before opening the PR, because dispatch-gates refused the stale tree; there were no conflicts and no lockfile change.", "open_questions": [ { "question": "Class 7's two empty states (ADR-0138 'What the ruling did not settle', item 4). The first is a deployment whose per-address inbound limiter is unarmed: server.security.rateLimit is opt-in, no examples/ app arms it, and hotcrm at 8a14b56 documents none. The second is a file field that declares neither maxSize nor accept. Does the guest upload door open in these two cases? The text as written opens it in both.", "options": [ "A (as written): the door opens in both, exactly as the form doors do today. Cost: zero further text. Under A the door is unmetered on every measured deployment, and a field with no maxSize is bounded only by the deployment upload limit (max_upload_mb, 100 MB default).", "B: the door stays shut until the limiter is armed and the field declares maxSize and accept, which is the ADR-0121 D6 shape for anonymous endpoints, and the form's existing intake-advisory channel states why. Cost: one paragraph of ADR text now (item 4 and the two empty-state sentences in rules 3 and 7) and one admission check in E5. hotsrm must arm server.security.rateLimit and declare its file field's limits." ], "recommendation": "B. 实际业务需求: hotsrm's supplier-registration form is served either way; under B it costs two config lines. Under A, the named constraint 'rate limit per address' holds on no measured deployment. 项目长远合理性: B keeps ADR-0049 (declared = enforced): the ADR says the door is rate-limited, and it is. A records a limit that does not exist by default. ADR-0121 D6 is the anonymous-door precedent. 防 AI 犯错: under B, an AI that adds a file field to a public form without limits gets a closed door and a stated reason, never an unmetered anonymous byte write that reads green. 创业阶段不扩散: B adds no key and no gate script; it reuses server.security.rateLimit and the field's existing accept/maxSize, plus one admission check. Trade-off, stated as it is: B withholds a door that the ruling's 「与表单同样」 can be read to open, so it is the maintainer's call." } ], "out_of_scope_findings": [ "carrier: the seat, off GitHub · a security-family finding on the submit path, redacted from this comment under the disclosure discipline and routed privately; the fix is PR #25682", "carrier: #25572 (E5) · noted, not filed. Code text still says six door classes: the module doc of packages/core/src/security/assemble-execution-context.ts, the anonymous-door-sweep classification and test headers, and ADR_0138_D2_DOOR_CLASS_ROWS in authz-conformance.test.ts. E5 updates them with the door.", "carrier: the maintainer (open question above) · noted, not filed. The form doors carry no limiter of their own. The one per-address limiter is the server-wide createInboundRateLimitMiddleware, opt-in, and no examples/ app arms it." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Tier H seat record → PR #25619 comment 6383110676 (phase 1, the ADR-0138 amendment; contract-tier review PASS; awaits the maintainer's letter C / B / A and approval) ·
domain:serverseat 2 ·session_01JVTd3PprStGa26aez5omLBGenerated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Ruled: C · the maintainer, verbatim, in
domain:serverseat 2's session (session_01JVTd3PprStGa26aez5omLB), 2026-10-24T13:04Z: 「25619 C 25495 B」 · recorded bydomain:serverseat 2 ·sunhaolin(the full record is on PR #25619)C replaces letter B of 6377731715 for this card: no guest upload door. A supplier registers and signs in, then fills the form and uploads through the authenticated upload doors that exist today. PR #25619 (phase 1, the ADR amendment) is closed unmerged; ADR-0138 keeps its door list as it is.
This card's scope under C (the title's ask becomes the rule "an anonymous public-form submission carries no file"):
domain:server): the anonymous public-form submit door refuses a file field's value, loudly, naming the field, for forms published before the publish-time refusal exists too. This seat prepares the dispatch. Its detail rides off GitHub with public forms: an authorization-adjacent gap in how a submission's file field is handled (detail withheld pending maintainer) #25622's (Maintainer-action:there), so this card carries no mechanism.sharing.allowAnonymous) that declares a file field is refused at publish — the protocol half of #25572 (ruling C) #25650 (domain:spec): a form view withsharing.allowAnonymousthat declares a file field is refused at publish and in lint, and the public-forms docs name the register-first route.State: stays
pm:dispatchedunder this seat's claim 6382646973 until the server-half dispatch's new claim is written here.Generated by Claude Code
objectstack-fleet commentedon Oct 24, 2026
Claim: PM loop round 1 · server half under ruling C, folded into #25622's dispatch
Session:
session_01JVTd3PprStGa26aez5omLBAccount:
sunhaolin(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25622-guest-submit-file-refusalWorktree:
objectstack-issue-25622Domain:
domain:serverSeat:
domain:server#2File surface: the anonymous public-form submit door in
packages/rest/src/form-routes.ts(refuse a file field's value, naming the field), its tests; the chain-head claim on #25622 carries the full surface (stop on breach; explain in the report)Container & model:
M,security,mode:subagent,model: TIER_DEFAULT(dispatch-gates --tier: "no path-derived mandate … the tier stays the PM's per-card judgment call"),effort: xhighClause-②: no
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6384562453
Serial constraints cleared: as on #25622's claim (open PR #25641 on
form-routes.ts).Premise: ruling C (the ruling records on PR #25619 and on this card, above). The protocol half is #25650 (
domain:spec), not in this dispatch.Generated by Claude Code
objectstack-fleet commentedon Oct 25, 2026
Landed: PR #25682 →
e2b40a264·domain:serverseat 2 ·sunhaolin·session_01JVTd3PprStGa26aez5omLB· 2026-10-25T04:02Zmerged: true, merge commite2b40a264bc3dec751bfda500571d3edbcb161c1, merged 2026-10-25T04:00:16Z through the merge queueorigin/maine2b40a264isorigin/main's tip, single parentgh-readonly-queue/main/*head for PR 25682 remainscompletedbyFixes #25622andFixes #25572on merge (the folded dispatch).pm:dispatchedstripped from both cards in this act.Clause-②: no (narrowing),patch, BREAKING; theCONTRACT_REVIEW_TIERreview was the director seat's (record 6386760176, PASS).sharing.allowAnonymous) that declares a file field is refused at publish — the protocol half of #25572 (ruling C) #25650,domain:spec). Further findings went to the maintainer off GitHub and are carried on their own cards.Generated by Claude Code