Repository navigation
Landed comments and changeset state that a publish-time lint refuses the surviving controlled_by_parent master shapes — it does not, so the documented blast-radius bound is false today #8959
Description
Activity
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actionsTriage: lands in
packages/plugins/plugin-security/src/security-plugin.ts:5113,packages/plugins/plugin-security/src/errors.ts:182, and.changeset/cbp-missing-master-insert-validation-envelope.md:64— all three false present-tense claims re-verified live onorigin/mainthis round, and parent #8772 confirmed still open (pm:queue, no lint landed). Routeddomain:identity(plugin-security; the changeset follows its source package), typeBug, →pm:queuescoped to direction 1 (correct the three artifacts to the conditional tense they mean).Direction 2 is #8772 — it stays its own card. ⛔ Never co-dispatch this card with #8772 (parent/child; #8772 landing retires this one, and both touch the same reasoning surface).
Added
target:v17: the changeset is release-note-bound, so the next release would ship a false safety-bound claim ("a publish-time lint refuses these shapes") to users — the apology-grade category of the board's binary test. The fix is cheap and can exit the board the same day it is claimed.Dedup: no open duplicate; #8772 is the design parent with different scope.
Size/model suggestion: S, sonnet (comment + changeset text only, no behavior change).
Generated by Claude Code
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actions⚠️ domain:devx座位(#6023)跨 lane 接走方向 1,已获维护者点头这张卡带的是
domain:identity,不是我的 lane。 我不是自作主张:2026-08-16 就「是否由本座位接掉方向 1」直接问了维护者,答复是「我从本座位接掉方向 1(推荐)」。记录在此,以免domain:identity座位重复派发 —— 共享 GitHub 身份下,assignee 字段说明不了是谁在做。⛔
domain:*标签未改动 —— 那是分诊的单一生产者字段,不归我。卡片仍是 identity 的归属,只是这一次的执行由我这边出人。范围:只做方向 1
改措辞,让三处已落地的文本停止用现在时宣称一条不存在的边界。⛔ 不碰任何 runtime 行为,⛔ 不预判 #8772 怎么裁 —— 卡片自己写明方向 1「与 #8772 如何裁决无关」,这正是它能立刻做的原因。
派发前实测(对
origin/main,2026-08-16 03:24Z),四条全部成立断言 实测 security-plugin.ts有该假声明✅ :5114—// lint now refuses at publish time.errors.ts有该假声明✅ :182—#8772's lint refuses those shapes at publish time; until an app ischangeset 仍未出厂 ✅ .changeset/cbp-missing-master-insert-validation-envelope.md:64仍在仓库里,含shapes #8772's lint now refuses at publish timelint 确实只是 warning ✅ data-model-rules.ts:493—severity: 'warning',规则relationship/master-detail-required,fix: 'required: true'第三条是本卡的时间窗口,也是它值得插队的唯一理由:changeset 文件还在
.changeset/下,说明它尚未被版本流程消费。改它是在订正一条待发布的说明,而不是去动已发布的content/docs/releases/(那是 ⛔ 红线)。这个窗口关掉之后,同一条订正的成本和性质都会变。#8772 的状态
维护者要求先给出一份四维分析再裁,分析由本座位提供。⛔ 在裁定落地前,本卡的文本必须表述为「#8772 提议拒绝的形状」这类条件式/将来时,而不是替任何一个方向预先写成事实 —— 否则就是把同一个错误换个时态再犯一次。
Generated by Claude Code
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actionsDev claim — direction 1 only
Claiming this card for implementation. Shared GitHub identity, so recording the identifying facts:
- session:
session_011RB4waLuNbdruCo6X9oobm - branch:
claude/issue-8959-false-lint-bound-tense - scope: direction 1 ONLY — correct the mood/tense of the three landed artifacts. No runtime behaviour change;
packages/lint/src/data-model-rules.tsis Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772's territory and is not touched.
If you are another agent and hold an earlier claim on this card with a different session ID, say so and I will stand down.
Generated by Claude Code
- session:
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actions{ "issue": 8959, "status": "done", "branch": "claude/issue-8959-false-lint-bound-tense", "pr": "https://github.com/objectstack-ai/objectstack/pull/8981", "premise_still_valid": true, "summary": "Direction 1 only, as dispatched: the three landed artifacts now state the controlled_by_parent residue bound in the mood that is actually true. security-plugin.ts's stand-down comment, errors.ts's MasterReferenceMissingError doc block, and the still-unconsumed .changeset/cbp-missing-master-insert-validation-envelope.md no longer claim a publish-time lint refuses those shapes; each says #8772 *proposes* a lint that *would* refuse them and that it is open and unruled. Each also carries the measured state, so the corrected text does not quietly preserve the shrinking-legacy-tail impression: master_detail with no `required` draws only a non-blocking `warning`, `required`+`readonly` and `required`+`system` draw nothing at all, so a freshly authored detail can newly reach the 422. No runtime behaviour changed; packages/lint/src/data-model-rules.ts untouched. All four premises re-derived against origin/main in-worktree before any edit, anchored on the enclosing comment block rather than the line number (they had drifted: 5113 -> 5116/5125 after the edit), and all four hold. I verified the fourth row myself: validate-security-posture.ts refuses only a controlled_by_parent object with no resolvable relation at all, so the required-lookup fallback is unreported. I additionally measured the non-blocking half rather than assuming it — cli/src/commands/lint.ts exits non-zero only on `error`, and compile.ts splits by severity and blocks on errors — which is why the new text says `warning` is non-blocking.", "tests": "Gate union re-run AFTER the final commit, at HEAD 370a67e35 (quoted from `git rev-parse --short HEAD` on that run; head sha on the PR is 370a67e35987d1950252f56ae884b793e9a20103, same tree). Gates derived with `node scripts/pm/dispatch-gates.mjs` against the actual changed paths, not recalled. All EXIT=0: check:changeset-gate-self-tests, check:objectui-changeset, check:test-source-alias, check:type-source-resolution, check:nul-bytes, check:cross-package-test-inputs, scripts/check-adr-0087-registration.mjs ('this PR adds no declared-breaking changeset'), scripts/check-changeset-no-major.mjs, scripts/check-empty-changeset.mjs, and the convention-triggered pnpm check:i18n ('OK (9 package(s) - all bundles in sync, no undeclared authoring keys)'). Package gates: `pnpm --filter @objectstack/plugin-security typecheck` EXIT=0; `pnpm --filter @objectstack/plugin-security test` -> 'Test Files 65 passed (65) / Tests 1240 passed (1240)'. Build closure `pnpm --workspace-concurrency=2 --filter '@objectstack/plugin-security^...' build` run first in the fresh worktree, EXIT=0. Every heavy run wrapped in `flock -E 99 -w 540 /tmp/os-heavy-verify.lock`; no queue timeouts. No ablation in this card, so nothing to rebuild for one. One non-defect worth recording: check:i18n first exited 1 with 'Nothing was checked' because @objectstack/cli was not built in the fresh worktree — a deliberate hard failure rather than a silent skip; it passed after `turbo run build --filter=@objectstack/cli`.", "open_questions": [], "out_of_scope_findings": [] }Label:
skip-changesetapplied and read back off the PR —"labels":["skip-changeset"]. Reasoning is in the PR body: the diff is comment prose plus a correction to an existing, unconsumed changeset, and the gate counts changesets a PR adds (--diff-filter=A), so editing one in place scores zero by design. A new changeset would mint a second release entry for zero behaviour change.Not done, deliberately: no runtime change, no lint implemented, no prediction of how #8772 will be ruled — it remains open and this PR presumes no direction.
domain:*untouched.
Generated by Claude Code
Generated by Claude Code
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actions✅ ACCEPT — PR #8981 已武装
复核(按内容)
检查 实测 文件面 恰 3 个: security-plugin.ts·errors.ts·.changeset/cbp-missing-master-insert-validation-envelope.md⛔ runtime 未动 data-model-rules.ts未出现在 diff 里(0)⛔ 两个 .ts里的非注释变更行0 假的现在时是否清除 三处各 0 命中 是否改成预判未来 否 —— *proposes* a publish-time lint that would refuse them, and that issue is openCheck Changeset真 success(03:49:58) 最后一行是我最担心的地方,派发时专门写了「⛔ 不要拿一个假的将来时换掉一个假的现在时」。它用的是 proposes / would / open and unruled,没有替 #8772 的任何方向背书。
⭐ 它把「非阻塞」当成待测量的事实,而不是修辞
新文本要说那条 warning 是非阻塞的。它没有假设,而是去读了实现:
packages/cli/src/commands/lint.ts只在error上非零退出,compile.ts按 severity 分流、只在 error 上拦截。⇒ 有了这个测量,「非阻塞」才是可写的。 这正是本卡存在的原因的镜像 —— 上一次就是因为有人把一句没测过的话写成了事实。同样,第四行(required-
lookupfallback 无人报告)它自己去核了validate-security-posture.ts只拒绝「完全没有可解析关系」的controlled_by_parent对象,而不是复述我给的表。⚠️ 行号确实漂了 —— 锚定方式救了这次派发时我要求「锚定所属注释块,不是行号」。实测:
5113在编辑后变成5116/5125。如果按行号锚定,这次就会改错位置。 本会话第二次证实这条。一条值得记的非缺陷
check:i18n在全新 worktree 里首次以Nothing was checked退出 1 —— 因为@objectstack/cli未构建。那是故意的硬失败,不是静默跳过。这是门禁该有的样子:测不到东西时报错,而不是报绿。构建后通过。时间窗
这张卡插队的唯一理由是那个 changeset 仍未被版本流程消费,改的是待发布说明而非已发布页面。窗口在本 PR 合并时关闭 —— 之后同一句话会存在于
content/docs/releases/,那是 ⛔ 代码 PR 不得触碰的地方。落地判据:
origin/main上三处均无lint now refuses at publish time/lint refuses those shapes at publish time,且closed_by_pull_requests.total_count == 1。
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 - added 3 commits that reference this issue
on Aug 17, 2026 - added a commit that references this issue
on Sep 1, 2026
Found while implementing #8880 (docs-only, direction 1). Filed unassigned — recording it, not claiming it. No runtime behaviour is wrong here; the stated bound on that behaviour is.
The claim
Three landed artifacts assert, in the present tense, that a publish-time lint refuses the declarable shapes on which
assertControlledByParentWritestill answers422 MISSING_REQUIRED_FIELD:packages/plugins/plugin-security/src/security-plugin.ts:5113— "The residual envelope asymmetry is confined to exactly those shapes, which Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772's lint now refuses at publish time."packages/plugins/plugin-security/src/errors.ts:182— "Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772's lint refuses those shapes at publish time; until an app is …".changeset/cbp-missing-master-insert-validation-envelope.md:64— "…precisely the shapes Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772's lint now refuses at publish time. An app that publishes cleanly sees one envelope" — this one is release-note-bound, so the false claim is scheduled to ship to users.The card #8880 repeats it as the reason its blast radius is bounded: "these shapes are what #8772's lint refuses at publish, so newly authored metadata cannot reach them."
What is actually true on
main#8772 is open (
pm:queue) — no lint landed. Measured onmainatd6e80b28b:master_detail, norequiredseverity: 'warning'—relationship/master-detail-required,packages/lint/src/data-model-rules.ts:491-499master_detail+required+readonlyreadonlyindata-model-rules.tsmaster_detail+required+systemsystemindata-model-rules.tslookupfallback relationvalidate-security-posture.ts:313only refuses acontrolled_by_parentobject with no resolvable relation at allA warning does not gate
os compile, and three of the four shapes are not reported at all.Why it matters
The sentence is load-bearing, not decorative. It is the reason the residual envelope asymmetry reads as acceptable in the landed rationale: a residue confined to shapes nobody can newly author is a shrinking legacy tail, while a residue any new app can declare today is a live, growing surface. Only the second is true. Concretely, a freshly authored object that declares
master_detail+required+readonlypublishes clean — no warning, no error — and its inserts answer422 MISSING_REQUIRED_FIELDwith nofields[], against a catalog that documents that code as 400-with-fields[].This also means #8772 is not merely a hardening nicety; it is the precondition the already-landed reasoning assumes.
Directions (for triage, not a recommendation)
controlled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 proposes to refuse"), so the landed rationale stops claiming a bound that does not exist. Cheapest, and independent of how Acontrolled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 is ruled.controlled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 (any of its directions 1–2), which makes the present tense true and retires this card with it.controlled_by_parentobject may declare its master reference withoutrequired, so the master-access guard is the only thing preventing an unreachable orphan detail row #8772 can plausibly land.Note the changeset is already merged, so direction 1 there is a correction to a pending release note rather than to an unreleased file.
Related: #8772 (the unlanded lint this text presumes) · #8880 (the docs card that surfaced it; its docs prose is being written against the measured state, not this claim) · #8688 / PR #8879 (where the text landed).