Repository navigation
security(forms): withdrawing a public form from anonymous intake on a walled (and degraded walled) tenancy posture — follow-up to #21331, detail withheld pending maintainer #21468
Description
Activity
- addedarea:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingSomething isn't workingpriority:p1High: required for production / M2High: required for production / M2
on Oct 2, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (follow-up of #21331, dispatched on the maintainer's direct order)
Session:session_018zT8d8NpiQ1ExhuNd5TxY6
Account:hotlong(the seat's linked user asGET /useranswers it; always the card's assignee)
Branch:claude/issue-21468-walled-form-withdrawal
Worktree:objectstack-issue-21468
Domain:domain:services(inherited from the in-flight parent #21331, whose fix PR #21420 is queued); expected surfacepackages/restand the metadata write door, the cross-lane surface triage named on #21331
File surface:packages/rest/src,packages/metadata-protocol/src(only the view save door, if the refusal belongs there),packages/qa/dogfood/test,.changeset/(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(default tier; no path-derived mandate)
Clause-②: no
Thread-read: none
Serial constraints cleared: #21420 (same filepackages/rest/src/rest-server.ts; this branch starts after it lands, or on its head if still queued)Provenance: the maintainer, in Claude Code session
session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-02, verbatim: 「按照你的建议继续,开发完整就进队列合并」 and 「同意, 合并你可以做。」. Labels set by this seat at filing because the card is a derived follow-up of #21331 (same class, same lane); triage may re-route. The withheld detail stays off this card and its PR.
Generated by Claude Code
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 21468,
"status": "done",
"branch": "claude/issue-21468-walled-form-withdrawal",
"pr": "#21473",
"session": "session_018zT8d8NpiQ1ExhuNd5TxY6",
"premise_still_valid": true,
"summary": "Implemented the accepted direction: on a posture where the anonymous form doors cannot honour an organization-scoped change (walled, degraded or not), an organization-scoped view save, draft save or draft promotion that changes which slugs a form opens to anonymous intake is refused 403 NOT_OVERRIDABLE with the reason and the remedy (save it env-wide). The seat is the metadata-protocol save door (saveMetaItem plus the promotion path), reading the tenancy service; no spec change and no new error code (the sibling org-scope refusal's code and status are reused), so Clause-2 stays no. Branched off the head of claude/issue-21331-public-form-withdrawal (4d4d342) because #21420 had not merged at dispatch; this PR's own diff does not touch packages/rest/src/rest-server.ts. AGENTS.md section 2 says stacked series are unsupported; the dispatch ordered this base, so the stacking is stated in the PR body and the branch needs one merge of origin/main after #21420 lands.",
"tests": "At b5e4b51: metadata-protocol full suite 201 files passed / 3 skipped, 2990 tests passed / 19 skipped; new unit block in protocol.org-scoped-write-refused.test.ts 22/22 green (4 refusal cases, 3 controls); new dogfood pin public-form-withdrawal-walled.dogfood.test.ts 5/5 green on a multiTenant posture-only boot (org-scoped withdrawal 403 with nothing saved, org-scoped non-sharing edit 200, env-wide withdrawal makes both doors answer 404 FORM_NOT_FOUND with no row landing, republish restores 200/201); single-posture pins from #21420 plus showcase-public-form and public-form-read-back-masking all green (9 + 6 tests). typecheck green for metadata-protocol and dogfood. Ablation on the committed head: the guard was made to always return null via scripts/ablation-replace.mjs with a restore trap, the package was rebuilt, and ablation-dist-preflight found the marker in 2 dist files. Unit 4 red / 18 green; dogfood 1 red / 4 green. Restore: blob equals HEAD and git diff HEAD is empty; after the rebuild the marker is absent from all 24 dist files. dispatch-gates derived 70 families, all run: 68 exit 0; check-plugin-teardown-shape --self-test exited 3 on the shallow clone and 0 after fetching its pinned commit; check:dual-build-cjs-loads is NOT MEASURED (exit 3, PREREQUISITE NOT MET, unrelated packages have no dist). pnpm lint is NOT MEASURED locally and is declared to CI. CI: in_progress at report time.",
"mcp_calls": "0",
"api_writes": "3 relay writes (fleet-write dispatch): pr_create POST /repos/objectstack-ai/objectstack/pulls (draft #21473); assign POST /repos//issues/21473/assignees (hotlong, read back MATCHES); comment POST /repos//issues/21468/comments (this report). Plus git pushes of the branch (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: POST /forms/SLUG/submit on a walled posture (multiTenant posture-only boot) answers 500 ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED for a published public form bound to a tenant-scoped object (the showcase contact form). GET of the same form serves 200, so the form looks published while every submit fails · evidence: the first run of public-form-withdrawal-walled.dogfood.test.ts on the showcase form, engine.ts resolveSystemInsertOrganization · dedupe words: public form submit walled 500, SystemWriteOrganizationRequired anonymous submit, form intake tenant-scoped object",
"class: b · reach: withheld, authorization class; specifics delivered privately to the dispatching session · dedupe words: withheld",
"carrier: dispatching seat (already noted in the dispatch) · the GET fail-closed answer is 500 FORM_RESOLVE_FAILED while submit answers 503 SERVICE_UNAVAILABLE for the same outcome · noted, not filed"
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 2, 2026 ContributorAuthorMore actionsReview: ACCEPT — PR #21473 (landing when CI is green on the merged head)
Reviewing seat: the dispatching session
session_018zT8d8NpiQ1ExhuNd5TxY6(class-level only).- Base: the branch was cut from the security(forms): access-security.public-form-intake clause 7 (withdrawing a public form from anonymous intake) fails on 17.6.0 — detail withheld pending maintainer #21331 fix branch while fix(rest): withdrawing a public form takes effect on every anonymous intake door #21420 was queued; fix(rest): withdrawing a public form takes effect on every anonymous intake door #21420 has merged, and
origin/mainis now merged into the branch (296d7342). The delta againstmainis exactly this PR's 5 files; the stacking note in the PR body is resolved. - Diff read:
packages/metadata-protocol(save + promotion doors, a slug-projection helper), a unit pin, apackages/qa/dogfoodwalled-boot pin, one patch changeset. No governed surface, nopackages/spec, no new error code (reuses the sibling org-scope refusal's403 NOT_OVERRIDABLE); Clause-② no holds. - Direction: the maintainer's chosen option — refused loudly at authoring where the anonymous doors cannot honour the write, remedy named; env-wide saves and single posture unchanged.
- Re-verified by this seat on the merged tree:
pnpm build72/72; unit block 22/22; dogfood walled pin + both single-posture pins 13/13;metadata-protocoltypecheck green. The developer's ablation reds both pins. - Routed: a sibling withdrawal path the doors do not read is security(forms): a second way of withdrawing a public form from anonymous intake is not honoured by the anonymous doors — sibling of #21331, detail withheld pending maintainer #21475 (withheld; lands after this PR); the walled-posture publish-side 500 is forms: on a walled tenancy posture a published public form bound to a tenant-scoped object is served (GET 200) but every anonymous submit answers 500 ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED #21476.
Landing on the maintainer's instruction (verbatim): 「按照你的建议继续,开发完整就进队列合并」 / 「同意, 合并你可以做。」 — ready + auto-merge once CI on
296d7342is green.
Generated by Claude Code
- Base: the branch was cut from the security(forms): access-security.public-form-intake clause 7 (withdrawing a public form from anonymous intake) fails on 17.6.0 — detail withheld pending maintainer #21331 fix branch while fix(rest): withdrawing a public form takes effect on every anonymous intake door #21420 was queued; fix(rest): withdrawing a public form takes effect on every anonymous intake door #21420 has merged, and
QA-source: #21330 · access-security.public-form-intake · acceptance[6]
Follow-up to #21331 (fix PR #21420). That fix makes withdrawing a public form from anonymous intake take effect on a single-posture deployment, and deliberately leaves two deployment shapes unchanged:
OS_ALLOW_DEGRADED_TENANCY=1).On those shapes the same both-sides contract (a withdrawn form refuses anonymous intake on every door; a published one still accepts it) is not yet guaranteed.
session_018zT8d8NpiQ1ExhuNd5TxY6) holds it.objectstack.Generated by Claude Code