Skip to content

Commit 0687a7f

Browse files
committed
docs,changeset: the public-form intake advisory on save and publish
Claude-Session: https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ Co-authored-by: Claude <noreply@anthropic.com>
1 parent dc0a93d commit 0687a7f

3 files changed

Lines changed: 28 additions & 5 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/metadata-core': minor
3+
'@objectstack/metadata-protocol': patch
4+
'@objectstack/rest': patch
5+
---
6+
7+
Public forms on a walled tenancy posture: saving or publishing a view whose public form cannot take anonymous intake now tells the author why, on the response.
8+
9+
Clause-②: yes (widening)
10+
11+
On a walled posture (`group` or `isolated` in force), an open public form whose object is walled by an organization column cannot take an anonymous submission: the submission carries no organization, and an insert without one into a walled object is refused. The two anonymous form endpoints already answer such a form as a withdrawn one (`404 FORM_NOT_FOUND`), and the administrator's read of the view (`GET /meta/view/:name`) already states why in `_diagnostics.warnings`.
12+
13+
- **`@objectstack/metadata-protocol`**: saving the view (`PUT /meta/view/:name`) or publishing its draft (`POST /meta/view/:name/publish`, and a package's batch publish) now answers success with one `warning` advisory per such form, under `advisories`, with rule `public-form-intake-unavailable`. It is located at the form's `sharing` (for example `views[0].formViews.contact.sharing`), its `message` is the same text the administrator's read states, and its `hint` is the remedy: if the object's rows belong to no organization, declare `tenancy: { enabled: false }` on it. The write is never refused. The advisory reads the posture in force from the `tenancy` service, which is what the anonymous endpoints read: a single-posture deployment, a deployment whose walled posture is degraded to `single`, a deployment with no tenancy service, and a form bound to a tenancy-disabled object get no advisory, and a draft save is not judged. The publish refusal for an unstamped platform schedule flow still reads the requested posture, as before.
14+
- **`@objectstack/metadata-core`**: the intake-availability rule moved here from `@objectstack/rest` and is exported, so the anonymous endpoints, the administrator's read and the publish advisory read one answer: `anonymousFormIntakeUnavailability(object, posture, readObjectSchema)` (`null` when the form can take intake, otherwise the object, the posture and the wall column; it judges the object's effective schema, with the injected `organization_id`), `anonymousFormIntakePosture(tenancy)` (the posture in force, as a tenancy service reports it), `anonymousFormIntakeUnavailableMessage` and `anonymousFormIntakeUnavailableRemedy` (the reason and its remedy), `anonymousFormSharingPath` and `anonymousFormObjectName`, and the type `AnonymousFormIntakeUnavailable`.
15+
- **`@objectstack/rest`**: the anonymous form endpoints and the administrator's read import that rule instead of holding their own copy. Their answers are unchanged.

‎content/docs/deployment/validating-metadata.mdx‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,7 @@ orthogonal to both, and no cell here can carry it; it is written out in
478478
| Declared enforcement that cannot run, **declared on the object being written** — a validation rule's regex / JSON Schema (#4762) and its `format` names (#5178) | ✓ | ✓ | ✓ | ✓ᵒ |
479479
| Declared enforcement that cannot run, **declared on another collection** — sharing-rule conditions (#4698), row-level-security predicates (#4983) | ✓ | ✓ | ✓ | — |
480480
| Platform-schedule `create_record` organization (#6285) | — | — | — | ✓ᶠ |
481+
| Public-form anonymous intake on this deployment's tenancy posture — advisory only (#21476) | — | — | — | ✓ᵛ |
481482
| Autonumber `{field}` interpolation | ✓ | ✓ | ✓ | ✓ᵒ |
482483
| View references — form targets, view-key collisions (#2554) | ✓ | ✓ | ✓ | — |
483484
| Flow authoring anti-patterns (#1874) | ✓ | ✓ | ✓ | ✓ᶠ |
@@ -594,11 +595,17 @@ The fourth door does not weaken that, because it is held to the CLI's verdicts
594595
rather than to its own: a test fails if a rule runs at the runtime publish gate
595596
but not on `os build` — the two publish verbs must not disagree. What that
596597
column narrows is which *types* it judges, never which *verdict* it reaches. The
597-
one deliberate exception is the platform-schedule row (#6285), runtime-only by ruling:
598-
both of its inputs are facts about the **deployment** (the organization this
599-
write lands in, and whether this deployment walls organizations), and a build
600-
machine's environment is a false signal for them — so `os build` must not judge
601-
it at all.
598+
deliberate exceptions are the two rows whose inputs are facts about the
599+
**deployment**, and a build machine's environment is a false signal for those —
600+
so `os build` must not judge them at all. The platform-schedule row (#6285) is
601+
runtime-only by ruling: its inputs are the organization this write lands in and
602+
whether this deployment walls organizations. The public-form intake row (#21476)
603+
reads the tenancy posture **in force**: on a walled posture, an open public form
604+
whose object is walled by an organization column cannot take an anonymous
605+
submission, so the anonymous form endpoints do not offer it, and a save or
606+
publish of the view answers success with a `public-form-intake-unavailable`
607+
warning in `advisories`, located at the form's `sharing`. It never refuses the
608+
write.
602609

603610
Some rows are deliberately not universal across the three commands, and each is
604611
one-directional (none lets a stack through a gate another command enforces):

‎content/docs/ui/forms.mdx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export default defineView({
100100
> - Anything not in the `sections[].fields[]` whitelist is silently stripped at submit time. Treat the whitelist as the form's authoritative "what the public is allowed to set" list.
101101
> - A form whose sections declare **no** fields collects nothing, so the submit is **refused** (`400 VALIDATION_ERROR`) rather than accepting whatever the caller sent (#6920). Its `GET /forms/:slug` publishes no schema either (#6601) — declare the fields and both planes come alive together.
102102
> - Multiple form views per object are fine — only the one(s) with `sharing.enabled === true` and `sharing.allowAnonymous === true` are exposed.
103+
> - On a **walled** tenancy posture (`group` or `isolated` in force), a form whose object is walled by an organization column is **not offered**. An anonymous submission carries no organization, and an insert without one into a walled object is refused, so both anonymous endpoints answer the form exactly as they answer a withdrawn one (`404 FORM_NOT_FOUND`). The administrator is told why, at the form's `sharing`: the view's read (`GET /api/v1/meta/view/:name`) carries it in `_diagnostics.warnings`, and a save or publish of the view answers success with a `public-form-intake-unavailable` warning in `advisories`. If the object's rows belong to no organization, declare `tenancy: { enabled: false }` on it and the form is offered again.
103104
104105
## 2. (Optional) Create the `guest_portal` permission set
105106

0 commit comments

Comments
 (0)