Skip to content

QA run · release-18.3.0-w4-c3b2 (27/27) · 7fa9873f · 2026-11-02 · 23 PASS / 0 PARTIAL / 4 FAIL / 0 BLOCKED / 0 NOT-RUN #28981

Open

Description

@objectstack-fleet

domain:devx#1 · os-warren · session_01JQwxbWJDYbbtH6dhJNoboN
Part of #27377 (wave 4, W4-C3b2)

QA run record for the 18.3.0 release-candidate sweep, wave 4 card W4-C3b2: the unpinned manual set on the browser and mixed surfaces for every area other than studio-authoring, records-forms, approvals, automation and dashboards (those are W4-C3b1). 27 items. Every clause was driven live (Playwright chromium plus the API, DB and log halves) against the Console built in-repo from the subject. Item verdicts are derived from clause verdicts, never hand-assigned. Run under .claude/skills/checklist-test/SKILL.md and docs/qa/platform-checklist/RUNNER.md.

Environment fingerprint

  • Framework: 7fa9873f38f7a0158e3ce17338dcc0f446b113e3 (main, 2026-11-02 02:44Z), detached and pinned; it never followed main or the Version PR chore: version packages #26517. ui/ is the same commit. pnpm install --frozen-lockfile, then pnpm exec turbo run build --concurrency=2 (118/118 tasks, exit 0, 26m33s), then pnpm console:build --concurrency=2 (cache hit plus copy). check-dev-prereqs: 106 build artifacts present.
  • Boot (per item): a scratch copy of examples/app-showcase under the run dir with node_modules symlinked to the tree. OS_PORT=PORT OS_STORAGE_LOCAL_ROOT=RUN/uploads OS_HOME=RUN/home setsid node packages/cli/bin/run.js dev --ui --seed-admin --no-watch -p PORT -d file:RUN/data.db, from the copy. A canary boot reached /_console/home as the seeded admin before any runner started.
  • Ports 42100–42619, one block of 20 per runner, a fresh port and file DB per boot. Extra boots, each on its own port and DB: zero-user --no-seed-admin with and without OS_DISABLE_SIGNUP=true (first-run-owner-bootstrap); OS_DISABLE_SIGNUP=true (self-signup-gate); OS_SEARCH_PINYIN_ENABLED=false with OS_LOG_LEVEL=debug (pinyin-flag-both-sides); env-lock OS_LOCALIZATION_TIMEZONE + OS_MAIL_SMTP_PASSWORD plus a local capture SMTP (settings-hub-roundtrip); OS_AUTOMATION_SCHEDULED_WORK_ENABLED=1 (job-scheduled-run, notification-center); a walled group boot with two organizations (OS_TENANCY_POSTURE=group OS_PLATFORM_OWNER_EMAIL OS_AUTH_MEMBERSHIP_POLICY=invite-only) for webhook-lifecycle A4's cross-org arm; a scratch app copy declaring a bulk-opted webhook (webhook-lifecycle A2); a local verdaccio 6.11.1 registry with the 109 public workspace packages packed at the subject and no upstream for @objectstack/*, @object-ui/* or create-objectstack (cli.scaffold-console-first-paint).
  • Seed: --seed-admin (admin@objectos.ai), the stock showcase seed and demo personas. Members were minted by invite then sign-up, or admin create-user then the persona's own change-password. Each persona's identity was proved with GET /api/v1/auth/get-session before its cells.
  • Execution: 6 runner subagents (opus, effort high), at most 3 running at once, each driving its items one after another with one browser. The orchestrator checked every FAIL against its runner's reproduction rule and source, and reproduced the re-judged i18n FAIL itself on two fresh browser contexts.
  • Hygiene: after the run, git status is clean, examples/app-showcase/.objectstack does not exist, every scratch package and translation probe was deleted, and no listener remains on any run port.
  • Time: environment prep about 91 min (orchestrator 30: install 1, build 27, console and canary 2; runners 61 for scratch boots, fixtures and the verdaccio registry) against about 236 min of testing summed across runners, of which about 165 min were off-clause probes. Prep to testing is about 1 : 2.6. Wall clock 03:33Z to 05:40Z.

Scope

Selector release-18.3.0-w4-c3b2: the item list of card W4-C3b2 in the wave-4 brief of anchor #27377, computed from the ledger at the subject. No planned items. Revisions pinned from the ledger at the subject (all matched the file):

access-security.audit-log-browser r7 · access-security.public-form-intake r3 · access-security.permission-matrix-edit-loop r6 · access-security.capability-declaration-lifecycle r7 · api-backend.formula-stdlib-matrix r7 · cli.scaffold-console-first-paint r7 · i18n.notification-localized-and-clears r6 · i18n.strict-translation-key-rejection r5 · identity-auth.session-list-revoke r3 · identity-auth.api-key-ui-lifecycle r5 · identity-auth.self-service-profile-password r3 · identity-auth.org-membership-team-management r6 · identity-auth.first-run-owner-bootstrap r5 · identity-auth.self-signup-gate r7 · integration-system.webhook-lifecycle r13 · integration-system.job-scheduled-run r6 · integration-system.notify-inbox-delivery r7 · platform-core.settings-hub-roundtrip r7 · platform-core.package-lifecycle-enable-disable r3 · platform-core.notification-center r5 · platform-core.docs-portal-render r3 · platform-core.home-admin-cluster-links r5 · search.pinyin-flag-both-sides r6 · search.console-global-search r6 · ux-conventions.write-feedback r9 · ux-conventions.disabled-control-reason r4 · ux-conventions.labels-over-machine-names r4

The per-clause verdict table is in the two comments below this body.

Derived item verdicts

23 PASS / 0 PARTIAL / 4 FAIL / 0 BLOCKED / 0 NOT-RUN (27 of 27 judged).

  • FAIL (4): i18n.notification-localized-and-clears (A1), platform-core.home-admin-cluster-links (A2), ux-conventions.write-feedback (A0, A1), ux-conventions.disabled-control-reason (A0, A1, A2)
  • PASS (23): every other item.

Delta against wave 3

18 of the 27 items were in W3-C3b's record #27441 (at c4c515ad):

item #27441 here why
api-backend.formula-stdlib-matrix FAIL (r5) PASS (r7) r7 re-pointed A0 to 30 functions; registry, validate.ts and docs agree; 73-row matrix against the built dist, 0 failures
integration-system.webhook-lifecycle PARTIAL (r11) PASS (r13) A2 scored on a declared bulk-opted webhook (deployment-wide under ADR-0131 ruling A); A4's cross-org arm driven on a walled group boot. The in-organization subscription still gets no bulk event (#23166's open question); see the fixture gaps
i18n.notification-localized-and-clears PASS (r5) FAIL (r6) the deep-link target is the seeded in-review task, whose detail page shows an English record:alert on a zh-CN session (R-2)
ux-conventions.write-feedback PASS (r7) FAIL (r9) r9 (ruling 6545938831 ② on #28345) scores Studio's "Saved" status as not write feedback; the autosave row now fails. A first measurement of the ruling, not a regression
cli.scaffold-console-first-paint PASS (r7) PASS (r7) this time the candidate console was exercised: the pre-release registry route ran, served console index-DqtqClJh.js = the tree's build (published 18.2.0 serves index-BJwcizUn.js); lockfile integrities match the candidate tarballs
the other 13 PASS PASS unchanged

Not in #27441 (9): access-security.audit-log-browser PASS, identity-auth.session-list-revoke PASS, identity-auth.org-membership-team-management PASS, identity-auth.self-signup-gate PASS, platform-core.docs-portal-render PASS, search.pinyin-flag-both-sides PASS, ux-conventions.labels-over-machine-names PASS, platform-core.home-admin-cluster-links FAIL (last judged in #24603), ux-conventions.disabled-control-reason FAIL (last judged in #24570).

Reproduction rule for every fail

R-1 · platform-core.home-admin-cluster-links · A2 (stale spec)

  1. Stock boot; form sign-in as admin@objectos.ai.
  2. Open /_console/apps/setup/system/roles, /system/positions, /system/permissions (also via /_console/apps/com.objectstack.setup/system/…).
  3. Expected (clause): one hop to /apps/setup/metadata/position?scope=environment and /apps/setup/metadata/permission?scope=environment. Actual: one hop to /_console/studio/~all/metadata/position?scope=environment and /_console/studio/~all/metadata/permission?scope=environment, Studio's All metadata lists rendering (Position; Permission Set, 18 items). Reproduced twice and once from the canonical prefix.
    Both sides act on their own declarations: feat(setup): Setup's metadata pages open Studio's All metadata area; the catalog's Active switch moves to each item's page #28818 (ADR-0146 D1) moved the Setup metadata catalog into Studio, and the routing pins at this SHA assert the new landing (AppContent.systemHubRoutes / legacyRedirects, 38 passed, routing layer only). The item still names the Setup catalog URL, and still counts 9 Administration targets where the shell now has 8.

R-2 · i18n.notification-localized-and-clears · A1 (product defect, showcase content)

  1. Stock boot (the showcase declares en and zh-CN). A zh-CN user (or a zh-CN browser locale as admin).
  2. Reassign the seeded in-review task "Design system" to the zh-CN user; click the entry in the bell.
  3. Expected: the target page renders in zh-CN, not mixed-language. Actual: object, path, action, highlight, section and field labels are zh, but the callout reads "Awaiting review / This task is in review — confirm the work before marking it done." in English. Reproduced by the runner and twice more on fresh browser contexts by the orchestrator (/_console/apps/com.example.showcase/showcase_task/record/ID for any status = in_review task).
    Mechanism: examples/app-showcase/src/ui/pages/task-detail.page.ts declares that record:alert with no component id, so pages.showcase_task_detail.components.ID cannot address it, and the zh bundle carries no copy for it. A leftover of showcase (zh-CN): pages, objects and actions outside the bundle render in English beside translated navigation — the 414-key coverage baseline is user-visible on the first screens #25505.

R-3 · ux-conventions.write-feedback · A0, A1 (product defect under ruling 6545938831 ②)

  1. As admin POST /api/v1/packages {"manifest":{"id":"com.qa.r6wf","name":"QA R6 Scratch","version":"0.1.0","type":"app","namespace":"qrsix"}}; PUT /api/v1/meta/object/qrsix_widget?package=com.qa.r6wf with fields name and note (label "Note"), sharingModel private.
  2. Form sign-in; /_console/studio/com.qa.r6wf/data?surface=object:qrsix_widget → Form → field "Note" → Properties → Label "QA Remark", Tab.
  3. Network: PUT /api/v1/meta/object/qrsix_widget?mode=draft&package=com.qa.r6wf&surface=studio → 200 state:"draft".
  4. Expected: a toast or inline text naming the field or object. Actual: no toast and no role=status/alert text within 6 s; only the top bar's "Saved HH:MM", the "Draft · 1 unpublished" chip and "Changes 1". Reproduced twice (Note → QA Remark; Name → Widget Name). The other 14 write surfaces passed, including Studio publish and discard.

R-4 · ux-conventions.disabled-control-reason · A0, A1, A2, flow node inspector (product defect)

  1. Stock boot, admin. /_console/studio/com.example.showcase/automations?surface=flow:showcase_task_completed (header "Read-only", Publish disabled with its reason).
  2. Click the canvas node "Compose Summary". ID, Label, Node Type, Function, Inputs, Output variable, Timeout and Remove node are all disabled.
  3. Expected: the reason on hover, on keyboard focus and as an accessible description. Actual: no tooltip on hover; Tab never reaches the controls or a described ancestor; aria-describedby null and title empty on Remove node and the Label input; no adjacent text. Reproduced on two fresh loads. The field rail (objectui#12303) and the validation editor (objectui#12691) carry the described wrapper; FlowNodeInspector.tsx passes disabled={readOnly} with none.

R-5 · ux-conventions.disabled-control-reason · A0 (partly), A1, field inspector in base-field display-patch mode (product defect, regression)

  1. Same boot. /_console/studio/com.example.showcase/data?surface=object:showcase_task → Form → field "Priority".
  2. The rail opens in display-patch mode ([data-testid=field-base-patch-only]): Label, Description, Help text, Placeholder and option labels enabled; API name, Type, Required, Unique, Default value, option values, Track history, the CEL editors, Move up/down and Remove "Priority" disabled.
  3. Expected: each disabled control explains itself on hover, focus and to AT. Actual: no aria-describedby, no title, no focusable described wrapper ([data-disabled-reason] absent from the rail), no tooltip; the explanatory sentence at the top of BASIC is linked to no control and is off-screen when Remove, Track history or the CEL editors are hovered. Reproduced on two fresh loads.
    Mechanism: StudioDesignSurface.tsx fieldRailReadOnly = readOnly && !(extWritable && fieldSel?.kind === 'field') turns false for a base field with a writable pair, so objectui#12303's described wrapper is skipped while ObjectFieldInspector.tsx (displayPatchOnly → locked) disables the non-whitelisted controls. Introduced by feat(studio): add a field to a read-only base object as an extension in its pair #28860 (this subject's head commit, Studio: add a field to a read-only base object — written as an extension in <base>.custom named xxx__c, base fields editable only within the display-property whitelist #28575). knownGaps[1]'s field-inspector regression row no longer holds.

Fixture gaps and partial coverage

  • integration-system.webhook-lifecycle · A2: scored on a declared bulk-opted webhook in a scratch app copy. An in-organization webhook still receives no bulk event from a flow multi-write ("names no organization"), the open question of run record QA run · surface:mixed (90/90) · 36b2889c · 2026-10-12 · 72 PASS / 10 PARTIAL / 8 FAIL / 0 BLOCKED / 0 NOT-RUN #23166, which no open card carries. A4's 503 and stale-membership arms rest on webhook-redeliver-entitlement.test.ts (21 passed, plugin HTTP face over a security-service double); removing a member revokes its session, so the stale claim has no live recipe. The parked-row arm was made by corrupting a sys_secret ciphertext in the run's own DB.
  • platform-core.settings-hub-roundtrip · A8: no stock manifest declares a user-scope secret (carried).
  • platform-core.docs-portal-render · A5: the stock corpus prunes nothing for a member (member subset = admin's, 9/9); only anonymous is pruned, and anonymous has no console tree, so the UI mirror never exercised pruning.
  • ux-conventions.disabled-control-reason: variants 4 (form submit disabled) and 5 (member toolbar disabled) have no stock instance; both dialogs validate on submit, and a member gets controls removed, not disabled.
  • identity-auth.api-key-ui-lifecycle · A1: the key owner held one live session (1 = 1 against the admin's 4); still discriminating.

Checklist-accuracy findings (for the anchor, not extracted)

  • platform-core.home-admin-cluster-links: title, steps[0], acceptance[0], knownGaps[1], source[1]/[2] still say 9 Administration targets onto the Setup catalog; 8 at this SHA, landing in Studio (feat(setup): Setup's metadata pages open Studio's All metadata area; the catalog's Active switch moves to each item's page #28818). acceptance[3]'s "Keyboard shortcuts" is in the member's Help menu only inside an app, not on /home. The item is on QA checklist: rewrite the Setup-designer items to the Studio door and add the .custom customization journey, with one live e2e through Studio #28579's list of Setup → Metadata items to rewrite.
  • ux-conventions.write-feedback: variants[5]/knownGaps[0] quote the Invite toast as the Invitation sent to … successMessage; since invite-member answers outcome by mail delivery and sys_invitation gains a server copy_invitation_link action that answers the accept URL (ruling E on #27797) #27843 outcomeMessages wins, and a mail-less boot shows the link_only copy. variants[10]'s /apps/setup/metadata/object/OBJ now redirects to /studio/~all/metadata/object/OBJ (feat(setup): Setup's metadata pages open Studio's All metadata area; the catalog's Active switch moves to each item's page #28818). An update-mode import CSV must carry every required column.
  • ux-conventions.disabled-control-reason: knownGaps[0] says Archive has no author reason; it now declares disabledReason: 'Mark the task done first.', and it has no record_section placement. knownGaps[1]'s automation Enabled toggle is now enabled on the read-only package. Import Next shows its reason as an adjacent banner, not a hover tooltip.
  • ux-conventions.labels-over-machine-names: knownGaps[0]'s objectui#13056 caveat no longer reproduces (Explain's chips show labels); variant 7's "user values" has no instance on the task record page.
  • identity-auth.session-list-revoke: steps[3]/source[1] say revoke_session keys on token; it now targets /api/v1/auth/sys-session/revoke with recordIdParam: 'sessionId'. The toolbar action goes through POST /api/v1/actions/sys_session/revoke_my_other_sessions.
  • identity-auth.api-key-ui-lifecycle: revoke/restore go through POST /api/v1/actions/sys_api_key/revoke_api_key|restore_api_key, not a data PATCH.
  • identity-auth.first-run-owner-bootstrap: knownGaps[1]/source[2] are stale; bootstrap-status answers from hasBootstrapWindow() → isBootstrapCreation() (human users only), so the described divergence cannot happen. The owner's first /setup visit opens a timezone dialog.
  • identity-auth.org-membership-team-management: the Members tab shows no row actions without interaction (steps[1]).
  • integration-system.webhook-lifecycle: knownGaps[1] should name the declared-webhook route; steps[3]'s "api trigger" is simpler as an autolaunched flow via POST /api/v1/automation/NAME/trigger; a retriable failure reads pending with next_retry_at, never failed.
  • integration-system.job-scheduled-run: the handler-not-found WARN says only os start --artifact resolves handlers, yet os dev ran every other handler job; os dev logs at warn, so A2's per-attempt log needs a debug boot (run rows carry the attempts).
  • integration-system.notify-inbox-delivery: there is no GET /notifications/ID door, so a "by id 404" proves nothing about scoping.
  • platform-core.notification-center: "View approvals" is a button; ?view=my_pending is not a data-API parameter (400), so the verify should name the view's filter.
  • platform-core.package-lifecycle-enable-disable: the app-level not-found is a full-screen named verdict without header or sidebar ("inside the shell" is ambiguous); the console canonicalises the stale link's app segment to the package id.
  • platform-core.docs-portal-render: with one book, the per-app docs index opens the reader directly.
  • search.pinyin-flag-both-sides: debug logs need OS_LOG_LEVEL=debug (dev defaults to warn); plugin counts now 54 vs 53.
  • search.console-global-search: the palette sends an objects= allow-list and limit=24, so its counts differ from a bare API call.
  • cli.scaffold-console-first-paint: the pre-release route works in about 6 min; npm publish tarballs/x.tgz is read as a GitHub shorthand (use ./tarballs/x.tgz); candidate and published both say 18.2.0, so provenance must be proven by integrity with a run-local npm cache.
  • access-security.audit-log-browser: the page lives at /_console/apps/com.objectstack.setup/system/audit-log.
  • access-security.permission-matrix-edit-loop: the Setup door redirects to /_console/studio/~all/metadata/permission/S; matrix rows carry no perm-row-* test ids; S must also grant create on showcase_project for M to create tasks.
  • access-security.capability-declaration-lifecycle: no seeded persona holds showcase_ops (a minted member was granted it).
  • api-backend.formula-stdlib-matrix: a draft refused at promotion stays pending, and publish-drafts is all-or-nothing, so steps[6] should run publish-drafts last.
  • i18n.strict-translation-key-rejection: the bundle door reports a bad locale as invalid_key on the record key, not invalid_format at locale.
  • i18n.notification-localized-and-clears: the bell's accessible name is "Open inbox" / 「打开消息中心」.

Off-clause probes (RUNNER rule 8)

About 165 minutes across the 27 items (5–8 min each), on the same boots and as the same personas.

Doors probed: sys_session / sys_audit_log / sys_api_key / sys_user_permission_set data doors; auth revoke-session, sys-session revoke, update-user, change-password, set-password, organization member/role/team and invitation doors; public forms; capability and permission metadata doors; packages enable/disable/delete/publish-drafts/commits/revert; settings namespaces; notifications read/read-all; webhooks redeliver and activation; job compile; translations; search; console routes under /apps/setup/… and /apps/APP/system/…; the scaffolder's os validate.

Boundary classes: empty, missing and unknown ids and tokens; another user's id; another package's commit id; malformed role names; case variants of a valid locale; unknown objects in a grant or translation; repeat and no-op writes; a member and anonymous on admin doors; the alias vs canonical app id; six parallel sign-ups on a zero-user boot.

Findings extracted as cards are listed in the close-out comment. Observations not filed (by design, or below the filing gate): update-user accepts an image that is any https or data:image/… URL (javascript: refused; the console never sends either); GET /packages/UNINSTALLED/commits answers 200 with history while a never-existed id answers 404; a translation's objects.no_such_object saves 200; DELETE /api/v1/meta/capability/showcase.export_data answers 200 reset:false with nothing removed; a failed import's toast says "skipped 1" while the response counts it under errors; Setup → Users shows Email Verified/Banned as disabled checkboxes with no reason (display-only, scope question for ux-conventions); replacing a palette query in one input event leaves cmdk with nothing selected (seen only with Playwright's fill).

No security finding in this run.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbWJDYbbtH6dhJNoboN

    Per-clause verdicts, part 1 of 2 (items 1–13)

    Clause ids: A# = acceptance[#], N# = negative[#], zero-based. One line of text evidence each; the full per-runner evidence (requests, response strings, row values) was kept in the run environment.

    access-security.audit-log-browser rev 7 — PASS

    • A0 pass: admin GET /api/v1/data/sys_audit_log $filter action=login → row KH1WqAIC… action login, user_id vjKW0wJC… (the member), object_name sys_session; action=delete → total 1, row TBHG47XQ… user_id = admin, object_name showcase_task …
    • A1 pass: screenshot of /_console/apps/com.objectstack.setup/system/audit-log (form sign-in) showed the painted table (Timestamp/Action/Object/Record/Actor/IP); post-screenshot DOM rows: login rows with actor "QA R3 Member" and object sys_session …
    • A2 pass: choosing Action=Delete re-issued GET /api/v1/data/sys_audit_log?$filter={"action":"delete"}&$expand=user_id&$orderby=created_at desc&$top=51&$skip=0 → 200, 1 record; screenshot shows the single delete row and "Page 1 · end" …
    • A3 pass: clicking the showcase_contact update row opened the side sheet; screenshot shows "Change payload", a "Before" panel with pretty-printed {"title": "Engineering Manager"} and a separate "After" panel {"title": "Engineering Manager QA"} — two panels …
    • A4 pass: field-by-field compare of DOM rows vs an independent admin API read (bearer, same filters): login 11 page rows / 11 API rows in the page's window, 0 field mismatches, 0 API rows missing; delete 1/1, 0/0; config_change 3/3, 0/0 (action, object_name …
    • A5 pass: POST /api/v1/data/sys_audit_log (admin) → 405 OBJECT_API_METHOD_NOT_ALLOWED "API operation 'create' is not allowed", allowed [get,list,aggregate,search,export]; PATCH /…/ID → 405 'update' not allowed, same allowed set; member POST → 405 …
    • N0 pass: login, delete and config_change each left a row (above).
    • N1 pass: no POST/PATCH succeeded (405 each).

    access-security.public-form-intake rev 3 — PASS

    • A0 pass: anon GET /api/v1/forms/contact-us → 200; objectSchema.fields keys = [name, email, company, message]; owner_id / organization_id / status / source / created_by absent from objectSchema.fields and from form.sections[0].fields (name, email, company …
    • A1 pass: anon POST /api/v1/forms/contact-us/submit {name,email:'forger@example.com',company,message, owner_id:'usr_victim', organization_id:'org_forged', created_by:'usr_forged_creator', status:'closed', source:'forged_src'} → 201 {"id":"mMXM_kE2B0ymMASY"} …
    • A2 pass: same landed row status 'new', source 'web' (submitted 'closed' / 'forged_src').
    • A3 pass: 201 + the landed row readable by staff with name 'QA R3 Forger', email 'forger@example.com', company 'Forge Co', message 'hello from r3' persisted; no guest_portal profile involved, no Authorization on the request.
    • A4 pass: anon GET /api/v1/forms/contact-us/lookup/owner_id → 404 {"success":false,"error":{"code":"ENDPOINT_NOT_FOUND","message":"Not found"}}, byte-identical to a never-registered sibling GET /api/v1/forms/contact-us/never_registered_qa (404 ENDPOINT_NOT_FOUND) …
    • A5 pass: GET /forms/contact-us → 302 to /_console/f/contact-us; the public page painted "Inquiry / Tell us about yourself" with Name*, Email*, Company, Message* (screenshot); filled via Playwright fill (values verified) …
    • A6 pass: PUT /api/v1/meta/view/showcase_inquiry.contact (config.sharing.allowAnonymous:false) → 200 "Saved customization overlay … state=active"; anon GET /api/v1/forms/contact-us → 404 FORM_NOT_FOUND "No public form configured at /forms/contact-us" (anon submit also 4 …
    • N0 pass: no forged anchor landed; schema exposes no server-managed anchor (A0/A1).
    • N1 pass: raw body {"name":"QA R3 Proto",…,"proto":{"owner_id":"usr_victim","organization_id":"org_forged","status":"closed"},"constructor":{"prototype":{"owner_id":"usr_victim2"}}} → 201; landed row owner_id null, organization_id the deployment org …

    access-security.permission-matrix-edit-loop rev 6 — PASS

    • A0 pass: baseline as M DELETE /api/v1/data/showcase_task/exc2ID0EybsIluFm (M's own) → 403 PERMISSION_DENIED; admin re-read 200 (row still there).
    • A1 pass: in the editor, checkbox "showcase_task Delete" unchecked → clicked → checked → Save: network PUT /api/v1/meta/permission/qa_r3_matrix (no ?mode=draft) body …"showcase_task":{…"allowDelete":true}… → 200 "state":"active" seq 3 …
    • A2 pass: as M DELETE showcase_task/Xl25lyGzTWEhO46o → 200 {"success":true}; admin re-read → 404 RECORD_NOT_FOUND.
    • A3 pass: editor flip back (checked → unchecked) + Save → PUT 200 state active seq 4 (allowDelete:false); publish → 404 NO_DRAFT; M DELETE showcase_task/TSlngENe3z_YA9qO → 403 PERMISSION_DENIED; row still readable by admin.
    • A4 pass: admin inserts sys_user_permission_set {M, qa_r3_extra} → 201; M POST /api/v1/data/showcase_product → 201 (baseline before assign 403); admin DELETE that assignment row → 200; M POST showcase_product → 403 PERMISSION_DENIED.
    • A5 pass: re-opened the editor (fresh browser) — screenshot shows the Task (showcase_task) row with C/R/U checked and D unchecked; DOM checkbox "showcase_task Delete" data-state=unchecked = last published allowDelete:false. FLS too: Project row expanded …
    • N0 pass: every editor Save produced a landed PUT (200) and M's live access followed it (A1–A3, FLS).
    • N1 pass: PUT /api/v1/meta/permission/qa_r3_matrix?mode=draft with allowDelete:true → 200 "state":"draft"; published GET still allowDelete:false; M DELETE own task → 403 (draft alone does not enforce); POST …/publish → 200 "Published draft"; M DELETE → 200 …

    access-security.capability-declaration-lifecycle rev 7 — PASS

    • A0 pass: GET /api/v1/meta/capability/showcase.export_data → 200 item {name:'showcase.export_data', label:'Export Showcase Data', description:'Bulk-export showcase records (accounts, invoices) to CSV/XLSX.', scope:'org', packageId:'com.example.showcase' …
    • A1 pass: GRANT/DENY: showcase_zoo_perm_held → ops 200 {"success":true,"data":{"ok":true,…}}; plain 403 PERMISSION_DENIED "Action 'showcase_zoo_perm_held' on 'showcase_field_zoo' requires capability [showcase.export_data] — caller is missing [showcase.export_data]" …
    • A2 pass: scratch copy declaring a raw capability {name:'manage_platform_settings', scope:'platform'} appended to capabilities: os validate exit 0, os build exit 0 (artifact written in the copy); os dev --no-compile -p 42307 refused at boot, process exit 1 …
    • A3 pass: scratch copy with raw entry {name:'qa.galaxy', scope:'galaxy'} appended after the two declared capabilities: os validate exit 1 "✗ capabilities.2.scope: Invalid value 'galaxy'. Expected one of: platform, org." …
    • N0 pass: shadow refused at boot; no runtime capability write answered 2xx.
    • N1 pass: plain member refused held; missing executed for nobody; and refused for the export_data-only holders.
    • N2 pass: after withdrawal from the clone, the holder was refused (403) on the first invoke — no cached grant.
    • N3 pass: ops holder executed held; empty executed for every persona.
    • N4 pass (mis-run guard): the REST 404 was recorded and not scored; clauses were scored on the dispatcher /actions domain.

    api-backend.formula-stdlib-matrix rev 7 — PASS

    • A0 pass: source count — packages/formula/src/stdlib.ts registerBoundStdLib chains exactly 29 registerFunction calls (now, today, daysFromNow, daysAgo, isBlank, coalesce, trim, joinNonEmpty, daysBetween, addDays, addMonths, date, datetime, isoDate, isoDatetime, abs …
    • A1 pass: today() under Asia/Shanghai at 2026-08-30T22:00Z → 2026-08-31T00:00:00.000Z (UTC control → 2026-08-30T00:00:00.000Z); daysFromNow(2) → 2026-09-02T00:00Z; daysAgo(1) → 2026-08-30T00:00Z; daysFromNow(0)==today() true; isoDate(today()) → '2026-08-31' …
    • A2 pass: addMonths(date('2026-01-31'),1) = 2026-02-28T00:00:00.000Z (and 2024 → 02-29); floor(-1.2) = -2, ceil(-1.2) = -1; joinNonEmpty record-field row = 'a-b' (literal mixed list refused at type-check "List elements must have the same type", as documented) …
    • A3 pass: record.amount / 100 with amount 1234.5 → 12.345 (record.amount * 2 → 2469); 7 / 2 → 3.
    • A4 pass: stock formulas materialize on GET — showcase_project Dagtz2SN… budget 90000, spent 88000, budget_remaining 2000 (also 600000/420000 → 180000); showcase_field_zoo f_formula 315 / 3.5 …
    • A5 pass: PUT /api/v1/meta/object/qaformula_r3bad?package=… (active, sharingModel private, bad_f = sqrt(4)) → 422 code INVALID_METADATA, issues[0] rule expression-invalid, where "object 'qaformula_r3bad' · field 'bad_f' expression" …
    • N0 pass: the harness resolved dist (path above), not src.
    • N1 pass: today() returned UTC midnight of the zone's day, no wall-clock component (A1).
    • N2 pass: the unregistered-function save was refused at the active door; nothing saved 2xx.

    cli.scaffold-console-first-paint rev 7 — PASS

    • A0 pass: npx os validate in the untouched scaffold → VALIDATE_EXIT=0, "✓ Validation passed (160ms)", "Data: 1 Objects 2 Fields". (One ⚠ warning printed — see off-clause probes; exit 0, not a refusal.)
    • A1 pass: B2 (os dev --ui) GET /_console/ → 200 text/html 19151 bytes (title ObjectOS, #root, module script assets/index-DqtqClJh.js); browser: 200, lands /_console/login …
    • A2 pass: B1 (npm run dev, bare objectstack dev -p 42211, no --ui) GET /_console/ → 200 text/html 19151 bytes; B2 → 200 19151 bytes; the two HTML bodies are identical except the per-response CSP nonce (same asset hash) …
    • A3 pass: newcomer check on B1 — form sign-in with the banner's seeded admin (get-session admin@objectos.ai) → home screenshot "Working late, Dev Admin." with "Your apps 0" + "Add app" (blank scaffold ships no app; /api/v1/meta/app → [setup, account]) …
    • N0 pass (not observed): console served on the fresh scaffold.
    • N1 pass (not observed): the two invocations agree.
    • N2 pass (not observed): dev forwards no --no-ui; console default-on under bare dev.
    • N3 pass (not observed): validate exit 0 on the pristine scaffold.
    • N4 pass (not observed): 200 painted a real login card (screenshot), not a white screen.

    i18n.notification-localized-and-clears rev 6 — FAIL

    • A0 pass: admin PATCH showcase_task Z3eDNat1tcJkDWV4 ("Design system") assignee → r4.zh@example.com (200). zh recipient's bell → popover "消息中心", tab "通知 1": screenshot shows the entry "New task assigned: Design system" / "You have been assigned "Design system"." / "21秒钟 …
    • A1 FAIL (re-judged by the orchestrator from the runner's evidence and its own two fresh-load reproductions): the click-through lands on /_console/apps/com.example.showcase/showcase_task/record/ID; breadcrumb, object label, path stages, actions, highlight, section and field labels are all zh (任务, 待规划…已完成, 标记为完成, 项目/负责人, 概览/排期), but the page is mixed-language: the record:alert callout reads "Awaiting review / This task is in review — confirm the work before marking it done." in English (R-2)
    • A2 pass: network trace of the click: POST /api/v1/notifications/read {"ids":["eUBhvnHx7RoM2qFH"]} → 200 {success:true,data:{readCount:1}} on the live server; server unreadCount (GET /api/v1/notifications, in-page fetch) 1 before → 0 after.
    • A3 pass: after a full page reload, GET /api/v1/notifications → unreadCount 0, the row read:true (createdAt 04:53:59.009Z, no newer rows).
    • A4 pass: the same task reassigned to the en control (200); en recipient (form sign-in, get-session r4.en@example.com, English console) bell → "Inbox", tab "Notifications 1": entry "New task assigned: Design system" / "You have been assigned "Design system"." / "14 seco …
    • N0 pass: mark-as-read answered 200 on the served Hono route (not 404/405).
    • N1 pass: no bug filed for the English title on the zh session — it is the contract (inline title, no template).
    • N2 pass: PUT /api/v1/meta/translation/r4_notif_zh {name, locale:'zh-CN', objects.showcase_task.label, notifications:{…}} → 422 INVALID_METADATA "Unrecognized key(s) on this translation: notifications …

    i18n.strict-translation-key-rejection rev 5 — PASS

    • A0 pass: every variant refused at the item door with 422 INVALID_METADATA; every key variant is unrecognized_keys naming the surface and echoing the key; locale variants invalid_format at path locale. Raw output /tmp/qa-w4c3b2/R6/i18n/item-door.out.
    • A1 pass: both bundle functions throw for all 12 with equivalent content (bundle path prefixed zh-CN, surface "this locale of the translation bundle"); valid control returns at both. root.defineTranslation is undefined, as the step warns (system subpath used) …
    • A2 pass: near-miss keys get did-you-mean — field helpText → help; widget label → title; object-level probe labell → label.
    • A3 pass: retired keys carry the prescriptions in the table (plural dashboards, nested navigation path, ADR-0049 removal version for validationMessages, top-level locale for _meta, no-replacement wording for errors).
    • A4 pass: before the item existed, every read-back after a rejection was 404. After the corrected item existed (label 任务(QA)), each of the 12 variants re-sent with label 任务(改) returned 422 and read-back still showed 任务(QA) / help 帮助(QA) / locale zh-CN.
    • A5 pass: corrected save 200 (seq 1) stores objects.showcase_task.label 任务(QA), fields.title.label 标题(QA), help 帮助(QA), widget title 任务总数(QA). zh-CN browser context: task record header badge "任务(QA)", New dialog title "新建任务(QA)" …
    • N0 pass: no variant got a 2xx at the item door; no bundle call returned for a variant.
    • N1 pass: no rejection is bare — every one names its surface and echoes the key (nothing PARTIAL).

    identity-auth.session-list-revoke rev 3 — PASS

    • A0 pass: GET /auth/list-sessions as A (device-1 bearer) → 200, 2 rows, both user usr_showcase_phone_demo (QA-device-1, QA-device-2); GET /data/sys_session as A → 200, 2 rows, 2 with revoked_at null, user_ids = {usr_showcase_phone_demo} only …
    • A1 pass: screenshot of /_console/apps/com.objectstack.account/sys_session/view/mine as device-1 shows "My Sessions · 2", rows QA-device-2 and QA-device-1 with IP 127.0.0.1, Created At, Expires At columns (plus last activity, active org) …
    • A2 pass: POST /auth/revoke-session {token: device-2 token from list-sessions} as device-1 → 200 {"status":true}; device-2 next GET /data/sys_session → 401 UNAUTHENTICATED, list-sessions → 401, its browser reload redirected to /_console/login …
    • A3 pass: with A holding device-1 + device-3 (API, UA node) + device-4 (browser), clicked list-toolbar "Sign out other devices" in device-1's console → confirm dialog ("…Your current session will remain active.") → network POST /api/v1/actions/sys_session/revoke_my_othe …
    • A4 pass: admin Setup → Sessions (all_sessions) screenshot "All · 4": live rows for Dev Admin ×2, Mei Phone (demo) QA-device-1, Ada Auditor (demo) — A and B both present, User column shown, no revoked rows …
    • A5 pass: PATCH /data/sys_session/{device-1 id} → 405 OBJECT_API_METHOD_NOT_ALLOWED, DELETE → 405, POST /data/sys_session → 405 — same for A and for admin (allowed: get,list,aggregate,export); device-1 still 200 afterwards.
    • N0 pass (not observed): A's reads never contained B's rows (list-sessions, data list, filter user_id=B → 0, GET B's id → 404).
    • N1 pass (not observed): revoke-session killed device-2 only; device-1 stayed 200.
    • N2 pass (not observed): revoke-other-sessions left the caller alive and every other A session 401.
    • N3 pass (not observed): revoked sessions refused on the very next request (401), no expiry wait.

    identity-auth.api-key-ui-lifecycle rev 5 — PASS

    • A0 pass: on /_console/apps/com.objectstack.account/developer/integrations typed "qa-r1-key", Generate key → confirm alertdialog ('Create the API key "qa-r1-key"? … It is shown ONCE.' Cancel / Create key) → Create key → network POST /api/v1/keys {"name":"qa-r1-key"} 201 …
    • A1 pass: GET /data/sys_session with x-api-key RAW (no cookie/bearer) → 200, 1 row, user_id set = {usr_showcase_phone_demo}, row-id set identical to the owner's own session read (1 row); admin session read of the same route → 4 rows across 3 users (admin, phone.demo …
    • A2 pass: mine view row menu → "Revoke API Key" → confirm → network POST /api/v1/actions/sys_api_key/revoke_api_key 200, record revoked:true; very next x-api-key GET /data/sys_session → 403, error.code API_KEY_REVOKED, body has no records.
    • A3 pass: row menu now offers "Restore API Key" → confirm → POST /api/v1/actions/sys_api_key/restore_api_key 200 (revoked:false); next x-api-key GET → 200 with 1 row.
    • A4 pass: as auditor.demo, mine view screenshot shows "You have no API keys yet"; GET /data/sys_api_key filtered user_id=self → 0 rows (KID absent); unfiltered list → 0 rows; GET /data/sys_api_key/{KID} → 404 RECORD_NOT_FOUND …
    • A5 pass: screenshots — show-once dialog "Your new API key — Copy this now — for your security it will not be shown again." with the copyable osk_… secret + Copy button; re-opened My Keys list shows the single row with Prefix osk_0ZtdGGFN only (no secret).
    • N0 pass (not observed): raw secret never returned after mint (get-by-id, list, select=key, list DOM).
    • N1 pass (not observed): post-revoke answer was 403 API_KEY_REVOKED, not 200 / generic 401 / other code.
    • N2 pass (not observed): key read equals the owner's RLS view (1 row) vs admin's 4.
    • N3 pass (not observed): the second member's mine view / reads never listed the owner's key.

    identity-auth.self-service-profile-password rev 3 — PASS

    • A0 pass: filled #profile-name "Mei Phone QA-R1" → Save Changes → network POST /api/v1/auth/update-user {"name":"Mei Phone QA-R1"} 200 {"status":true}; GET /auth/get-session → name "Mei Phone QA-R1" …
    • A1 pass: setInputFiles on [data-testid=profile-avatar-file] (16×16 PNG, 85 B) → POST /api/v1/storage/upload/presigned 200 (uploadUrl /api/v1/storage/_local/raw/… …
    • A2 pass: [data-testid=profile-avatar-remove-btn] → POST /auth/update-user {"image":null} 200; get-session image null; no an img element left, screenshot shows initials "MP" fallback and the Upload button.
    • A3 pass: Change Password card with correct current "showcase123" + new → POST /auth/change-password 200 (user body, "Password changed." shown); sign-out 200; sign-in with NEW → 200; sign-in with OLD → 401 INVALID_EMAIL_OR_PASSWORD.
    • A4 pass: same card with wrong current password → POST /auth/change-password 400 {"code":"INVALID_PASSWORD"}; subsequent sign-in with the old password → 200 (credential unchanged).
    • A5 pass: before: sign-in for qa.r1.sso → 401, sys_account rows for the user = [] ; as that user the card renders "Set Local Password — You signed in via single sign-on…" with Password / Confirm password and NO #current-password field (GET /auth/list-accounts → []) …
    • N0 pass (not observed): name persisted across reload and in get-session.
    • N1 pass (not observed): avatar stored as a committed storage object URL, not data:.
    • N2 pass (not observed): wrong current password refused 400 INVALID_PASSWORD (also empty current → 400).
    • N3 pass (not observed): passwordless user offered set-initial with no current-password field.

    identity-auth.org-membership-team-management rev 6 — PASS

    • A0 pass: Setup → nav "Organization" (role link click) → /_console/apps/com.objectstack.setup/sys_organization/record/org_mvyqz5nb0d0g6h9x — record page, not the list; URL id = GET /auth/organization/get-active-member organizationId (200 …
    • A1 pass: forger-independent gate = POST /auth/organization/invite-member as phone.demo: before 403 YOU_ARE_NOT_ALLOWED_TO_INVITE_USERS_TO_THIS_ORGANIZATION; update-member-role {memberId mem_showcase_usr_showcase_phone_demo, role admin} 200 …
    • A2 pass: update-member-role role "guest" → 400 ROLE_NOT_FOUND; "contributor" → 400 ROLE_NOT_FOUND; permission-set name "showcase_member_default" → 400 ROLE_NOT_FOUND; invite-member role guest → 400 ROLE_NOT_FOUND; afterwards sys_member roles = [owner, member, member …
    • A3 pass: POST /auth/organization/update {data:{name:"QA R1 Renamed Org"}, organizationId} 200; get-full-organization name "Default Organization" → "QA R1 Renamed Org"; record page title and breadcrumb read "QA R1 Renamed Org" (screenshot) …
    • A4 pass: target2 before: get-full-organization 200, set-active 200; admin remove-member {memberIdOrEmail: target2 member id} 200; target2 old session → 401; fresh sign-in 200 …
    • A5 pass: create-team {name "QA R1 Team"} 200; add-team-member for usr_showcase_phone_demo 200 and usr_showcase_auditor_demo 200; GET /data/sys_team_member filtered on the team → 2 rows (team_id, user_id) = (2owOl…, auditor), (2owOl…, phone) …
    • A6 pass: as auditor.demo (member): update-member-role → 403 YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_MEMBER (also self→owner 403), remove-member → 403 YOU_ARE_NOT_ALLOWED_TO_DELETE_THIS_MEMBER, update → 403 YOU_ARE_NOT_ALLOWED_TO_UPDATE_THIS_ORGANIZATION …
    • N0 pass (not observed): every forged endpoint refused server-side.
    • N1 pass (not observed): removal changed authorization (403 on fresh sign-in).
    • N2 pass (not observed): no off-vocabulary role stored; role changes flipped the invite gate both ways.
    • N3 pass (not observed): nav resolved {current_org_id} to the record page.

    identity-auth.first-run-owner-bootstrap rev 5 — PASS

    • A0 pass: anonymous GET /api/v1/auth/bootstrap-status (no credentials) on B1 → 200 {"hasOwner":false} before the wizard (also the console's own two probes on /_console/setup read {"hasOwner":false}); after the wizard → 200 {"hasOwner":true} (anonymous, re-read twice) …
    • A1 pass: on B1 (OS_DISABLE_SIGNUP=true, 0 human users) the wizard's POST /api/v1/auth/sign-up/email {"email":"owner@qa-r2.test",…,"name":"QA Owner"} → 200 with token + user id FahOR2Ho…; in-page GET /api/v1/auth/get-session → user owner@qa-r2.test …
    • A2 pass: wizard org field "华宁测试组织" (CJK-only) → network shows POST /auth/organization/update {"organizationId":"org_mvyr4jizo6bxho2c","data":{"name":"华宁测试组织"}} (no slug key) → 200; no organization/create request …
    • A3 pass: exit is document navigation — request log shows DOC-NAV GET /_console/ twice after set-active (no SPA push), final URL /_console/home; screenshot: home "Working late, QA Owner.", "Your apps 1" with Showcase tile …
    • A4 pass: door 1 (B1, OS_DISABLE_SIGNUP, owner exists): uninvited forge uninvited-r2@qa-r2.test → 403 SELF_REGISTRATION_CLOSED (audience gate, recorded not scored) …
    • A5 pass: B1 post-bootstrap, fresh anonymous context → /_console/setup lands /_console/login?redirect=%2Fsetup; screenshot shows the "Welcome back / Sign in" card, no wizard (#orgName count 0) …
    • N0 pass (not observed): wizard never rendered on an owner-holding boot (B1 post-bootstrap anon + owner, B3 anon).
    • N1 pass (not observed): no post-bootstrap anonymous sign-up succeeded on any boot (3 boots, invited and uninvited).
    • N2 pass (not observed): exit was full-document, landed console is the owner's.
    • N3 pass (not observed): CJK-only name applied (name 华宁测试组织, slug kept "default").
    • N4 pass (not observed): no second org; no organization/create on the wire.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbWJDYbbtH6dhJNoboN

    Per-clause verdicts, part 2 of 2 (items 14–27)

    Clause ids: A# = acceptance[#], N# = negative[#], zero-based. One line of text evidence each; the full per-runner evidence (requests, response strings, row values) was kept in the run environment.

    identity-auth.self-signup-gate rev 7 — PASS

    • A0 pass: GET /api/v1/auth/config — S1 emailPassword {enabled:true, disableSignUp:false, requireEmailVerification:false}, features.audiencePosture "invite_only"; S2 emailPassword.disableSignUp true, audiencePosture "invite_only" …
    • A1 pass: S1 POST /api/v1/auth/sign-up/email {email:"stranger-r2@qa-r2.test",…} (uninvited) → 403 {"code":"SELF_REGISTRATION_CLOSED","message":"Self-registration is closed (audience posture invite_only) …
    • A2 pass: S1 admin (get-session admin@objectos.ai) POST /auth/organization/invite-member {email:"invitee-r2@qa-r2.test",role:"member"} → 200 status pending id FTebc8Fd…; invitee POST /auth/sign-up/email → 200 with token …
    • A3 pass: S2 fresh context /_console/register?redirect=%2Fapps%2Fcom.example.showcase → main-frame navigations register → register → /_console/login?redirect=%2Fapps%2Fcom.example.showcase (redirect preserved) …
    • A4 pass: S2 uninvited stranger-off-r2@qa-r2.test → 403 SELF_REGISTRATION_CLOSED (audience gate — recorded, proves nothing about the toggle); admin invite-member invitee-off-r2@qa-r2.test → 200 pending …
    • N0 pass (not observed): uninvited refusal is a loud 403 code, no synthetic 200.
    • N1 pass (not observed): no row created for any uninvited sign-up (S1, S2).
    • N2 pass (not observed): endpoint refuses on S2 (400 for invited) alongside the UI bounce.
    • N3 pass (not observed): invited registrant admitted on S1.
    • N4 pass (not observed): no generic Sign-up link / no form for an uninvited visitor on S1; form offered for the /accept-invitation redirect. (Zero-owner leg of N4 not re-driven here — the zero-owner /_console/setup wizard was observed under identity-auth.first-run-owner-bootstrap.)

    integration-system.webhook-lifecycle rev 13 — PASS

    • A0 pass: fresh B1 boot — GET /api/v1/data/sys_webhook → 200 {records:[], total:0} (also $filter {name:'showcase_task_changed'} → 0). GET /meta/webhook/showcase_task_changed → 200 declaration (isActive:false, _provenance package) …
    • A1 pass: in-org scratch webhook r4_scratch_hook (POST /api/v1/data/sys_webhook as admin → 201, organization_id = Default Org, triggers [create,update,delete], method 'post', definition_json, signing_secret, headers_secret) …
    • A2 pass (on this run's own fixture, B2 — see note): flow update_record multi:true (3 rows matched, acted 3) and delete_record multi:true (acted 3), autolaunched flows created over POST /api/v1/automation and fired with POST /api/v1/automation/:name/trigger …
    • A3 pass: receiver headers carried the authored custom header X-R4-Custom: hello-r4 (from headers_secret) and X-Objectstack-Signature sha256=… which re-computes as HMAC-SHA256(body, 'r4-signing-secret') for all 3 hits; timeoutMs 2000 stored as timeout_ms 2000 …
    • A4 pass: terminal row a29e550d (dead, attempts 4, response_code 410 "HTTP 410") → POST /api/v1/webhooks/redeliver {deliveryId} as admin → 200 {success:true,data:{id:'a29e550d…',status:'pending'}}; receiver re-hit with X-Objectstack-Signature sha256=d21ef21c…b027b01 …
    • A5 pass: scratch compile (control build exit 0) with showcase_task_changed triggers ['create','undelete'] → exit 2, Zod invalid_value at path triggers[1] "Invalid option: expected one of "create"|"update"|"delete"|"bulk_update"|"bulk_delete"" …
    • A6 pass: after stopping B1 and rebooting the same DB (B1'), sys_metadata_activation row unchanged (webhook/showcase_task_changed, active 1, updated_at from before reboot) …
    • N0 pass: receiver killed → new delivery row a29e550d status pending, attempts 2→3, error "fetch failed", next_retry_at set (schedule ~1s/10s/60s); receiver back answering 410 → next attempt → status dead, attempts 4, response_code 410, error "HTTP 410" …
    • N1 pass: the data door refuses an unknown trigger (POST sys_webhook triggers ['create','undelete'] → 400 VALIDATION_FAILED "Triggers: "undelete" is not one of …") …
    • N2 pass: scratch compile with webhooks: [...] on showcase_status_api → exit 2 "connector.webhooks was removed in @objectstack/spec 17 (ADR-0049 enforce-or-remove) … Delete the key …" …

    integration-system.job-scheduled-run rev 6 — PASS

    • A0 pass: interval r4_interval (intervalMs 20000) → 10 sys_job_run rows 04:44:31…04:47:31 at 20 s spacing, status success, trigger schedule, plus 10 showcase_account side-effect rows "R4JOB interval TS" over GET /api/v1/data/showcase_account …
    • A1 pass: sys_job rows over GET /api/v1/data/sys_job are keyed by name with adapter-minted ids (e.g. job_031d49d6… name r4_interval, schedule_type interval, schedule_expression 20000; r4_cron_tz has timezone Asia/Shanghai) …
    • A2 pass: r4_fail_retry (maxRetries 2, backoffMs 1000, multiplier 2) → run rows attempt 1 at 04:45:55.579 (ended .582), attempt 2 at 04:45:56.593 (+1.01 s), attempt 3 at 04:45:58.604 (+2.00 s), each status failed …
    • A3 pass: r4_timeout (timeoutMs 1000, handler sleeps 4 s) → run row status timeout, duration 1001 ms, error 'Job "r4_timeout" timed out after 1000ms'. r4_timeout_retry (timeoutMs 1000, maxRetries 1, backoffMs 1500) → attempt 1 timeout ended 04:46:06.600 …
    • A4 pass: J1 default level: "WARN [AppPlugin] job handler not found in bundle.functions — skipping. … {"appId":"com.example.showcase","job":"r4_no_handler","handler":"r4DoesNotExist"}" in the boot diagnostics …
    • A5 pass: compile with id: 'x' on showcase_health_sweep → exit 2, unrecognized_keys [id], message "job.id was removed in @objectstack/spec 17.0.0 (ADR-0049) … name IS the job's identity everywhere … This edit left os migrate meta with the protocol-16.x conversio …
    • N0 pass: both declared-but-never-run jobs are reported by their skip line (WARN for missing handler at default level; DEBUG for enabled:false); no job here went silent.
    • N1 pass: no runtime-created job saved — PUT 403 NOT_CREATABLE, POST 405, POST /api/v1/data/sys_job 405 OBJECT_API_METHOD_NOT_ALLOWED (allowed get/list/aggregate/search/export); meta read 404.

    integration-system.notify-inbox-delivery rev 7 — PASS

    • A0 pass: before, assignee GET /api/v1/notifications → {notifications:[], unreadCount:0}. Admin PATCH /api/v1/data/showcase_task/4dFxCdhffgKn_ePm {assignee:'r4.assignee@example.com'} (was admin@objectos.ai) → 200 …
    • A1 pass: third member's authenticated listing at the same instant → {notifications:[], unreadCount:0}; third's GET /api/v1/data/sys_inbox_message → 0 records; GET /api/v1/notifications/GDhKsyXozuS82PB1 → 404 ENDPOINT_NOT_FOUND (no per-id read door …
    • A2 pass: second reassignment gave the assignee 2 unread. POST /notifications/read {ids:['GDhKsyXozuS82PB1']} → 200 readCount 1; ?read=false → only D_wsM5qDh6LQzNCN, unreadCount 1; POST /notifications/read/all → 200 readCount 1; ?read=false → 0 rows, unreadCount 0 …
    • A3 pass: anonymous GET /api/v1/notifications on stock N1 → 401 UNAUTHENTICATED (POST /read and /read/all anonymous → 401). N2 (no MessagingServicePlugin): anonymous GET → 401; admin (get-session proven) GET /notifications, POST /notifications/read …
    • A4 pass: runtime flow r4_push_probe (POST /api/v1/automation, notify node channels ['push'], recipient the assignee's email) fired by POST /api/v1/automation/r4_push_probe/trigger → 200, notify node selected 1 acted 0 …
    • N0 pass: no notify step reported success with an empty recipient listing — every reassignment to a real user landed in that user's listing; a reassignment to an address no user holds failed loudly (ERROR "Trigger-fired run of flow 'showcase_task_assigned_notify' failed …
    • N1 pass: third member never saw the assignee's notification (listing, data API, per-id path); third's POST /notifications/read {ids:[assignee's id]} → 200 readCount 0, no receipt row created for the third member, and the assignee's row stayed unread.

    platform-core.settings-hub-roundtrip rev 7 — PASS

    • A0 pass: before PUT, GET /api/settings/localization timezone = {value:"UTC", source:"tenant"} (dev seed, as steps[1] says); PUT {timezone:"Asia/Tokyo"} → 200, values.timezone {value:"Asia/Tokyo", source:"tenant", cascadeChain [tenant Asia/Tokyo effective …
    • A1 pass: GET /api/v1/auth/me/localization before PUT {"timezone":"UTC","locale":"en-US"} → after PUT {"timezone":"Asia/Tokyo"} (same session and a fresh sign-in both). Effect also observed on the env boot: me/localization → "Europe/Paris" with the env pin …
    • A2 pass: GET /api/v1/data/sys_setting_audit?filter={namespace:localization,key:timezone} → 2 rows; the PUT's row: scope tenant, action "set", source "api", actor_id I2aOVFUz… (admin), old_hash sha256:6810…, new_hash sha256:dd97… …
    • A3 pass: Settings → Localization in console, default_country before save: no source indicator (source default per API); typed "Japan (JP)" in the datalist field and pressed "Save changes" → wire PUT /api/settings/localization {"default_country":"JP"} 200 …
    • A4 pass: env boot: GET localization timezone {value:"Europe/Paris", source:"env", locked:true, lockedReason:"Set via env: OS_LOCALIZATION_TIMEZONE", cascadeChain [env, locked]} …
    • A5 pass: env boot console Settings → Localization: Default timezone carries a "Locked by env" badge with lock icon; input shows "(UTC+01/+02) Paris" greyed; Playwright isDisabled() = true. Mail page: Password field shows "Locked by env", input disabled.
    • A6 pass: POST /api/settings/mail/test {} with stored default (provider smtp, no host) → 400 SETTINGS_ACTION_FAILED, details {ok:false, message:"SMTP host is required — nothing was sent."}; with provider "log" on the form → 400 SETTINGS_ACTION_FAILED …
    • A7 pass: after PUT mail {smtp_password:"S3cret-orig-R5"} and {api_key:"re_R5_apikey_orig"}: sys_secret has 2 rows, ids sec_3cd5bd4c… (mail.smtp_password) and sec_3e2ce921… (mail.api_key), alg aes-256-gcm, kms_key_id local:v1, ciphertext "v2:…" (59/63 chars …
    • A8 pass: GET /api/settings/mail: smtp_password (type password, implicit) and api_key (explicit encrypted:true) both value "••••••••" (code points 2022 ×8), cascadeChain [global "••••••••" effective, default null] — the two-entry global chain walked …
    • A9 pass: env boot GET mail smtp_password {value:"••••••••", source:"env", locked:true, lockedReason:"Set via env: OS_MAIL_SMTP_PASSWORD", cascadeChain [env "••••••••" locked]}; body lacks the env plaintext; PUT {smtp_password:"Other-R5"} → 409 SETTINGS_LOCKED …
    • A10 pass: PUT {smtp_password:MASK, api_key:MASK} → 200 {values:{}}; PUT {values:{smtp_password:{value:MASK}, api_key:{value:MASK}}} → 200 {values:{}}; after each, the sys_secret inventory (id, ciphertext …
    • A11 pass: anonymous GET /api/settings/localization → 401 {code:"UNAUTHENTICATED"}; anonymous GET /api/settings → 401 {code:"UNAUTHENTICATED"}; neither body carries a manifest or value.
    • A12 pass: GET /api/settings → 11 manifests (company, localization, auth, mail, sms, storage, ai, knowledge, feature_flags, lifecycle, branding); each GET /api/settings/:ns → 200 {manifest, values} with specifiers (company 16, localization 7, auth 43, mail 17, sms 15 …
    • N0 held: effect scored from /auth/me/localization, not the form.
    • N1 held: env-locked real-value PUTs both 409; the only 200 was the echoed mask.
    • N2 held: no plaintext in any GET/PUT body; secrets in sys_secret, not inline.
    • N3 held: masked keys present with value "••••••••"; unset secret present as null.
    • N4 held: echoed mask did not overwrite (inventory unchanged, consumer still original plaintext).
    • N5 held: in-process consumer read real plaintext.
    • N6 held: no ok:true without a real delivery.
    • N7 held: anonymous list 401.

    platform-core.package-lifecycle-enable-disable rev 3 — PASS

    • A0 pass: before disable GET /api/v1/data/r5p_widget → 200 total 3; /meta/object lists r5p_widget; /meta/app?id=r5p_app → 1 item, nav ["r5p_widget"]; /meta/view/r5p_widget.all_widgets → 200. PATCH /packages/com.qa.r5probe/disable → 200 {status:"disabled" …
    • A1 pass: PATCH …/enable → 200 {status:"installed", enabled:true}; /data/r5p_widget → 200 total 3; record n4kmQxdC… → 200 "alpha"; /meta/app?id=r5p_app nav ["r5p_widget"] back; view 200 …
    • A2 pass: DELETE /packages/com.qa.r5probe → 200 {registryRemoved:true, persisted.deletedCount:3 (object, view, app)}; afterwards /meta/object, /meta/view, /meta/app carry no r5p_ entry, /meta/_drafts none, /data/r5p_widget → 404 OBJECT_NOT_FOUND …
    • A3 pass: GET /packages/:id/commits: 0 before first publish, 1 after ("first publish"); after a second publish (draft adds field size, publish-drafts → published 1) → 2 (["add size","first publish"]): exactly +1.
    • A4 pass: /meta/object/r5p_widget/published before change: fields [title]; after the second publish: [title, size]; POST /packages/com.qa.r5probe/commits/cmt_5f116654…(add size)/revert → 200 {revertedCount:1, reverted:[{type:object, name:r5p_widget …
    • A5 pass: console home after disable: "Your apps 1" — only Showcase (R5 Probe App tile gone; before disable it read "Your apps 2 … R5 Probe App"). Stale deep-links captured before disable (the console canonicalises the app segment to the package id): /_console/apps/com. …
    • A6 pass: PATCH /packages/com.example.showcase/disable → 422 WRITABLE_PACKAGE_REQUIRED "[writable_package_required] Cannot disable package 'com.example.showcase': it is read-only…"; DELETE → 422 same code; same pair on com.objectstack.platform-objects → 422/422 …
    • A7 pass: row count before disable 3 == after re-enable 3 (titles alpha, beta, gamma; record n4kmQxdC… readable).
    • N0 held (no 200 while disabled). N1 held (no orphaned meta, package gone from list). N2 held (revert restores exactly). N3 held (422 on read-only).

    platform-core.notification-center rev 5 — PASS

    • A0 pass: server payload before any mark: 4 inbox rows → groups approval.requested|Approval requested ×3 unread 3, project.digest|Scheduled project digest ×1 unread 1 → unreadTopics 2 + approvals 3 = 5; rendered inbox-bell-badge = "5" …
    • A1 pass: popover screenshot shows three tabs; role=tab texts ["Notifications 2", "Approvals 3", "Activity feed"].
    • A2 pass: screenshot shows "Approval requested ×3" as one row with a chevron and "3 unread"; DOM: its button carries aria-expanded, pill text "×3" aria-label "3 notifications" …
    • A3 pass: clicked the group's "Mark read" → exactly one POST /api/v1/notifications/read body {"ids":["LABJb-XGSNYKHlYK","j_9DoDkbSM8bBzsi","yDyY0_TxPMt7Xu1J"]} → 200; no other POST; badge 5 → 4 (breakdown "1 unread topic + 3 pending approvals") …
    • A4 pass: "Mark all read" → one POST /api/v1/notifications/read/all body {} → 200; badge 4 → 3, breakdown "3 total · 0 unread topics + 3 pending approvals" (approvals portion unchanged).
    • A5 pass: Approvals tab panel text "3 pending approvals" + "View approvals" button, 0 list items (a count and a control, no request list); clicking it lands on /_console/apps/com.example.showcase/system/approvals …
    • A6 pass: after a fresh form sign-in and reload, badge "3" and breakdown "0 unread topics + 3 pending approvals"; GET /api/v1/notifications?view=mine shows all five then-present rows read:true (2 digest, 3 approval.requested) …
    • N0 held (badge counted topics). N1 held (one POST per group). N2 held (no keyed row reverted).

    platform-core.docs-portal-render rev 3 — PASS

    • A0 pass: /_console/docs (screenshot: two book cards) renders "Showcase Manual — 8 articles" (/docs/manual) and "Setup — com.objectstack.setup — 1 article" (/docs/com.objectstack.setup). Rendered trees: manual → showcase_index, showcase_tour_data, _ui, _automation …
    • A1 pass: opened "Tour · Security" from the BookSidebar → /_console/docs/manual/showcase_tour_security renders its body; on Showcase (showcase_index) the body link "Data" (href /_console/docs/showcase_tour_data …
    • A2 pass: navigation trace for /_console/docs/showcase_tour_ui: [/docs/showcase_tour_ui → /docs/manual/showcase_tour_ui], final page renders "Tour · UI"; /_console/docs/setup_overview → /_console/docs/com.objectstack.setup/setup_overview (implicit home book) …
    • A3 pass: /_console/apps/com.example.showcase/docs lands at /_console/apps/com.example.showcase/docs/manual/showcase_index inside the Showcase app shell (top bar "Showcase", app sidebar; screenshot) …
    • A4 pass: member's Help menu (button aria-label "Help & Documentation", screenshot) offers ["All documentation", "Online documentation", "About"]; All documentation → /_console/docs. Member rendered tree (2 books …
    • A5 pass: index, book landing (redirects to the book's first doc), reader, and app-scoped index each rendered content (screenshots); no blank region; the named empty state was seen on probes ("Documentation not found — No document named … is installed.").
    • N0 held: member tree not wider than the member API subset (equal). N1 held: no entry 401/403. N2 held: flat URL redirected. N3 held: screenshot-first; nothing read empty.

    platform-core.home-admin-cluster-links rev 5 — FAIL

    • A0 pass: adminItems at this SHA (ui/packages/app-shell/src/layout/UnifiedSidebar.tsx) holds 8 entries: sys-settings, sys-apps, sys-marketplace, sys-datasources, sys-users, sys-orgs, sys-roles, sys-config …
    • A1 pass: trace from the canonical prefix: /apps/com.objectstack.setup/system → /apps/com.objectstack.setup/system/settings (one hop; from the /apps/setup alias the only extra step is the app-id canonicalisation). SettingsHub lists 11 entries (localization, company …
    • A2 FAIL (stale spec): users → /apps/com.objectstack.setup/sys_user and organizations → …/sys_organization hold (one hop each, pages render). roles and positions land on /_console/studio/~all/metadata/position?scope=environment (Studio "Position" list) …
    • A3 pass: member /home (screenshot): no sidebar, no Setup link, no admin words, no link containing setup/system/metadata; Help menu = ["All documentation", "Online documentation", "About"] …

    search.pinyin-flag-both-sides rev 6 — PASS

    • A0 pass (ON, POST /api/v1/data/OBJ/query {search}): showcase_contact "zhangwei" → 200 [张伟]; "zw" → 200 [张伟]; "张" → 200 [张伟]; showcase_account "huaning" → 200 [华宁科技]; "hnkj" → 200 [华宁科技] (also "wf"/"wangfang" → [王芳], "huaningkeji" account → [华宁科技]). DB: showcase_contact.__search for 张伟 = "zhangwei zw" …
    • A1 pass: contrast on showcase_contact (张伟/王芳/李雷 all carry company 华宁科技, a non-name CJK field): "hnkj" → 200 n=0 and "huaningkeji" → 200 n=0 on ON, while the same terms hit the account whose NAME is 华宁科技 — company does not feed the companion …
    • A2 pass (OFF, after flagged restart): showcase_contact "zw" → 200 [] , "wf" → 200 [], showcase_account "hnkj" → 200 []; "张" → 200 [张伟] (source column); as the clause predicts "zhangwei" → [张伟] and "wangfang" → [王芳] via email, "huaning" account → [华宁科技] via website/billing_email; all 200 …
    • A3 pass: roster diff — ON "Plugins: 54 loaded", OFF "Plugins: 53 loaded"; sorted roster diff is exactly one entry, PinyinSearchPlugin present on ON and missing on OFF …
    • A4 pass: first-boot recall without manual rebuild — the A0 queries ran on a fresh first boot; ON log: [pinyin-search] companion reconcile walked an object {"object":"showcase_contact","mode":"full","scanned":32,"pages":1,"updated":3} …
    • N0 pass (not observed): no 500/error on any latin search with the flag off (all 200).
    • N1 pass (not observed): "zw" and "zhangwei" both hit on ON.

    search.console-global-search rev 6 — PASS

    • A0 pass: on /_console/apps/com.example.showcase — Ctrl+K → overlay:command-palette visible (1 overlay), URL gains ?palette=1 (screenshot: palette with "Recently viewed" + Objects); Ctrl+K again → closes (accelerator toggles by design, not scored); Meta+K → opens …
    • A1 pass: typed "zhangwei" → wire GET /api/v1/search?q=zhangwei&limit=24&objects=showcase_preference,…,showcase_contact,… → 200; no per-object find fanout observed. Global endpoint served (plugin present).
    • A2 pass: /api/v1/search responses — "zhangwei" → [showcase_contact:张伟]; "张伟" → [showcase_contact:张伟]; "huaning" → [showcase_account:华宁科技, showcase_contact:张伟, 李雷, 王芳]. Screenshot "huaning": heading "Account (Success Overlay)" over 华宁科技 …
    • A3 pass: fresh palette (?palette=1), typed "zhangwei" (keyboard), selected item = "张伟 zhangwei@huaning.example" (cmdk data-selected), Enter → URL /_console/apps/com.example.showcase/showcase_contact/record/mgXxT-QggHidSwKl (package-id address), overlay gone …
    • A4 pass: after visiting 王芳 and 华宁科技 record pages, Ctrl+K with empty input — screenshot shows "Recently viewed" group (华宁科技 Account, 王芳 Contact) above Objects; 0 /api/v1/search requests fired between open and the screenshot; typing the single character "张" → 0 requests.
    • A5 pass: GET /api/v1/search?q=INV-1003 — member → 200 {"hits":[],"totalHits":0,"totalObjects":23} (no INV-1003, no count leak; invoice line "INV-1003 · Widget B units" also absent); admin → 200 totalHits 2 [showcase_invoice:INV-1003 …
    • A6 pass: /_console/apps/com.example.showcase/search?q=huaning → wire GET /api/v1/search?q=huaning&limit=60&objects=… 200; screenshot "4 results for "huaning"", groups "Account (Success Overlay) 1" and "Contact 3" …
    • N0 pass (not observed): member saw no INV-1003 hit or count.
    • N1 pass (not observed): hits grouped under object headings.
    • N2 pass (not observed): empty input fired no request and showed recents.
    • N3 pass (not observed): Enter navigated (ref-targeted keyboard select).
    • N4 pass (honoured): deny side run as the contributor-bound member, not admin.

    ux-conventions.write-feedback rev 9 — FAIL

    • A0 FAIL (one row): 14 of 15 landed writes gave visible feedback on the surface that started them (rows 0–7, 9–11, M0, edit form; kanban by card position + live region). Row 8 Studio autosave: write landed (PUT 200 draft seq 2, and again seq 5 on a second fresh load) …
    • A1 FAIL (same row): record-level rows name record/item/count — Task "QA R6 create probe" created, 1 row saved, Deleted 2 Task records, Warehouse schema marked done., invitee email, Approved "EXP-2001", 2 created/Imported 2 rows. …
    • A2 pass: Mark Done declared the template record.title (default 'Task') + "marked done." → shown Warehouse schema marked done. (exact interpolation). Invite User: declared successMessage "Invitation sent to" + result.email is the fallback …
    • A3 pass: (a) required-empty submit → no write request left the browser (0 POSTs), field errors Title is required / Project is required, no toast (console-block shape) …
    • A4 pass: no-op on Grid inline editors (Estimate number editor and Priority select opened, Escape, click away) → 0 non-GET requests, no "modified" / "Save All" text in main.
    • A5 pass: Import as job, create mode (imp_mvyse7i886k8nujp, 2 created) → Undo import (native confirm accepted) → POST …/undo 200 deleted 2 → DB: both rows gone; history row reads Undone. Update mode matching Title (imp_mvysg6uw7w80nzm7 …
    • N0 pass: refused writes (required-empty, invalid_transition 400, member 403) never showed a success toast.
    • N1 pass: same evidence as A4.
    • N2 pass: no success claim without a landed write anywhere (every success toast paired with a 2xx; the import with an unresolvable lookup showed Import failed · 0 imported 1 skipped · Row 1: Project: No matching record for "No Such Project" + warning toast …

    ux-conventions.disabled-control-reason rev 4 — FAIL

    • A0 FAIL: pass for Archive, Publish, validation editor (tooltips) and import Next (adjacent banner). FAIL for (a) the flow node inspector's disabled inputs/Remove node — hover shows nothing and nothing adjacent; (b) the field inspector's disabled Remove "Priority" …
    • A1 FAIL: pass for Archive, Publish, validation editor, import Next (focusable wrapper + aria-describedby). FAIL for every disabled control of the flow node inspector and of the field inspector (display-patch mode): not in tab order, no accessible description …
    • A2 FAIL (one surface): specific reasons — Archive "Mark the task done first." (author-declared, not the generic fallback), Publish/validation "Read-only package — …", import "Can't continue — required field(s) not mapped: Project (project), Status (status)…" …
    • N0 pass: Archive on a done task (App wireframes) is enabled with no aria-describedby, no wrapper (parent tabIndex −1), no tooltip on hover. The enabled automation toggle carries no read-only reason.
    • N1 recorded: member list/grid remove selection, bulk delete and inline edit (absent from DOM), rather than rendering them disabled; Mark Done hidden on a done task.

    ux-conventions.labels-over-machine-names rev 4 — PASS

    • A0 pass: every sampled item's primary text is its label (table above); no row rendered the name while a distinct label exists.
    • A1 pass: Explain principal "Mei Phone (demo)" + "phone.demo@example.com" = sys_user name/email; audit Actor "Dev Admin" = sys_user name; Profile "Dev Admin"; record Owner/Updated by "Dev Admin" …
    • A2 pass: every machine name seen on a variant is beside its label and subordinate — small muted mono under/after the label (permission set, object row, Changes item, nav columns, related/trigger object, Explain principal id …
    • A3 pass: scan of 19 page/inspector text dumps (Access, Interfaces, Data + three field inspectors, two flows × every node inspector, task list, task record, audit log, Profile) plus the Explain result: no dotted Zod path …
    • N0 recorded: authoring finding above (审批节点「处理人 Value」应改为记录 lookup(现查 metadata 端点→只能手填);附 approver value 语义核实 + queue 未实现 #3508 in an app flow label). No variant rendered a name for want of a label.
    • N1 recorded: CEL expression editors / their lint ("unknown field no_such_field on qrsl_gadget") and the Advanced (JSON) panes use identifiers — developer/expression context, out of scope.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-warren · session_01JQwxbWJDYbbtH6dhJNoboN

    Close-out (RUNNER extraction obligation, checklist-test §5). Every FAIL has a disposition; probe findings that passed the filing gate are extracted with a QA-source: line.

    Extracted: #28982 · i18n.notification-localized-and-clears · A1
    Extracted: #28984 · ux-conventions.write-feedback · A0, A1
    Extracted: #28985 · ux-conventions.disabled-control-reason · A0, A1, A2
    Extracted: #28986 · ux-conventions.disabled-control-reason · A0, A1
    Extracted: #28579 · platform-core.home-admin-cluster-links · A2
    Extracted: #28987 · platform-core.package-lifecycle-enable-disable · observed beside the clauses
    Extracted: #28988 · platform-core.home-admin-cluster-links · observed beside the clauses
    Extracted: #28990 · access-security.permission-matrix-edit-loop · observed beside the clauses
    Extracted: #28992 · cli.scaffold-console-first-paint · observed beside the clauses
    Extracted: #28993 · i18n.strict-translation-key-rejection · observed beside the clauses
    Parked-on: #27377 · checklist-accuracy findings and fixture gaps listed in this record's body

    Dispositions: R-1 stale spec (re-point owed by #28579, which already lists the item; measured detail posted there). R-2, R-3, R-4 product defects. R-5 product defect, a regression from #28860.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions