Repository navigation
Commit 53ef752
docs(skills): objectstack-api says the form's own publicFormGrant authorizes a public submit and the guest_portal name admits nothing (#24262)
Fixes #24239
Clause-②: no
## What changes
One published file and one changeset. No behaviour changes; the form
routes are untouched.
- `skills/objectstack-api/SKILL.md`, the public-form passage (lines
87–89 at `8eccf519`, now 87–91). It said the anonymous form endpoints
「run under a synthetic `{ permissions: ['guest_portal'], anonymous: true
}` execution context」 and named nothing else, so an author read it as
"declare a `guest_portal` set to authorize the submit", or as "the form
falls open without one". It now says what runs: the form's own
declaration authorizes the submit through a `publicFormGrant` on its
target object (create and read-back of its new row, nothing else),
decided before any permission set resolves; the `guest_portal` name on
the submit context admits nothing and needs no set; a set so named only
feeds the grant's result masker. The `enforceAuth` bypass, the
Web-to-Lead / Web-to-Case framing, the field allow-list, the
`beforeInsert` defaults hook, the walled-posture withholding and the two
contract pointers are kept as they were.
- `.changeset/24239-public-form-grant-skill.md` — `@objectstack/skills`:
`patch` (the package ships `skills/**` as `dist/skills/**`; measured
below).
The three texts now say the same thing, each in its own register:
`content/docs/ui/public-data-collection.mdx` (section 2), the
`registerFormEndpoints` docstring in `packages/rest/src/rest-server.ts`,
and this skill.
Before:
```
These bypass `enforceAuth`, run under a synthetic
`{ permissions: ['guest_portal'], anonymous: true }` execution context, and
are intended for Web-to-Lead / Web-to-Case style flows. The framework
```
After:
```
These bypass `enforceAuth` (Web-to-Lead / Web-to-Case flows). The form's own
declaration authorizes the submit: a `publicFormGrant` on its target object
(create and read-back of its new row, nothing else), decided before any permission
set resolves. The submit context's `guest_portal` name admits nothing and needs
no set; a set so named only feeds the grant's result masker. The framework
```
## Line budget (`skills/**` readings)
Tokens follow the ratchet's own convention
(`scripts/check-skills-token-ratchet.mjs`: ceil(utf8 bytes / 4), the
release-stamp `version:` line unpriced); lines are `wc -l`.
| reading | before (`8eccf519`) | after (`e551e42f`) | delta | ceiling |
|---|---|---|---|---|
| `skills/objectstack-api/SKILL.md`, lines | 415 | 417 | +2 | the
order's budget: +2 |
| `skills/objectstack-api/SKILL.md`, tokens | 4642 | 4691 | +49 | 6314
(`check:skills-token-ratchet`) |
| package, every `SKILL.md` under `skills/` (10 files), lines | 4392 |
4394 | +2 | — |
| package, every `SKILL.md` under `skills/` (10 files), tokens | 52555 |
52604 | +49 | per-file ceilings; the gate is green |
Three lines became five. Nothing else in the file moved, and no line was
re-wrapped to pay for them. The widest new line is 82 characters, which
is the file's existing maximum for a prose line (line 180).
## Measured
- **(a) The passage is the only place in the catalog that says it.** At
`8eccf519`: `grep -rn "guest_portal\|publicFormGrant" skills/` hits
once, `skills/objectstack-api/SKILL.md:88`; the control `grep -rn
"enforceAuth" skills/` hits once, line 87 of the same file. No other
skill file carries the claim, so nothing else is fixed here.
- **(b) What runs** was not re-measured; the order carries card #24130's
measurement. The wording follows
`packages/plugins/plugin-security/src/security-plugin.ts` (the
`publicFormGrant` branch, about line 2412: it admits `insert` / `find` /
`findOne` / `count` on the grant's object only, before any permission
set resolves, and resolves the context's named sets only for the result
masker) and the `registerFormEndpoints` docstring as `main` has it.
- **(c) `check:skill-docs` regenerated nothing**: the worktree is clean
after the run. The generator reads frontmatter; the passage is body
text.
- **(d) The file's last `main` touch** is `2c9bf943`, the version
script's frontmatter re-stamp; the passage read exactly as the card
quoted it at `8eccf519`.
- **The package ships the text.** `pnpm --filter @objectstack/skills
build` (its `sync-catalog`, self-test 9 cases then the copy): 「65
file(s) across 10 skill(s) copied from skills/** into dist/skills and
read back byte-identical」, exit 0; `publicFormGrant` appears once in
`packages/skills/dist/skills/objectstack-api/SKILL.md`.
`@objectstack/skills` declares no `test` or `typecheck` script, so there
is no package test to run (a filtered run that matches no script exits 0
and measures nothing, so none is claimed).
- **`origin/main` moved** 3 commits past the base while this was in
flight (`fb6fb24e`). None touches `skills/**`, `.changeset/**` or a gate
that reads them (the derivation names `scripts/check-route-envelope.mjs`
and one ADR anchor as changed across the range; neither is in this
card's derived list), so the branch was not merged forward.
## Gates (head `e551e42f`)
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths; the change set from the merge
base) derived 43 commands. Every exit code was captured before any pipe
(`eval "$cmd" > log 2>&1; status=$?`) and recorded beside the command
for `--ran`.
- **42 of 43 exit 0** — among them `check:skills-token-ratchet` (「54
authored bundle file(s) within their ceilings」; this file 4691 of 6314),
`check:skill-docs` (「Skill docs in sync」),
`check:skill-identifier-liveness`, `check:skill-compatibility`,
`check:skill-frame-sync`, `check:corpus-claim-drift`,
`check:doc-authoring`, `check:role-word`, `check:nul-bytes`,
`check:pm-skill-id-lint`, `check:pm-governed-merges`,
`check:published-files`, and the changeset gates
(`check-adr-0087-registration`, `check-changeset-no-major` and
`check-empty-changeset`, each with `--base origin/main`;
`check:changeset-gate-self-tests`; `check:objectui-changeset`;
`check:pm-changeset-deadline-census`). Two of the 42 first refused with
`PREREQUISITE NOT MET` (exit 3, unbuilt packages): `pnpm --filter
@objectstack/lint run check:doc-formula-expressions` and `pnpm
check:lean-entry-closure`. After `pnpm exec turbo run build
--filter=@objectstack/objectql --filter=@objectstack/formula
--filter=@objectstack/lint --concurrency=2` under the verify lock
(「Tasks: 14 successful, 14 total」; lock 「VERDICT command-exit 0 · held
the lock 95s」) both exit 0 (`lean-entry-closure`: 「Admitted set held
exactly (15 packages); 6 denied names absent」). `check:dts-closure` and
`check:sourcemap-no-sources-content` were re-run over the same 15 built
packages (「75/75 declared declaration file(s) present」; 「105 map(s),
none embed source text」); their whole-tree reading is CI's.
- **1 NOT MEASURED locally:** `pnpm check:dual-build-cjs-loads` — exit
3, `PREREQUISITE NOT MET`: it loads every package's built output, and
111 packages have no `dist/` in this fresh worktree. A full-tree build
is out of proportion for a five-line text change, so this is a declared
narrowing: CI's `Lint & Repo Gates` runs it on this PR and is the
reading of record.
- **`--ran` reconciliation** (every line `command :: exit N`): 「43
derived famil(ies) accounted for — 42 run, 1 NOT-MEASURED (1 DERIVED
from a recorded exit 3)」, 0 UNRUN.
- **Not run locally, CI's:** `test:repo`, the repo-wide `pnpm lint`, the
type-check lanes, and the artifact-roster and wide-population families
the derivation lists outside its total.
- **Stale-tree note from the derivation:** this tree is 3 commits behind
`origin/main` `fb6fb24e`. The two derived-from files that changed across
that range (`scripts/check-route-envelope.mjs` and
`scripts/adr-anchors/packages__rest__src__meta-item-write-routes.ts.json`)
belong to families this card's paths do not name — neither is among the
43 commands — so no command above read an old copy of a script CI will
run differently.
## Acceptance notes
- The docs page also says which parts of a registered `guest_portal` set
the masker reads (its field permissions, and the capabilities it holds
against a field's `requiredPermissions`). That clause is not in the
skill: it costs a sixth line against a +2 budget, and an author who
needs it reads the docs page the passage already sits beside. Noted, not
filed.
- The old text named `anonymous: true` on the context; the new text does
not. The key has no reader (card #24130's measurement: no non-test
property read of `anonymous` in `packages/`), so the skill no longer
teaches it. Noted, not filed.
## 维护者速读(草稿)
**改了什么** — 只改一个对外发布的技能文件 `skills/objectstack-api/SKILL.md`
里讲公开表单(匿名提交)的那一段。原来说这两个端点「在一个合成的 `{ permissions: ['guest_portal'],
anonymous: true }`
执行上下文下运行」;现在改为说清楚:提交由表单自己的声明授权——运行时为它派生一个只限该表单目标对象、只允许创建和读回刚建那一行的
`publicFormGrant`,在任何权限集解析之前就决定;上下文里的 `guest_portal`
这个名字不授予任何权限,也不需要声明权限集;就算部署注册了同名权限集,它也只用于结果脱敏。其余内容(字段白名单、`beforeInsert`
默认值、隔离姿态下的下线、契约文件指引)原样保留。另加一条 `@objectstack/skills` 的 patch changeset。
**为什么改** — 文档页和 REST 代码注释(PR #24237)已经改成与运行时一致的说法,技能文件是第三份文本,还在说旧话。AI
作者读技能时会推断「必须声明一个 `guest_portal` 权限集才能让提交通过」(CRM
示例就是这么被误导的),或者反过来以为不声明表单就会「敞开」——两者都不是运行时的真实行为。发布的承诺必须与运行的契约一致。
**风险与代价(含回滚)** — 纯文本改动,不改任何运行时行为。文件 +2 行、+49 token(上限 6314,现 4691),整个技能包
+2 行、+49 token;所有读这个文件的门禁本地均绿(token
棘轮、skill-docs、identifier-liveness、corpus-claim-drift
等)。风险只在措辞是否准确,已逐句对照安全插件源码和 REST 注释。回滚即 revert 这一个 PR。
**席位意见** —
**你要做的** — `skills/**` 是 Tier H 治理面:请读上面的 Before / After
两段,确认措辞与运行时一致;无误则由授权账号 approve,落地由席位经队列完成,不需要你手动合并。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QBcLjVCmcWbZEk6qhYMib2)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0d34066 commit 53ef752
2 files changed
Lines changed: 14 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
88 | | - | |
89 | | - | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
90 | 92 | | |
91 | 93 | | |
92 | 94 | | |
| |||
0 commit comments