Skip to content

QA run · release-18.2.0-manual-set (29/29) · 6679644a · 2026-10-25 · 25 PASS / 4 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN #25817

Open

Description

@objectstack-fleet

This is the QA run record for the 18.2.0 release sweep's manual non-P0 set (wave anchor #25807, card T3), for the Version Packages PR #25640. It was run with the checklist-test skill following docs/qa/platform-checklist/RUNNER.md.

The set follows the 18.1 precedent (#25479). It holds the since:v18.x items that carry no automated pin, plus the unpinned P1 items whose source[] cites files changed by the 14 Clause-②: yes changesets in #25640. Like #25479, the set was named by hand, not resolved by a single selector. Every id was resolved one at a time with node scripts/checklist-select.mjs ID --json, and all 29 came back runnable: none is blocked and none is planned. Every item has a verdict (29/29). None of the 29 carries an automated.ref, so every clause was driven live.

Environment fingerprint

  • Framework: 6679644a1a56b552d6864b125900221823ec78b3 (objectstack main head at start, 14:16Z). The tree was clean. pnpm install --frozen-lockfile and pnpm build --concurrency=2 passed 76/76. The tree is unreleased, so the CLI and health report 18.1.0.
  • Console: .objectui-sha = b41ed7f68956c8cfda21bc790548361af81b09ac, built with OBJECTUI_DEPS_BUILD_CMD='pnpm exec turbo run build --concurrency=2 --filter=@object-ui/console^...' pnpm objectui:build ("dist ready … from objectui@b41ed7f68956"). packages/console/dist/.objectui-sha equals the pin, so stale-console-bundle is ruled out for every console observation. A pin move is in flight (chore(console): move the objectui pin b41ed7f68956 → objectui main before the 18.2.0 cut (maintainer: bump first) #25810), and the maintainer directed this run to stay on b41ed7f68956.
  • App and boot: examples/app-showcase, booted with OS_PORT=PORT setsid pnpm -C examples/app-showcase exec objectstack dev --ui --seed-admin -p PORT -d file:SCRATCH/BOOT.db. Each runner had its own port range (41100–41499) and its own file DBs. Seed: --seed-admin (admin@objectos.ai) plus the showcase seed.
    • Scratch copies (tar, without node_modules, .objectstack or dist) were used for cli.fresh-install-migrate-apply-first (production os serve with OS_AUTH_SECRET/OS_SECRET_KEY), the connector-degraded twins, the capability shadow/malformed apps, and app-todo --preset minimal.
    • examples/app-showcase/.objectstack/installed-packages/ never existed.
  • Special switches: OS_AUTH_TWO_FACTOR=true for the two-factor items. OS_SEARCH_PINYIN_ENABLED=false for the pinyin OFF leg. OS_AUTOMATION_SCHEDULED_WORK_ENABLED=1 only on one approvals A9 candidate boot.
  • Browser: Playwright chromium via executablePath=/opt/pw-browsers/chromium, with its own context per persona and a form sign-in.
  • Execution: four runner agents worked in parallel (A: CLI/API/automation · B: identity/search/i18n · C: approvals/automation/formula/notify (mixed) · D: approvals/records/UX/i18n (browser)). git status stayed clean, and every server was stopped by process group.
  • Timings: environment prep took about 22 minutes for the cold tree: pnpm build 9 min, then the console build about 13 min, from 14:18Z to 14:40Z. In-run prep (boots, personas, scratch copies) was about 18 runner-minutes. Testing, probes included, was about 100 runner-minutes. Wall clock was 14:16Z to 15:29Z.

Scope and verdicts

item priority surface rev verdict
cli.fresh-install-migrate-apply-first P1 cli 1 PASS
access-security.capability-declaration-lifecycle P1 mixed 6 PASS
access-security.packaged-flow-write-door-parity P1 api 4 PASS
ai.mcp-run-action-exposure-gate P1 api 4 PASS
api-backend.aggregate-contract-matrix P1 api 4 PASS
api-backend.formula-stdlib-matrix P1 mixed 3 PASS
approvals.per-group-signoff P1 browser 9 PASS
approvals.quorum-m-of-n P1 browser 6 PASS
approvals.inbox-metadata-actions P1 browser 5 PASS
approvals.decision-action-matrix P1 mixed 8 PARTIAL (A9 blocked(fixture), knownGaps[0])
approvals.approver-resolution-matrix P1 api 6 PASS
automation.flow-run-step-nesting P1 mixed 7 PASS
automation.flow-node-type-matrix P1 mixed 9 PASS
automation.flow-error-handling P1 mixed 6 PASS
automation.trigger-status-contract P1 api 5 PARTIAL (A4 503 STORE_UNAVAILABLE arm blocked(fixture))
automation.packaged-flow-subflow-disable-refusal P1 api 8 PARTIAL (N1 blocked(fixture): a second packaged caller)
automation.packaged-flow-clone-contract P1 api 7 PASS
i18n.notification-localized-and-clears P1 browser 4 PASS
i18n.strict-translation-key-rejection P1 mixed 2 PASS
identity-auth.org-membership-team-management P1 mixed 5 PASS
identity-auth.two-factor-enrollment-reveal P1 api 3 PASS
identity-auth.two-factor-backup-codes P1 api 4 PASS
identity-auth.two-factor-disable-lifecycle P1 api 1 PASS
integration-system.connector-degraded-recovery P1 api 4 PASS
integration-system.notify-inbox-delivery P1 mixed 5 PASS
records-forms.action-location-matrix P1 browser 14 PARTIAL (A3 fail-closed half and A4 half (a) blocked(fixture), knownGaps[2])
search.rls-both-personas P1 api 8 PASS
search.pinyin-flag-both-sides P1 mixed 5 PASS
ux-conventions.write-feedback P1 browser 4 PASS

Derived: 25 PASS / 4 PARTIAL / 0 FAIL / 0 BLOCKED / 0 NOT-RUN. No clause failed, so no reproduction rule is owed, and there is no authentication or authorization finding.

#25626, Create User. It merged at 15:24Z, after this run's subject was fixed. Under this set's rule it adds no unpinned item. The only P1 item whose source[] cites admin-user-endpoints.ts, identity-auth.admin-lifecycle-operations, carries an automated.ref. That item is being run separately on the new head and will be filed as its own record, linked from the close-out comment.

Per-clause evidence (one line per clause; text oracles)

Labels: A0, A1, … are acceptance[0], acceptance[1], …; N0, … are negative[0], … (zero-based).

cli.fresh-install-migrate-apply-first

  • A0 pass: on an empty DB (no db, -wal or -shm), os migrate apply --yes exits 0, printing Created/extended 107 table(s) and the organization-ownership birth marker (shape generation 1). Before any boot, the marker query returns exactly 1 row: blocking 0, advisory 0, details.birth.shapeGeneration 1 (= ORGANIZATION_OWNERSHIP_SHAPE_GENERATION). After the boot it is the same single row, byte-identical.
  • A1 pass: the first os serve prints Server is ready (not DEGRADED) in production mode, and health answers 200 about 11 s in. The three refusal greps count 0.
  • N0 pass: the first serve is not refused.
  • N1 skipped: by its own text this negative is the pin's case (b), not this item's fixture (see the accuracy findings).

access-security.packaged-flow-write-door-parity

  • A0 pass: ?layers=true shows a populated code layer and _packageId com.example.showcase.
    • PUT /meta/flow/showcase_urgent_task_alert → 403 NOT_OVERRIDABLE.
    • With ?package=com.example.showcase → 403 ITEM_LOCKED.
    • The reads before and after are identical.
  • A1 pass: PUT /automation/showcase_urgent_task_alert → 403 NOT_OVERRIDABLE with the same lock text; the read-back is byte-identical.
  • A2 pass: DELETE /automation/… → 403 NOT_OVERRIDABLE ("sealed against removal"); the following GET is 200 and identical.
  • A3 pass: nothing mutated. _status reads enabled:true, bound:true, and an urgent task create took runs from 0 to 1 (completed, trigger.recordId = the new task).
  • N0 pass: the refusal is the package lock, which differs from the capability tier (Mei gets 403 "requires the manage_metadata capability").
  • N1 pass: neither /automation door returns a 2xx.

ai.mcp-run-action-exposure-gate

  • A0 pass: run_action showcase_mark_done is refused (isError) with the opt-in prescription, both with and without objectName. The task's status and updated_at are unchanged.
  • A1 pass: list_actions {} returns only showcase_portfolio_snapshot (totalCount 1).
  • A2 pass: the exposed action returns accounts:14, projects:5, invoices:12, which equals the REST totals.
  • A3 pass: the [action-audit] … executes TRUSTED … for user line names the user.
  • A4 pass: revoke_session is refused by the system-object guard, both without objectName and with objectName: sys_session. The victim session stays live.
  • N0 pass: the refused call has zero side effects.
  • N1 pass: list_actions and run_action agree.

api-backend.aggregate-contract-matrix

  • A0 pass: all 6 functions, grouped and ungrouped, have 0 mismatches against the local baseline. count(*) returns 16 while count(annual_revenue) returns 15, using a planted null row. On a boolean field, min/max are the numbers 0/1.
  • A1 pass: day, week, month, quarter and year all reconcile. The run was at 14:40Z, UTC.
    • Null dates form one real null bucket.
    • Weeks are ISO: 2024-11-24 → 2024-W47, 2024-12-30 → 2025-W01, 2027-01-03 → 2026-W53.
    • Quarter keys read YYYY-Qn.
  • A2 pass: on an empty where, the ungrouped result is count 0, sum 0, avg/min/max null, count_distinct 0; grouped, there are no buckets. A per-measure filter empties only its own measure.
  • A3 pass: array_agg and string_agg → 400 VALIDATION_FAILED with the retirement text and the os migrate meta --from 16 prescription. median → 400 naming the six functions. A nonexistent field → 400 INVALID_FIELD. A non-array → 400.
  • A4 pass: the contributor-bound member (recipe) sees 0 seeded rows, and INV-1003 answers 404. Their grouped count is {draft:1}, their own row only; the admin's is {draft:3, paid:5, sent:5}.
  • A5 pass: 11 variant rows. The 5 granularities give 14, 14, 12, 9 and 5 buckets.
  • N0 pass, N1 pass.
  • N2 pass: /analytics/query with day buckets returns identical labels under UTC (driver path, data.sql present), America/Los_Angeles and Pacific/Auckland (in-memory path). The analytics: the in-memory date bucket shifts a timezone-naive Field.date one day EARLIER under any negative-offset timezone (America/New_York → 2026-10-01 buckets as 2026-09-30), so it disagrees with the SQL pushdown path #24618 shift does not reproduce.

automation.trigger-status-contract

  • A0 pass: both trigger routes answer identically:

    • unknown → 404 RESOURCE_NOT_FOUND
    • always-fails → 400 FLOW_FAILED
    • disabled → 409 FLOW_DISABLED
    • no start node → 422 FLOW_NO_START_NODE
    • valid → 200

    The qa-flow-status-doors recipe provisioned live, every step 2xx.

  • A1 pass: showcase_reassign_wizard → 200 {status:'paused', runId, screen.nodeId:'collect'}, and that run was later resumed to completed.

  • A2 pass: with showcase_reassign_wizard disabled, POST /api/v1/actions/showcase_task/showcase_bulk_reassign → 409 FLOW_DISABLED. With showcase_inquiry_purge disabled, its type:'flow' endpoint POST /api/v1/apps/showcase/inquiries/purge → 409. Through /actions, a no-start flow → 422. All three doors import classifyFlowRefusal.

  • A3 pass: the 400 carries error.details.errorMessage and details.summary at both the trigger door and /actions.

  • A4 pass on 6 arms, each re-read as still paused:

    • missing screen input → 400 INVALID_SCREEN_INPUT
    • inputs+output → 400 INVALID_SIGNAL
    • inputs+variables → 400 VALIDATION_FAILED
    • member → 403 PERMISSION_DENIED
    • a concurrent resume during a 6 s http node → 409 RESUME_IN_PROGRESS
    • unknown or consumed run → 404 RUN_NOT_FOUND

    The 503 STORE_UNAVAILABLE arm is blocked(fixture): no stock trigger reaches it, as the clause says.

  • A5 pass: a flow deregistered under a live pause → 404 RUN_NOT_FOUND ("Flow … not found for run"). A paused node edited away → 404 ("Suspended node 'collect' no longer exists").

  • A6 pass: @objectstack/client trigger/execute reject with httpStatus/code 404/400/409/422, and resume with 400/400/403/404, all matching the rows. Paused and valid calls resolve.

  • N0–N5 pass.

automation.packaged-flow-subflow-disable-refusal

  • A0 pass: disabling showcase_notify_owner → 409 DELETE_RESTRICTED, naming caller showcase_task_done_notify_owner, ADR-0126 §7.3 and the remedy.
  • A1 pass: disabling map child showcase_one_task_signoff → 409 naming showcase_release_signoff.
  • A2 pass: 0 sys_metadata_activation rows after the refusals. A caller-driven run completed, and its call_notify subflow step succeeded.
  • A3 pass: enabling the child → 200, with the caller off and with it armed.
  • A4 pass: disable the caller → 200, then the child retry → 200, and the ledger holds both active:false. The teardown re-enabled both.
  • N0 pass.
  • N1 blocked(fixture): naming every packaged caller needs a second packaged caller. A ?package=-authored scratch flow counts as deployment-authored, so only a package-loader-installed package can stage one (see the accuracy findings).

automation.packaged-flow-clone-contract

  • A0 pass: {}, {name} and {label} each → 400 VALIDATION_FAILED naming the missing field, and no clone is registered.
  • A1 pass: the key diff is exactly name, label, status:'draft', plus the absence of _provenance, _packageId and _packageVersion. None of the 10 dropped keys is present, and no ancestry key appears.
  • A2 pass: one urgent create took the base runs from 0 to 1 and the clone runs from 0 to 1, for the same recordId. The notice equals FLOW_CLONE_NOTICE.
  • A3 pass:
    • same name → 409 RESOURCE_CONFLICT, suggesting …_copy
    • unknown source → 404
    • Bad-Name! → 400 with the pattern
  • A4 pass: the subflow node keeps config.flowName.
  • A5 pass: a PUT on the clone → 200, and the edit is read back.
  • A6 pass: after a cold restart over the same DB, the clone answers GET 200 and meta/flow shows _packageId null; a new create took the clone runs from 1 to 2. Studio /_console/studio/~org/automations (form sign-in) lists both clones under "Organization flows" and opens the designer.
  • N0–N2 pass.
  • N3 pass: Mei → 403 PERMISSION_DENIED and anonymous → 401, with no clone created.

integration-system.connector-degraded-recovery

  • A0 pass: in a scratch copy with the MCP fixture script moved away, the boot completes in about 13 s.
    • WARN Connector registered DEGRADED: showcase_mcp_tools … Connection closed.
    • The descriptor reads state:'degraded', the reason and actions:[], and it is listed.
  • A1 pass: the transport.kind:'carrier_pigeon' twin fails at boot (providerConfig.transport.kind must be 'stdio' or 'http') and nothing listens.
  • A2 pass: echo dispatch → 400 in 41 ms, quoting the stored degraded reason. That is distinguishable from an unknown connector ("no handler for …").
  • A3 pass: retries at +5 s, +10 s and +20 s, with the next announced at 40000 ms. A view publish triggered retry 5, and the next delay was 80000 ms, so backoff was not reset.
  • A4 pass: the file was restored with no restart. The next retry logged recovered connector instance 'showcase_mcp_tools' via provider 'mcp' (1 action(s)), the descriptor reads state:'ready', and echo → 200 {upper:'OBJECTSTACK'}.
  • N0 pass, N1 pass.

approvals.approver-resolution-matrix

  • A0 pass: each scratch flow was registered via POST /api/v1/automation and fired by a field_zoo create:
    • team → [Mei, Contributor]
    • field f_users → [Ada, Mei]
    • manager → [Ada]
    • user → [Mei]
    • org_membership_level owner → [admin]
  • A1 pass: department bu_field_ops → [Ada, Mei, Contributor], deduplicated. With bu_west_coast deactivated → [Ada, Contributor]. An unknown or inactive root warns "expanded to nobody" and goes to admin_rescue.
  • A2 pass: pending_approvers holds the two ids, and __resolvedFrom field:f_users holds the 2-element array.
  • A3 pass: role gives the ADR-0090 D3 deprecation WARN, and its slate equals the org_membership_level owner slate.
  • A4 pass, by policy:
    • absent / admin_rescue → pending [admin], the sole owner. __resolvedFrom records admin_rescue:abandoned ['position:ops'] with the reason, plus an actorless system comment and a WARN.
    • fail → no request row, and the run fails NO_APPROVERS.
    • auto_approve → no row, the run completes and the approve-edge marker is written.
    • fallback to owner → [admin]; fallback to user Mei → [Mei], which discriminates.
    • a fallback that also resolves to nobody → admin_rescue.
  • A5 pass: queue gives the not-implemented WARN, pending [admin], abandoned ['queue:q_runa'], and the request stays pending.
  • N0–N4 pass.

identity-auth.two-factor-enrollment-reveal

  • A0 pass: the guard discriminates. On the armed boot (OS_AUTH_TWO_FACTOR=true), /auth/config reads features.twoFactor:true and POST /two-factor/enable {} → 400. On the unarmed control, it reads twoFactor:false and enable → 404.
  • A1 pass: enable → 200 with method, totpURI, backupCodes. The URI is otpauth://totp/ with label ObjectStack:admin@objectos.ai and issuer=ObjectStack. The secret is 52 base32 chars, which is 32 bytes. digits=6, period=30.
  • A2 pass: backupCodes is a string[] of 10, shaped xxxxx-xxxxx.
  • A3 pass: the sys_two_factor.enable_two_factor resultDialog paths resolve against the live response (string; string[] of 10).
  • A4 pass (recorded): get-totp-uri returns 400 without a body, 400 INVALID_PASSWORD for a wrong password and 401 for anonymous. With the correct password it returns 200 and the same secret, both before and after verification. It is password-gated and re-reveals; the item's owed ruling stands.
  • A5 pass: sys_user.enable_two_factor declares the qrcode and code-list fields and the acknowledge text, with no successMessage. Both paths resolve.
  • N0 pass: a wrong-password or anonymous enable writes 0 rows.
  • N1 pass, N2 pass.

identity-auth.two-factor-backup-codes

  • A0 pass: the enrollment was verified (verify-totp 200; verified went from 0 to 1, and two_factor_enabled is 1).
  • A1 pass: the challenge sign-in returns {twoFactorRedirect:true, twoFactorMethods:['totp']} and sets only better-auth.two_factor; get-session mid-challenge is 401. A backup code → 200, then get-session 200.
  • A2 pass: the same code at a fresh challenge → 401 INVALID_BACKUP_CODE; the control code → 200.
  • A3 pass: generate-backup-codes → 200 with 10 new codes and no overlap. An unspent old code → 401, and a new one → 200.
  • A4 pass (recorded): backup_codes is stored as a hex blob that is not JSON and contains no plaintext code. It was read from the DB file, because REST never returns the column, even to admin.
  • A5 pass: sys_user.generate_backup_codes declares a code-list, the acknowledge text and refreshAfter:false, and the path resolves.
  • N0–N3 pass: a wrong-password regenerate → 400 and anonymous → 401, and the refused regenerate was a no-op.

identity-auth.two-factor-disable-lifecycle

  • A0 pass: before, there is 1 row and the challenge fires.
  • A1 pass: a wrong-password disable → 400 INVALID_PASSWORD with the state unchanged, and anonymous → 401.
  • A2 pass: disable → 200, leaving 0 rows and the flag at 0.
  • A3 pass: the next sign-in → 200 with no twoFactorRedirect and only session_token.
  • A4 pass:
    • A retained code with no cookie → 401 INVALID_TWO_FACTOR_COOKIE; on a live session → 400 BACKUP_CODES_NOT_ENABLED.
    • Re-enable gives a new secret with no overlap.
    • An old-secret TOTP → 401 INVALID_CODE on both lanes; a new-secret TOTP → 200.
  • A5 pass (recorded), with mfa_required on:
    • Disable → 200, not refused.
    • mfa_required_at is stamped lazily on the next request (a fresh 7-day grace).
    • With grace 0, a data read → 403 MFA_REQUIRED and get-session carries authGate, while /two-factor/enable and verify-totp stay reachable (200), after which data answers 200.
    • The stamp is not cleared on re-enrolment, matching source. Settings were restored.
  • N0–N3 pass.

search.rls-both-personas

  • A0 pass: the recipe was replayed as written. The member's list is 200 with 0 rows, and by-id INV-1003 → 404. Member search INV-1003 → [] with total 0; admin → [INV-1003] with total 1.

  • A1 pass: paged {search:'INV', limit:2} reads:

    • skip 0 → 2 rows, total 3
    • skip 2 → 1 row, total 3
    • skip 4 and 6 → empty, total 3

    The total always equals the member's visible rows; the admin's is 15, which never leaks.

  • A2 pass: the member's own 3 rows are found.

  • A3 pass: deny, allow and own-row evidence are complete, through expandSearchOnAst.

  • N0 pass.

access-security.capability-declaration-lifecycle

  • A0 pass: GET /meta/capability/showcase.export_data → 200 with the declared fields and scope org. GET /data/sys_capability → 404.
  • A1 pass, on the action dispatcher:
    • perm_held: the ops member → 200; a non-granted member → 403 naming the missing capability; admin → 403.
    • PUT /meta/permission/showcase_ops → 403 NOT_OVERRIDABLE.
    • A clone with no label → 400; with a label → 200.
    • A member granted the clone → 200. Withdrawing the capability → 403 (twice); restoring it → 200, also within one live session.
    • perm_missing and perm_and → 403 for all personas, and perm_empty → 200 for all.
  • A2 pass: a scratch app declaring manage_users passes os validate and os build (both exit 0). The boot then stops with Security catalog name conflict … "manage_users" is already held by the platform, and nothing listens.
  • A3 pass:
    • scope:'galaxy' makes os validate exit 1, naming the path and the allowed values.
    • PUT /meta/capability/NEW → 403 NOT_CREATABLE.
    • PUT on a platform or package capability → 403 NOT_OVERRIDABLE.
    • The data door answers 404 for both GET and POST.
  • N0–N4 pass.

identity-auth.org-membership-team-management

  • A0 pass: the Setup "Organization" nav targets the sys_organization record whose id equals get-active-member.organizationId. The record page renders the Members, Invitations and Teams tabs and the Invite, Rename and Edit actions (screenshot).
  • A1 pass: as a member, create-team and invite-member → 403. After promotion to admin, invite → 200; after demotion, 403 again. delegated_admin and owner are accepted.
  • A2 pass: guest, contributor and showcase_ops → 400 ROLE_NOT_FOUND on both doors, with no state change and no invitation row.
  • A3 pass: rename → 200; the full-organization read, the data read and the page title all follow.
  • A4 pass: remove-member → 200, and the old session → 401. A fresh sign-in gets 403 USER_IS_NOT_A_MEMBER_OF_THE_ORGANIZATION on get-full-organization and set-active. The member's sessions read revoke_reason: organization_membership_ended.
  • A5 pass: create-team and add-team-member give unique rows (a duplicate add is idempotent). A generic POST /data/sys_team_member → 405.
  • A6 pass: the forger gets 403 with its YOU_ARE_NOT_ALLOWED_* code on all 7 doors, and the snapshot is unchanged. The non-admin UI shows "You don't have access to this app", with no Organization nav.
  • N0–N3 pass.

search.pinyin-flag-both-sides

  • A0 pass (ON): zhangwei/zw/张 → 张伟, wf → 王芳, and huaning/hnkj → 华宁科技.
  • A1 pass: the Latin-named contact at 华宁科技 is not found by hnkj or huaningkeji (0), while 华宁科技 finds 4 via the source column.
  • A2 pass (OFF, explicit false): zw, wf and hnkj → 0, and 张 → 张伟. Latin source-column hits remain, with no errors.
  • A3 pass: 53 plugins loaded with the flag on against 52 with it off; the diff is exactly PinyinSearchPlugin. The OFF log has 0 'pinyin' lines once the runner's own file-path lines are excluded.
  • A4 pass: on first boot, the companion hooks are bound and reconcile updated 1 account and 3 contacts; the ON queries hit with no rebuild.
  • N0 pass, N1 pass.
  • Step 5 (no clause): list quick-search search=zw showed only 张伟.

i18n.strict-translation-key-rejection

  • A0 pass: all 10 variants → 422 INVALID_METADATA via PUT /api/v1/meta/translation/zh_cn_qa. Each issues[] entry names the surface and echoes the key.
  • A1 pass: defineTranslation (/system) and defineTranslationBundle (root) both throw for all 10, and accept the valid doc.
  • A2 pass: "Did you mean helpText → help?" and "label → title?" appear at both doors.
  • A3 pass: each retired key points at its replacement home: objects / apps / navigation / dashboards, object.validations[].message, ADR-0049 with spec 17.0.0, and the top-level locale.
  • A4 pass: a rejected save on a fresh name reads back 404. Three rejected saves over a saved baseline leave the baseline unchanged.
  • A5 pass: on a zh-CN session, the record-page type badge reads 任务(QA-runB) and the New dialog 新建任务(QA-runB).
  • N0 pass, N1 pass.

approvals.decision-action-matrix

  • A0 pass: each of the nine variants answers 200, and each appends exactly one /:id/actions row naming the actor and the action. The variants are approve, reject, revise ×2, resubmit (on the original id), recall, remind, reassign, request-info (by the reassigned approver) and comment. The maxRevisions-guard revise appends two rows; see the accuracy findings.
  • A1 pass: EXP-DEMO goes pending → approved, and its run goes paused → completed. A budget approve completes, passing a needs_exec:decision:success step. A budget reject ends rejected, and its run has no needs_exec step.
  • A2 pass: revise sets status returned, and the run is paused at wait_revision:approval_revise.
  • A3 pass: the submitter's resubmit opens a new pending request on the same flow_run_id and flow_node_id, with a new id. A non-submitter's resubmit → 403.
  • A4 pass: R1 still reads returned. The run lists [R3, R2:returned, R1:returned].
  • A5 pass: the third revise → 200. R3 is rejected and the run completes.
  • A6 pass: the submitter's recall → recalled. Two non-submitters → 403. ?approverId=…&status=pending lists the request before the recall and not after.
  • A7 pass: reassign replaces the slate with the target and leaves status pending. Remind, request-info and comment leave the status, tallies and slate byte-identical, adding one row each.
  • A8 pass: a PATCH under manager_review (lockRecord:false) → 200. Under exec_review (lockRecord:true) → 409 RECORD_LOCKED.
  • A9 blocked(fixture), knownGaps[0]. Both remaining candidates were refuted on a scheduled-work boot:
    • A schedule-triggered approval binds but fails with "no target object in context" ($record cannot be assigned).
    • An api-hook approval on a tenancy:{enabled:false} object still stamps the default organization.
  • N0 pass: revise at exec_review → 400 VALIDATION_FAILED ("no 'revise' out-edge"), with nothing changed.
  • N1 pass: a second remind → 429 THROTTLED, with no row.
  • N2 pass: every wrong-actor call → 403, including admin's request-info after reassigning its slot away.

automation.flow-run-step-nesting

  • A0 pass: the batch-reminders run completes with 3 send_reminder steps.
  • A1 pass: guard_reminder steps carry {parentNodeId:loop_tasks, regionKind:loop-body} with iterations 0, 1 and 2. send_reminder steps carry {parentNodeId:guard_reminder, regionKind:try} with the matching iteration. Top-level steps carry no parent.
  • A2 pass: in the nested fan-out over 2 rows, each (iteration, branch) pair appears exactly once and branch 0 is present. The container reads loop-body with no branch. All 18 steps of the three runs parse under ExecutionStepLogSchema.
  • A3 pass: the Studio Runs panel shows a nested tree: "For each task LOOP" → ITERATION 1/2/3 → TRY_CATCH → TRY → Send Reminder (screenshot).
  • A4 pass: the tree's 8 rows match the 8 API steps and their tags.
  • A5 pass: an empty-list run completes with [start, loop_tasks] and 0 children.
  • N0 pass.

automation.flow-node-type-matrix

  • A0 pass: GET /automation/actions returns 19 ids (start and end are excluded), and the Studio Add-node palette on a clone shows the same 19, plus End and Revise Window.

  • A1 pass: every type is evidenced by a logged step on a stock boot, including:

    • create_record from a signed inbound webhook (202)
    • http via the knownGaps self-ping recipe
    • connector_action via the declarative, REST and MCP connectors
    • map via release signoff

    A skipped end step is not used as end's evidence.

  • A2 pass: screen, wait (1-minute timer), approval, approval_revise and map each read paused, then completed.

  • A3 pass: a sweep of 46 runs (145 steps) over 41 flows finds 0 steps with an empty nodeType.

  • A4 pass: the loop-body, parallel-branch, try and catch steps all carry parentNodeId and regionKind.

  • A5 pass: the bogus_node flow saves 200 and a WARN names unknownTypes:['bogus_node']. Its trigger → 400 FLOW_FAILED "No executor registered", and the step error code is NO_EXECUTOR.

  • N0 pass.

automation.flow-error-handling

  • A0 pass: the resilient-sync run completes and its try_catch step reads success.
  • A1 pass: the push attempts (regionKind try, parent guarded_push) fail with NODE_FAILURE "http: fetch failed", and all come before the catch step record_failure.
  • A2 pass: retryAttempt runs 0–3. The 7096 ms total is consistent with a 1+2+4 s backoff, and a second run shows the same.
  • A3 pass: both tasks read sync_status=failed with the sync_error text.
  • A4 pass: an unprotected probe flow's run reads failed with the error string.
  • A5 pass: the Runs panel shows TRY with 4 FAILURE rows, then CATCH SUCCESS, and the probe panel shows the run-level error (screenshot).
  • A6 pass: the log has an ERROR line for the trigger-fired run ("no caller holds this result and nothing retries the run").
  • N0–N2 pass.
  • N3: recorded. A container reads success after catching a failure, as ruled by design.

api-backend.formula-stdlib-matrix

  • A0 pass (test oracle): the harness resolves packages/formula/dist, and no src file is newer than dist.
    • The source chain registers 29 functions, and formulas.mdx names the same 29, with 0 missing in either direction.
    • 63 known-answer rows cover all 29 functions, with 0 failures.
  • A1 pass: today() pinned to Asia/Shanghai gives that zone's midnight. UTC, and the invalid zone Not/AZone (no throw), give the UTC day. daysFromNow and daysAgo agree.
  • A2 pass:
    • addMonths(2026-01-31, 1) = 2026-02-28.
    • floor(-1.2) = -2 and ceil(-1.2) = -1, both int.
    • joinNonEmpty over fields gives 'a-b'.
    • coalesce('', 'x') = '', and coalesce(null, 'x') = 'x'.
    • min/max keep their type.
  • A3 pass: amount/100 with amount 250 gives 2.5 (double), and 7/2 gives 3 (int).
  • A4 pass, live: stock budget_remaining = 102000. A scratch formula upper(joinNonEmpty(…)) reads "ALPHA-GAMMA" in the 201 response and on a later GET.
  • A5 pass:
    • The active PUT with sqrt(4) → 422 INVALID_METADATA, rule expression-invalid, located at "field 'bad_f' expression".
    • A draft save → 200 while the active definition stays clean.
    • Publish → the same 422.
    • Control: floor saves and evaluates.
  • N0–N2 pass.

integration-system.notify-inbox-delivery

  • A0 pass: after a reassign to a minted assignee, the assignee's GET /notifications lists task.assigned with the title, body and actionUrl, and the run completes.
  • A1 pass: a third member's list is [] with unread 0.
  • A2 pass: POST /notifications/read → readCount 1, ?read=false drops from 2 to 1, and the receipt row flips delivered → read. read/all → 0 unread, and both receipts read state=read.
  • A3 pass: anonymous → 401. On a scratch app-todo with --preset minimal (no MessagingServicePlugin), GET, read and read/all → 501 NOT_IMPLEMENTED "Install @objectstack/service-messaging to enable", and anonymous still gets 401.
  • A4 pass: a ['push']-only notify leaves the inbox at 2 and deliveries at 23, and logs WARN "channel 'push' is not registered; refused 1 delivery row(s)".
  • N0 pass. N1 pass: the third member's cross-user mark-read → readCount 0.

approvals.per-group-signoff

  • A0 pass: before any decision, EXP-2001 reads pending. Its slate has two distinct ids (admin, Ada), pending_approver_groups maps admin→manager and Ada→finance, and decision_progress reads per_group 0/2, with each group at got 0, need 1.
  • A1 pass: after the admin's approve the request is still pending. The slate is [Ada], manager reads got 1 need 1 satisfied:true and finance reads 0/1.
  • A2 pass: the record-page chips match the API at each stage: "0 of 2 groups · finance 0/1 · manager 0/1 · Waiting on …" → "1 of 2 groups … Waiting on Ada Auditor·finance" → approved, with no chips.
  • A3 pass: Ada approves from her own form-signed-in context, and the response reads status:"approved". The run goes paused → completed (start, dual_signoff, mark_approved).
  • A4 pass: /actions reads submit, approve (admin), approve (Ada), both via_override:false.
  • A5 pass: the admin POSTing {actorId: Ada} gets 403 "cannot act as … recorded against the authenticated caller", with no row written. The UI body carries no actorId, and the recorded actor is the session.
  • N0 pass (contrast): unanimous INV-1006 with slate [admin, admin] finalizes on one approve. Per-group took two decisions.
  • N1 pass: Mei and a freshly minted member each get 403 "not a pending approver", with no row written.

approvals.quorum-m-of-n

The runtime fixture from fixtures.requires was applied on a fresh boot: Ada bound to finance, a minted member bound to legal, the expense flow toggled off, then two reports at 6000 submitted, then the flow re-enabled. Each request's slate holds 3 distinct holders, at progress 0/2.

  • A0 pass (clamp contrast): on EXP-DEMO, slate admin×3 with need 1, one approve gives approved.
  • A1 pass: Q1 goes 0/2 → 1/2 (Ada) → approved (the legal member), with two distinct non-override actors. The run completes with mark_approved.
  • A2 pass: Q2 goes 1/2 (Ada), then the legal member rejects via the UI. Result: rejected, the slate is empty, the run completes via return_to_draft, and the report reads draft. A later approve → 409 INVALID_STATE.
  • A3 pass: after Q1 finalizes, the slate is empty with the third holder dropped, and the admin's My Pending count goes from 3 to 2. A post-final approve → 409.
  • A4 pass: the record-page tally reads "0 of 2 · 3 eligible", then "1 of 2 · 2 eligible", then the approved state, matching the API at each stage.
  • N0 pass: Ada's repeat approve and Mei's approve → 403 "not a pending approver", and the tally stays at 1/2.
  • N1 pass: the verdict rests on the runtime fixture, not the clamp.

approvals.inbox-metadata-actions

Fixture: a minted plain member; the admin reassigns EXP-DEMO to them.

  • A0 pass: the member's My Pending → Request cell opens the served sys_approval_request record page, with approve, reject, reassign, send_back, request_info and Reply.
  • A1 pass:
    • Own request (admin, INV-1010): all 8 actions, including Send reminder and Recall.
    • Member on EXP-DEMO: neither Send reminder nor Recall.
    • Admin on EXP-DEMO: only the Override variants.
  • A2 pass: the viewer flags predict each rendered set exactly: {T,F,F}, {F,F,T} and {T,T,T}.
  • A3 pass: the member's Approve sends POST …/approve → 200, and a re-read shows approved. The admin's Send reminder → 200, and the request stays pending.
  • A4 pass: each action appends exactly one row with the right actor.
  • N0 pass: no button renders against a denying flag.

records-forms.action-location-matrix

The served meta/object/showcase_task actions match the source: 10, with showcase_new_task carrying locations: [].

  • A0 pass: every hosted location renders a declared action:

    location rendered
    list_toolbar Reassign…
    list_item Mark Done or Reopen, Reassign…, Quick View
    record_header Mark Done, Log Time, Archive
    record_more (⋯) Open Docs, Recalculate Estimate, Recalculate Selection
    record_related Log Time
    record_section Mark Done, Log Time, Archive
  • A1 pass: no extra placements. Open Docs and the Recalc actions are not inline or on the toolbar, Log Time is not on the task rows, and the toolbar's ⋯ holds only "Add to favorites".

  • A2 pass, one dispatch per location:

    • list_toolbar with a row selected: POST /actions/showcase_task/showcase_bulk_reassign → 200 opens a screen, Submit → resume 200, and the server-side assignee changed. With no row selected, the toolbar toasts "select a row first".
    • list_item: Quick View opens its modal.
    • record_header: Mark Done → 200, and done goes from false to true.
    • record_more: Recalculate Selection → POST /api/v1/apps/showcase/recalc 200, and estimate_hours goes from 1 to 136. Open Docs opens a popup (the target is egress-blocked).
    • record_section and record_related: Log Time routes to forms/showcase_task.form?recordId=….
  • A3 partial: the both-sides half passes: a not-done task shows Mark Done everywhere, and a done one shows Reopen and no Mark Done. The fail-closed half is blocked(fixture): no throwing predicate ships on stock, and runtime-authored actions are not served (knownGaps[2]).

  • A4 partial: half (a) is blocked(fixture), because no packaged locations-less specimen exists (knownGaps[2]). Half (b) passes: New Task appears on none of the six surfaces, and recalc_selection is under ⋯ only.

  • N0–N2 pass.

ux-conventions.write-feedback

  • A0 pass: every landed write showed feedback paired with a server read:

    write feedback
    create "Task created successfully"
    inline Priority edit "1 row saved"
    bulk delete ×2 confirm, then "Deleted 2 Task records"
    kanban Backlog→To Do "Moved Content backlog to To Do." (live region)
    Mark Done "Task marked done."
    invite "Invitation sent to …"
    approve Approved "EXP-2001"
    import of 2 rows "Imported 2 rows."
    Studio autosave "Saved 03:16 PM"
    Studio publish "Published 1 item…"
    Studio discard "Draft discarded: Widget"
    Settings Localization "Settings saved"
  • A1 pass: messages name the subject. The object-only strings are listed under the accuracy findings (an open ruling, as in 18.1).

  • A2 pass: the declared strings render verbatim: "Task marked done." and "Invitation sent to {{ result.email }}", rendered with the invitee.

  • A3 pass:

    • An empty create sends no request and shows field errors plus "Please check the highlighted fields".
    • Kanban Backlog→Done → 400 invalid_transition. An error toast appears, the card reverts, and no "Moved" claim is made.
    • A member's Mark Done → 403, with an error toast, and done stays false.
  • A4 pass: Escape, or re-picking the same value, sends no PATCH and shows no dirty indicator.

  • A5 pass: background import offers Undo. Create-mode undo → 200 deleted:2 (count 16→14). Update-mode undo → 200 restored:1 (priority back to high).

  • N0–N2 pass: no success feedback on any 4xx, and none without a request.

i18n.notification-localized-and-clears

Ada switched to zh-CN through the avatar menu (PATCH sys_user {locale:'zh-CN'} 200); Mei stays EN. The flow has an inline title and no template. The admin reassigned a task to Ada, then to Mei.

  • A0 pass: Ada's zh-CN bell (消息中心) entry reads the rendered literal, "New task assigned: Content backlog".
  • A1 pass: the deep link opens the task record page, fully in zh-CN.
  • A2 pass: POST /api/v1/notifications/read → 200 readCount:1, and unreadCount goes from 3 to 2.
  • A3 pass: after a hard reload the server still reads unreadCount 2 and the row reads read:true, through an independent client.
  • A4 pass: Mei's EN bell shows the identical title, and the server titles are identical.
  • N0–N2 pass.

Findings outside the clauses (rule 8 probes)

These are extracted at close-out (see the closing comment). None is an authentication or authorization defect.

  1. The aggregate door answers wrong data under 200 in three shapes (silent coercion, medium):

    • dateGranularity on a non-date field puts every row in one null bucket.
    • A duplicate alias lets the second measure overwrite the first.
    • An alias that equals a groupBy field destroys the group keys.

    Seen beside api-backend.aggregate-contract-matrix.

  2. POST /api/v1/data/OBJECT/query {"aggregations":[]} answers 404 OBJECT_NOT_FOUND "Object … is not registered" for a registered object (low). Seen beside api-backend.aggregate-contract-matrix.

  3. The resume door ignores the flow name in its path (low). POST /api/v1/automation/OTHER_FLOW/runs/RUNID/resume completes another flow's paused run, and GET with the wrong name reads it too. Authority is still identity-based: a member's 403 held, so this is not an authorization defect. Seen beside automation.trigger-status-contract.

  4. The trigger door drops a non-object params and dispatches anyway (low). {"params":"oops"} runs with an empty bag, while the resume door refuses the same shape with 400. Seen beside automation.trigger-status-contract.

  5. A translation item accepts any locale string (low to medium). PUT /api/v1/meta/translation/NAME with locale: 'not a locale!!' → 200 with _diagnostics.valid:true. LocaleSchema is a bare z.string(). Seen beside i18n.strict-translation-key-rejection.

Low, not extracted:

Checklist-accuracy findings and fixture gaps (wave anchor #25807, not extracted)

cli.fresh-install-migrate-apply-first

  • N1 states scope (the pin's case b), not an outcome, so it can only score skipped. This is the same class revision 3 fixed on the write-door item.

automation.trigger-status-contract

  • steps[7] asks for "the SAME disabled flow" through /actions and an endpoint, but no stock flow is reachable from all three doors.
  • The runner used showcase_reassign_wizard with showcase_bulk_reassign, and showcase_inquiry_purge with its endpoint.
  • The /actions 400 and 422 rows need a type:'flow' action. The recipe could add PUT /api/v1/meta/action/NAME?package=com.objectstack.qa.automation.
  • The recipe knownGap "NOT yet proven by a live run" is stale.
  • A bodyless resume of the stock wizard answers 400 INVALID_SCREEN_INPUT, not 200.

automation.packaged-flow-subflow-disable-refusal

  • knownGaps[0] is partly stale: a tenant caller can be authored through POST /api/v1/automation, and it does not guard.
  • A ?package=-authored flow counts as deployment-authored (the toggle answers 409 RESOURCE_CONFLICT "authored in this deployment"). So the self-caller arm and N1 need a package-loader-installed package.

integration-system.connector-degraded-recovery

  • steps[4]'s WARN "Connector … replaced" also prints on a husk-to-husk re-registration, so it is not a recovery signal; the descriptor state is.
  • os compile accepts transport.kind:'carrier_pigeon'; only the boot refuses it.

approvals.approver-resolution-matrix

  • The suggested fallback, org_membership_level owner, does not discriminate on stock, because the owner is the sole admin. Use {type:'user', member} instead.

automation.packaged-flow-clone-contract

  • For {}, A0's details names only the first missing field.

api-backend.aggregate-contract-matrix

i18n.strict-translation-key-rejection

access-security.capability-declaration-lifecycle

  • step 8 expects capabilities.0.scope, but the index is the entry's position (.2 when appended).
  • The surface is mixed, yet no clause has a browser oracle.

search.pinyin-flag-both-sides

  • The A3 zero-'pinyin' grep is polluted by runner file paths that contain "pinyin". Advise neutral names.
  • Plugin counts at 6679644: 53 with the flag on, 52 with it off.

identity-auth.two-factor-backup-codes

  • A4's at-rest check needs an out-of-band DB read, because REST never returns the column. The item should say so.

Runner C additions:

  • RUNNER.md "export OS_PORT" environment fact. At 6679644, os dev boots from the prebuilt dist/objectstack.json. With OS_PORT=41302 exported, GET /api/v1/meta/connector/showcase_status_api still answers baseUrl http://127.0.0.1:3000. Yet live connector_action reached 41302: ping.body uptime matched the boot, and nothing listens on 3000. So the Check that entry prescribes would misreport the fixture.
  • approvals.decision-action-matrix:
    • knownGaps[0]: the "one untried candidate" (a schedule-triggered approval) is refuted, and so is an api-hook on an object with no organization column. No stock door mints an org-less request.
    • N1 quotes "a reminder was sent recently"; the live text is "a reminder was already sent recently".
    • A0 says "exactly one" row, but the maxRevisions auto-reject appends revise then reject.
  • api-backend.formula-stdlib-matrix steps[5] / requires[1]: a scratch object without sharingModel gets 422 security-owd-unset. The step should say to declare one.
  • integration-system.notify-inbox-delivery knownGaps[2]: the app-todo scratch needs its node_modules. A symlink to the tree's copy works.
  • automation.flow-run-step-nesting steps[4]: the Studio route is /_console/studio/com.example.showcase/automations?surface=flow:NAME, then the Runs tab; probe flows are under ~org.

Browser items:

  • approvals.per-group-signoff:
    • A3.verify says end nodes log no step, but the approve branch now logs mark_approved.
    • Steps 3/4 say "drawer" and 待我审批. The row opens the served sys_approval_request record page, and the English tab is "My Pending".
    • The N0 contrast has no stock per_group collapsed-slate request; the unanimous invoice (admin×2) was used.
  • approvals.quorum-m-of-n: A2 says the reject edge is unobservable, but the run logs return_to_draft on reject. On a fresh boot the fixture needed no unbinding.
  • approvals.inbox-metadata-actions:
    • Steps 1/2/5 and A0 still say "drawer" and 待我审批/我发起的.
    • The Record cell opens the subject record, which also renders the bar, while the Request cell opens the request page. The steps should name the cell.
  • records-forms.action-location-matrix:
    • The related-list header renders the list_toolbar Reassign…, as in 18.1.
    • The sidebar "More actions" shares its accessible name with the header ⋯, a click trap; scope the click to main.
    • The quick bar names its actions explicitly, so recalc_estimate is absent there by page authoring.
  • ux-conventions.write-feedback:
    • knownGaps[3] and A5 ("no stock surface offers Undo") are stale: import Undo works in both create and update modes.
    • variants[10]: Discard draft is now an in-app dialog.
    • variants[6]: the approvals route has no drawer.
    • steps[3]: the console offers a member no inline edit, selection or drag, so use the member's Mark Done for the refusal row.
    • A1 needs a ruling on object-only strings ("Task created successfully", "Settings saved", Flow "Reassign Task" completed).
  • i18n.notification-localized-and-clears: the header badge counts notifications plus pending approvals. Read the server's unreadCount, never the badge.
  • Coverage gap: no ledger item asserts feat(plugin-auth): multi-org Create User joins the administrator's current organization #25626's walled Create User join or its 400 NO_ACTIVE_ORGANIZATION. To be confirmed by the addendum record.

Fixture gaps (already recorded on their items):

  • approvals.decision-action-matrix knownGaps[0]: there is no org-less request on stock. The schedule-trigger candidate and an api-hook on an object with no organization column are now both refuted.
  • automation.trigger-status-contract: the 503 arm has no stock trigger.
  • automation.packaged-flow-subflow-disable-refusal: N1 needs a package-loader-installed second caller.
  • records-forms.action-location-matrix knownGaps[2].

Off-clause probe line (rule 8)

About 41 runner-minutes across the four runners: A about 9, B about 8, C about 9, D about 15.

Personas: admin, Mei, Ada, contributor-bound member, plain members, an MFA user, an unenrolled user, an ops member, a forger (as member and as delegated_admin), a no-group approver, and anonymous.

Doors:

  • MCP run_action/list_actions
  • aggregate query and /analytics/query
  • /automation PUT/DELETE/trigger/resume/toggle/clone
  • connector dispatch
  • approvals POST family and list
  • two-factor family
  • /search and the data search
  • organization management doors
  • meta translation, capability and permission doors
  • notifications list/read
  • action dispatch, recalc API, settings PUT, import and undo, invite

Boundary classes:

  • empty, whitespace and missing values
  • unknown ids, names and actions
  • case variants
  • duplicate or colliding aliases
  • non-object bodies and params
  • wrong flow name in the path
  • TOTP ±1/±2 steps
  • last-owner self-demote
  • delegated_admin against admin reach
  • cross-user mark-read
  • forged actorId
  • readers outside scope

Found: the five extracted findings above and the low notes. Nothing was auth-class.

Carried forward from the 18.1.0 manual set (#25479)

#25479 judged 15 items at 77392e90 with pin 5fef032b1ada. Eight of them are re-judged above. These seven were not re-judged here and are carried forward unchanged:

Carried-forward: #25479 · platform-core.marketplace-install-local-lifecycle · PASS
Carried-forward: #25479 · identity-auth.first-run-owner-bootstrap · PASS
Carried-forward: #25479 · identity-auth.self-signup-gate · PASS
Carried-forward: #25479 · identity-auth.self-service-profile-password · PASS
Carried-forward: #25479 · platform-core.settings-hub-roundtrip · PASS
Carried-forward: #25479 · studio-authoring.draft-publish-lifecycle · PASS
Carried-forward: #25479 · approvals.record-page-decisions · FAIL

The FAIL is negative[1], extracted as objectui#13393.

Handover

None. Every item has a verdict.

Activity

  1. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Close-out for this record.

    Extracted: #25818 · api-backend.aggregate-contract-matrix · observed beside the clauses
    Extracted: #25819 · api-backend.aggregate-contract-matrix · observed beside the clauses
    Extracted: #25820 · automation.trigger-status-contract · observed beside the clauses
    Extracted: #25821 · automation.trigger-status-contract · observed beside the clauses
    Extracted: #25822 · i18n.strict-translation-key-rejection · observed beside the clauses
    Parked-on: #25807 · approvals.decision-action-matrix A9 fixture gap (no org-less request on stock; schedule-trigger and no-org-column candidates refuted)
    Parked-on: #25807 · automation.trigger-status-contract A4 503 STORE_UNAVAILABLE arm (no stock trigger)
    Parked-on: #25807 · automation.packaged-flow-subflow-disable-refusal N1 (needs a package-loader-installed second packaged caller)
    Parked-on: #25807 · records-forms.action-location-matrix A3 fail-closed half and A4 half (a), knownGaps[2]
    Parked-on: #25807 · checklist-accuracy findings of this record (body section of that name)
    Carried-forward: #25479 · see the body section of that name (7 items)
    

    No clause failed, so there is no four-way disposition to record. The 4 PARTIALs are fixture debts that their items already name, and they are parked on the anchor above.

    The low notes in "Findings outside the clauses" are not extracted:

    #25626 (Create User) merged at 15:24Z, after this subject was fixed. identity-auth.admin-lifecycle-operations is being run on 17f8217b as its own record, which will be linked here.

  2. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Addendum: #25626 merged at 15:24Z. identity-auth.admin-lifecycle-operations was then run on 17f8217b and is recorded in #25823 (1/1 PASS). #25626's J1/J2 dogfood passed 3/3, and #25824 was extracted. The Create User coverage gap and the three stale walled-persona recipes are parked on #25807.

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