Skip to content

docs(qa): six platform-checklist clauses re-pointed to the behaviour the product has since ruled (#23121) - #23132

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23121-checklist-stale-clauses
Oct 13, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-23121-checklist-stale-clauses

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23121
Clause-②: no

The browser pass of #23104 scored six acceptance clauses in the platform test checklist as fail. In each case the product is right and the clause is out of date: it pins a shape the product has since ruled away. This PR revises the five items that carry those clauses. Each item gets revision +1 and one appended history entry. No product code, test or fixture changes.

Before each edit, I checked the row's "what the product does now" against code and tests. I did not use a browser or boot the app. I read objectui source at this repo's .objectui-sha, 1fb1ced36243. Every objectui file cited below is byte-identical at 7578323a544e, the pin the dispatch named (git diff --quiet exit 0).

Rows: item, clause, old to new, and what it was checked against

Clause indices are zero-based, like a run record's clause. #23104 X is the QA run's own label.

item · clause old new checked against
platform-core.home-admin-cluster-links · acceptance[2] (#23104 A2) · rev 2 → 3 roles, positions and permissions redirect to the sys_position / sys_permission_set object routes roles and positions go to /apps/setup/metadata/position?scope=environment and permissions to /apps/setup/metadata/permission?scope=environment: the Setup metadata catalog, via SystemCatalogRedirect (objectui#7611). users and organizations are unchanged objectui apps/console/src/AppContent.tsx:167-171,289-293 · apps/console/src/__tests__/AppContent.systemHubRoutes.test.tsx:344-382 · packages/app-shell/src/views/metadata-admin/catalog-scope.ts:55 @ 1fb1ced36243
identity-auth.auth-method-matrix · acceptance[9] (#23104 A9) · rev 6 → 7 delete-user answers 404 "to every caller, authed or not" delete-user is never 2xx: a signed-in caller gets 404 (the capability switch) and an anonymous one gets 401 UNAUTHORIZED (session guard). The existing wiring test is the oracle packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts:320-375 (anonymous 401 at :349, authed 404 at :352, callback 404 at :372) · auth-route-ledger.ts:157 @ f931e765b
identity-auth.self-signup-gate · negative[4] (#23104 N5) · rev 2 → 3 under stock invite_only the login page offers the register link and /register renders the form no generic sign-up link, and /register shows the by-invitation notice with no form. The form is offered only for an /accept-invitation/ID redirect or on a deployment with no owner. The negative now fails the old offer-then-refuse shape, and still fails an invitee left without a form objectui packages/app-shell/src/console/auth/signUpOffer.ts:144-157 · apps/console/src/pages/auth/RegisterPage.tsx:125-143,229-257 · LoginPage.tsx:146-153,361-362 · __tests__/signUpFollowsPosture-11691.test.tsx:156-260 @ 1fb1ced36243; server unchanged: packages/plugins/plugin-auth/src/auth-manager.ts:6809-6816 @ f931e765b
access-security.owd-save-gate · acceptance[3] (#23104 A3) · rev 3 → 4 widening a packaged object's OWD answers 403 PERMISSION_DENIED with declaredCode: owd_widening_forbidden (R1) 403 NOT_OVERRIDABLE from the managed-content seal, or ITEM_LOCKED with ?package=. The seal is saveMetaItem's package door. It is asked ahead of every check that judges the body (#22338), and the hatch does not open it (ADR-0131 D6, #22401). R1 cannot be reached here on stock, so its oracle is its unit pins, named in the item. No fixture package was built for it packages/metadata-protocol/src/protocol.ts:20652 (the door, in saveMetaItem, ahead of runAuthoringGate at :21233) · :17465-17537 (refusePackagedBaseOverride) · :16669-16672 (isSealedManagedItem) · packages/spec/src/kernel/metadata-plugin.zod.ts:786 (object: allowEnvironmentOverlay: false) · packages/rest/src/meta-object-owd-gate.test.ts:346-430 · packages/plugins/plugin-security/src/object-posture-gate.test.ts:61-131 @ f931e765b; commits 35afb1587, e02833c24
api-backend.formula-stdlib-matrix · acceptance[0] (#23104 C1) · rev 1 → 2 27 registered stdlib functions; the joinNonEmpty row is the literal joinNonEmpty(['a', null, ' ', 'b'], '-') 29 functions: the 27 plus isoDate and isoDatetime (345d3f3d8, #22347), with their known answers. The joinNonEmpty row now feeds the same values through record fields and expects 'a-b'. The receiver method can is named as outside the count packages/formula/src/stdlib.ts:261-423 (29 chained registerFunction calls, counted from source; can registered at :267 → :196) · packages/formula/src/validate.ts:1240-1280 (the 29 tally) · content/docs/data-modeling/formulas.mdx:178-198 (29 names, 19 rows) @ f931e765b; probe against the built packages/formula/dist/index.mjs (below)
api-backend.formula-stdlib-matrix · acceptance[5] (#23104 C6) · rev 1 → 2 EXPECTED-FAIL: an unregistered function is a silent null at head positive: an active object save whose formula calls sqrt(...) answers 422 INVALID_METADATA (rule expression-invalid, a NAME fault), and nothing is stored. A draft promotion is refused the same way. The read-path residual is named packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts:1630-1700 · packages/lint/src/runtime-gate.object-formula-writes.test.ts:66-107 · packages/formula/src/validate.ts:548 · packages/objectql/src/engine-formula-fault-log.test.ts @ f931e765b; commit f85a83b83 (#22031; card #22019)

The C6 pin search found a test that pins this refusal: the 'runtime authoring gate on OBJECT writes — the formula field verdict (#22019)' block. The item names it, so the clause does not rest on a browser reading alone.

Probe against the built formula package (pnpm --filter '@objectstack/formula...' build under the shared lock, then celEngine imported from packages/formula/dist/index.mjs at f931e765b):

joinNonEmpty(['a', null, ' ', 'b'], '-')                  -> ok:false  "List elements must have the same type, expected type 'string' but found 'null'"
joinNonEmpty([record.a, record.b, record.c, record.d], '-')
  with record a='a' b=null c=' ' d='b'                    -> ok:true   'a-b'
isoDate(date('2026-02-28T13:45:00Z'))                     -> '2026-02-28'
isoDatetime(date('2026-02-28T13:45:00Z'))                 -> '2026-02-28T13:45:00.000Z'
isoDate(today()), now 2026-08-30T22:00Z, Asia/Shanghai    -> '2026-08-31'
isoDate('2026-01-01')                                     -> ok:false  found no matching overload for 'isoDate(string)'
sqrt(4)                                                   -> ok:false  found no matching overload for 'sqrt(int)'

Coupled fields. Each row also revises the fields of the same item that restate the same stale fact, so that no item contradicts itself after the edit:

  • A2: the title, step 4, and the AppContent source note.
  • A9: step 9.
  • N5: the title and step 1. Step 2 drops its "submit the register form" half and keeps the direct POST, because the stock /register has no form for an uninvited visitor. Also one new objectui source note.
  • A3: the title, step 5, the R1 knownGap, the first knownGap's "packaged tighten-only" parenthetical, and the R1 variant. Also two new source notes, including the anchor protocol.ts#refusePackagedBaseOverride.
  • C1: the title, step 1, step 3, the 27-function knownGap, the clause's evidence, and the registerStdLib source note.
  • C6: the title, step 7, and negative[2]. Also two new source notes, including the anchor packages/lint/src/authoring-rules.ts#EXPRESSION_INVALID.

Each history entry lists the fields it touched.

Gates

All gates ran at c84cc2314 (git rev-parse --short HEAD after the last commit). Each ran in its own foreground process with its own log, and the exit code was read before any pipe.

command exit verdict line
node scripts/check-ci-filter-parity.mjs 0 OK: all 197 declared cross-package glob(s) (144 unique) are covered …
node scripts/check-closing-keyword-parity.mjs 0 check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords …)
node scripts/check-closing-keyword-parity.mjs --self-test 0 ✓ … 40 assertions, 5 mutations of the shipped parsers each driven to red.
node scripts/check-comment-mask-corpus.mjs 0 ✓ comment-mask corpus sweep …: 8933 files, 0 disagree, 0 unparseable
pnpm --filter @objectstack/lint run check:doc-formula-expressions 0 ✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 474 files … (first run exited 3, PREREQUISITE NOT MET: lint was unbuilt; re-run after pnpm --filter '@objectstack/lint...' build)
pnpm check:cross-package-test-inputs 0 OK: 30 package(s) read outside themselves, all declared …
pnpm check:doc-authoring 0 ✓ doc authoring guard: 421 files clean …
pnpm check:driver-memory-census 0 check-driver-memory-census: OK …
pnpm check:gitlink-declared 0 check-gitlink-declared: OK (11177 index entries …)
pnpm check:nul-bytes 0 check-nul-bytes: OK (scanned 11168 text file(s) … no raw ASCII control bytes).
pnpm check:platform-checklist 1 check-platform-checklist: 8 problem(s), the same 8 lines at the base f931e765b (sorted problem lines diff empty). None is in the five items, so this PR adds no problem (see Acceptance notes)
pnpm check:refd-timer-probe 0 OK check-refd-timer-probe: 8927 source file(s) swept …
pnpm check:watch-hint-literal 0 ✓ check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s) …

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE, run after the edits with no paths so the script derives the change set (4 paths vs merge base f931e765b), printed ✓ dispatch-gates --ran: 13 derived famil(ies) accounted for — 13 run, 0 NOT-MEASURED (a DERIVED zero …). This is the same 13 the dispatch named. Symbol anchors per file rose and never fell (--anchor-census: access-security 64, api-backend 66, identity-auth 90, platform-core 67, all above their floors). skip-changeset: docs/qa/** ships in no package.

Acceptance notes

  • The check:platform-checklist red predates this PR. At f931e765b it reports 8 problems:

    • 5 ABSENT SYMBOL in access-security.public-form-withdrawal-layers (protocol.ts#anonymousFormIntakeOrgScopeRefusal, #anonymousFormIntakeReopenRefusal and #envWideRawViewRows, the last two each cited twice);
    • 1 ABSENT SYMBOL in attachments-storage.attach-requires-parent-edit (attachment-access-hooks.ts#canEdit), plus that file's SYMBOL ANCHORS LOST (27 resolve, floor 28);
    • 1 ABSENT SYMBOL in search.rls-both-personas (protocol.ts#countable).

    All 8 are outside this card's file surface and untouched here. Carrier: the daily platform-checklist-watchdog workflow, which files or refreshes one issue while main is red. Not filed.

  • identity-auth.self-signup-gate, other text. acceptance[2] ends "which is exactly why the register form stays rendered under the closed posture". After objectui#11691 that is true for an invitee only. That clause is outside this row and is left as written. Its two older objectui source notes also cite line ranges (RegisterPage.tsx,69-88, LoginPage.tsx,136,298) that no longer match the pin.

  • access-security.owd-save-gate, other text. fixtures.requires[1] still says to author the R2 probe with ?mode=draft, while step 3 says to drive it at the active door. That predates this PR and sits outside the row.

  • R1 now has no live path. No write reaches R1's packaged-baseline comparison through PUT /api/v1/meta/object/NAME on any kernel topology: the seal answers first, as the REST pin's own comment records. R1 keeps only its in-process unit pins. This is an observation, not a defect, so it is not filed.

  • can is undocumented. current_user.can(object, verb) is registered inside registerStdLib (as a receiver method) but appears in no doc outside release notes; the formulas.mdx stdlib table and its variable-scope table omit it. This is a doc observation, not filed.

  • Pin discrepancy. The dispatch named .objectui-sha 7578323a544e. origin/main moved it to 1fb1ced36243 (chore(objectui): move the console pin to 1fb1ced36243 (objectui main tip, Half 1 of #23104) #23110) after the PM's read at e9e10fdab. I read at the current pin. Every cited file is byte-identical across the two.

维护者速读(草稿)

改了什么:平台测试清单里五个测试项的六条验收子句改了指向:Setup 旧链接的落点、删除账号接口的应答、注册页在「仅限邀请」下的表现、受管对象 OWD 的拒绝码、公式函数数量与未注册函数的拒绝。只改了 docs/qa/platform-checklist/areas/ 下四个 JSON 文件,产品代码一行未动。

为什么改:#23104 浏览器测试把这六条判成 fail,但产品行为是对的,是清单写的时候早于后来的裁决或实现。不改的话,每次发版 QA 都会重复报出这六个假失败,把真问题淹没。

风险与代价(含回滚):不发布任何包(skip-changeset),不影响运行时。风险只在于清单措辞:若某条改写不准,下次 QA 会把它判成 fail,而不是漏报。回滚就是 revert 本 PR,清单回到旧措辞。

席位意见:

你要做的:无需操作。合并由席位按常规非受管路径完成。


Generated by Claude Code

…cts to the Setup metadata catalog

roles, positions and permissions land on /apps/setup/metadata/TYPE?scope=environment
(SystemCatalogRedirect, objectui#7611), not on the sys_position /
sys_permission_set object routes; users and organizations are unchanged.

Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC
Co-authored-by: Claude <noreply@anthropic.com>
…hipped delete-user and sign-up-offer rules

auth-method-matrix: delete-user is never 2xx, authed 404 and anonymous 401
(the wiring test is the oracle). self-signup-gate: under stock invite_only
the console offers the register form only to an invitation redirect or a
deployment with no owner, and the by-invitation notice to everyone else.

Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC
Co-authored-by: Claude <noreply@anthropic.com>
…anaged-content seal

A widening PUT on a packaged object answers 403 NOT_OVERRIDABLE from the
package door (ADR-0131 D6), which runs ahead of R1 on every topology; R1
keeps its unit pins as its oracle, and no fixture package is built for it.

Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC
Co-authored-by: Claude <noreply@anthropic.com>
…uthoring door's unknown-function refusal

The registration chain gained isoDate and isoDatetime; the joinNonEmpty row
goes through record fields because cel-js refuses the mixed list literal;
the EXPECTED-FAIL clause flips to the 422 INVALID_METADATA refusal the
object save door now gives a formula calling an unregistered function.

Claude-Session: https://claude.ai/code/session_012dGTuJen61ECNHXYXKChoC
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 13, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 13, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 13, 2026 03:05
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit 1ca7a80 Oct 13, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23121-checklist-stale-clauses branch October 13, 2026 03:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants