Repository navigation
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
Description
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(objectstackmainhead at start, 14:16Z). The tree was clean.pnpm install --frozen-lockfileandpnpm build --concurrency=2passed 76/76. The tree is unreleased, so the CLI and health report 18.1.0. - Console:
.objectui-sha=b41ed7f68956c8cfda21bc790548361af81b09ac, built withOBJECTUI_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-shaequals the pin, sostale-console-bundleis 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 onb41ed7f68956. - App and boot:
examples/app-showcase, booted withOS_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,.objectstackordist) were used for cli.fresh-install-migrate-apply-first (productionos servewithOS_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.
- Scratch copies (tar, without
- Special switches:
OS_AUTH_TWO_FACTOR=truefor the two-factor items.OS_SEARCH_PINYIN_ENABLED=falsefor the pinyin OFF leg.OS_AUTOMATION_SCHEDULED_WORK_ENABLED=1only 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 statusstayed clean, and every server was stopped by process group. - Timings: environment prep took about 22 minutes for the cold tree:
pnpm build9 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,
-walor-shm),os migrate apply --yesexits 0, printingCreated/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 serveprintsServer 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=trueshows a populatedcodelayer and_packageId com.example.showcase.PUT /meta/flow/showcase_urgent_task_alert→ 403NOT_OVERRIDABLE.- With
?package=com.example.showcase→ 403ITEM_LOCKED. - The reads before and after are identical.
- A1 pass:
PUT /automation/showcase_urgent_task_alert→ 403NOT_OVERRIDABLEwith the same lock text; the read-back is byte-identical. - A2 pass:
DELETE /automation/…→ 403NOT_OVERRIDABLE("sealed against removal"); the following GET is 200 and identical. - A3 pass: nothing mutated.
_statusreadsenabled: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_metadatacapability"). - N1 pass: neither
/automationdoor returns a 2xx.
ai.mcp-run-action-exposure-gate
- A0 pass:
run_action showcase_mark_doneis refused (isError) with the opt-in prescription, both with and withoutobjectName. The task's status andupdated_atare unchanged. - A1 pass:
list_actions {}returns onlyshowcase_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 userline names the user. - A4 pass:
revoke_sessionis refused by the system-object guard, both withoutobjectNameand withobjectName: sys_session. The victim session stays live. - N0 pass: the refused call has zero side effects.
- N1 pass:
list_actionsandrun_actionagree.
api-backend.aggregate-contract-matrix
- A0 pass: all 6 functions, grouped and ungrouped, have 0 mismatches against the local baseline.
count(*)returns 16 whilecount(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
nullbucket. - Weeks are ISO: 2024-11-24 → 2024-W47, 2024-12-30 → 2025-W01, 2027-01-03 → 2026-W53.
- Quarter keys read
YYYY-Qn.
- Null dates form one real
- 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-measurefilterempties only its own measure. - A3 pass:
array_aggandstring_agg→ 400VALIDATION_FAILEDwith the retirement text and theos migrate meta --from 16prescription.median→ 400 naming the six functions. A nonexistent field → 400INVALID_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/querywith day buckets returns identical labels under UTC (driver path,data.sqlpresent), America/Los_Angeles and Pacific/Auckland (in-memory path). The analytics: the in-memory date bucket shifts a timezone-naiveField.dateone day EARLIER under any negative-offsettimezone(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-doorsrecipe provisioned live, every step 2xx. - unknown → 404
-
A1 pass:
showcase_reassign_wizard→ 200{status:'paused', runId, screen.nodeId:'collect'}, and that run was later resumed tocompleted. -
A2 pass: with
showcase_reassign_wizarddisabled,POST /api/v1/actions/showcase_task/showcase_bulk_reassign→ 409FLOW_DISABLED. Withshowcase_inquiry_purgedisabled, its type:'flow' endpointPOST /api/v1/apps/showcase/inquiries/purge→ 409. Through/actions, a no-start flow → 422. All three doors importclassifyFlowRefusal. -
A3 pass: the 400 carries
error.details.errorMessageanddetails.summaryat 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_UNAVAILABLEarm is blocked(fixture): no stock trigger reaches it, as the clause says. - missing screen input → 400
-
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/clienttrigger/executereject with httpStatus/code 404/400/409/422, andresumewith 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→ 409DELETE_RESTRICTED, naming callershowcase_task_done_notify_owner, ADR-0126 §7.3 and the remedy. - A1 pass: disabling map child
showcase_one_task_signoff→ 409 namingshowcase_release_signoff. - A2 pass: 0
sys_metadata_activationrows after the refusals. A caller-driven run completed, and itscall_notifysubflow 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 → 400VALIDATION_FAILEDnaming the missing field, and no clone is registered. - A1 pass: the key diff is exactly name, label,
status:'draft', plus the absence of_provenance,_packageIdand_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
- same name → 409
- 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/flowshows_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_DENIEDand 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 andactions:[], and it is listed.
- WARN
- 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 readsstate:'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/automationand 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. Withbu_west_coastdeactivated → [Ada, Contributor]. An unknown or inactive root warns "expanded to nobody" and goes to admin_rescue. - A2 pass:
pending_approversholds the two ids, and__resolvedFrom field:f_usersholds 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.
__resolvedFromrecordsadmin_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.
- absent / admin_rescue → pending [admin], the sole owner.
- 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/configreadsfeatures.twoFactor:trueandPOST /two-factor/enable {}→ 400. On the unarmed control, it readstwoFactor:falseand enable → 404. - A1 pass: enable → 200 with
method, totpURI, backupCodes. The URI isotpauth://totp/with labelObjectStack:admin@objectos.aiandissuer=ObjectStack. The secret is 52 base32 chars, which is 32 bytes.digits=6,period=30. - A2 pass:
backupCodesis astring[]of 10, shapedxxxxx-xxxxx. - A3 pass: the
sys_two_factor.enable_two_factorresultDialog paths resolve against the live response (string;string[]of 10). - A4 pass (recorded):
get-totp-urireturns 400 without a body, 400INVALID_PASSWORDfor 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_factordeclares 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-totp200;verifiedwent from 0 to 1, andtwo_factor_enabledis 1). - A1 pass: the challenge sign-in returns
{twoFactorRedirect:true, twoFactorMethods:['totp']}and sets onlybetter-auth.two_factor;get-sessionmid-challenge is 401. A backup code → 200, thenget-session200. - 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_codesis 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_codesdeclares a code-list, the acknowledge text andrefreshAfter: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_PASSWORDwith 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
twoFactorRedirectand onlysession_token. - A4 pass:
- A retained code with no cookie → 401
INVALID_TWO_FACTOR_COOKIE; on a live session → 400BACKUP_CODES_NOT_ENABLED. - Re-enable gives a new secret with no overlap.
- An old-secret TOTP → 401
INVALID_CODEon both lanes; a new-secret TOTP → 200.
- A retained code with no cookie → 401
- A5 pass (recorded), with
mfa_requiredon:- Disable → 200, not refused.
mfa_required_atis stamped lazily on the next request (a fresh 7-day grace).- With grace 0, a data read → 403
MFA_REQUIREDandget-sessioncarriesauthGate, while/two-factor/enableandverify-totpstay 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 scopeorg.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→ 403NOT_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_missingandperm_and→ 403 for all personas, andperm_empty→ 200 for all.
- A2 pass: a scratch app declaring
manage_userspassesos validateandos build(both exit 0). The boot then stops withSecurity catalog name conflict … "manage_users" is already held by the platform, and nothing listens. - A3 pass:
scope:'galaxy'makesos validateexit 1, naming the path and the allowed values.PUT /meta/capability/NEW→ 403NOT_CREATABLE.PUTon a platform or package capability → 403NOT_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_organizationrecord whose id equalsget-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_adminandownerare accepted. - A2 pass:
guest,contributorandshowcase_ops→ 400ROLE_NOT_FOUNDon 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_ORGANIZATIONon get-full-organization and set-active. The member's sessions readrevoke_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→ 王芳, andhuaning/hnkj→ 华宁科技. - A1 pass: the Latin-named contact at 华宁科技 is not found by
hnkjorhuaningkeji(0), while华宁科技finds 4 via the source column. - A2 pass (OFF, explicit
false):zw,wfandhnkj→ 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=zwshowed only 张伟.
i18n.strict-translation-key-rejection
- A0 pass: all 10 variants → 422
INVALID_METADATAviaPUT /api/v1/meta/translation/zh_cn_qa. Eachissues[]entry names the surface and echoes the key. - A1 pass:
defineTranslation(/system) anddefineTranslationBundle(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-levellocale. - 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/actionsrow 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:successstep. A budget reject ends rejected, and its run has noneeds_execstep. - A2 pass: revise sets status
returned, and the run is paused atwait_revision:approval_revise. - A3 pass: the submitter's resubmit opens a new pending request on the same
flow_run_idandflow_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=pendinglists 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" (
$recordcannot be assigned). - An api-hook approval on a
tenancy:{enabled:false}object still stamps the default organization.
- A schedule-triggered approval binds but fails with "no target object in context" (
- 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_remindersteps. - A1 pass:
guard_remindersteps carry{parentNodeId:loop_tasks, regionKind:loop-body}with iterations 0, 1 and 2.send_remindersteps 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/actionsreturns 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
endstep 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
parentNodeIdandregionKind. -
A5 pass: the
bogus_nodeflow saves 200 and a WARN namesunknownTypes:['bogus_node']. Its trigger → 400FLOW_FAILED"No executor registered", and the step error code isNO_EXECUTOR. -
N0 pass.
automation.flow-error-handling
- A0 pass: the resilient-sync run completes and its try_catch step reads success.
- A1 pass: the
pushattempts (regionKind try, parentguarded_push) fail withNODE_FAILURE"http: fetch failed", and all come before the catch steprecord_failure. - A2 pass:
retryAttemptruns 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=failedwith thesync_errortext. - A4 pass: an unprotected probe flow's run reads
failedwith 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.mdxnames the same 29, with 0 missing in either direction. - 63 known-answer rows cover all 29 functions, with 0 failures.
- The source chain registers 29 functions, and
- A1 pass:
today()pinned to Asia/Shanghai gives that zone's midnight. UTC, and the invalid zoneNot/AZone(no throw), give the UTC day.daysFromNowanddaysAgoagree. - A2 pass:
addMonths(2026-01-31, 1)= 2026-02-28.floor(-1.2)= -2 andceil(-1.2)= -1, both int.joinNonEmptyover fields gives 'a-b'.coalesce('', 'x')= '', andcoalesce(null, 'x')= 'x'.- min/max keep their type.
- A3 pass:
amount/100with amount 250 gives 2.5 (double), and7/2gives 3 (int). - A4 pass, live: stock
budget_remaining= 102000. A scratch formulaupper(joinNonEmpty(…))reads "ALPHA-GAMMA" in the 201 response and on a later GET. - A5 pass:
- The active PUT with
sqrt(4)→ 422INVALID_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:
floorsaves and evaluates.
- The active PUT with
- N0–N2 pass.
integration-system.notify-inbox-delivery
- A0 pass: after a reassign to a minted assignee, the assignee's
GET /notificationsliststask.assignedwith 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=falsedrops from 2 to 1, and the receipt row flips delivered → read.read/all→ 0 unread, and both receipts readstate=read. - A3 pass: anonymous → 401. On a scratch app-todo with
--preset minimal(no MessagingServicePlugin), GET,readandread/all→ 501NOT_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_groupsmaps admin→manager and Ada→finance, anddecision_progressreads 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 readsgot 1 need 1 satisfied:trueand 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:
/actionsreads submit, approve (admin), approve (Ada), bothvia_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 givesapproved. - 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 viareturn_to_draft, and the report readsdraft. A later approve → 409INVALID_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_requestrecord 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 showsapproved. 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
donegoes from false to true. - record_more: Recalculate Selection →
POST /api/v1/apps/showcase/recalc200, andestimate_hoursgoes 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=….
- list_toolbar with a row selected:
-
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
donestays 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 → 200restored: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→ 200readCount: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.
-
The aggregate door answers wrong data under 200 in three shapes (silent coercion, medium):
dateGranularityon 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. -
POST /api/v1/data/OBJECT/query {"aggregations":[]}answers 404OBJECT_NOT_FOUND"Object … is not registered" for a registered object (low). Seen besideapi-backend.aggregate-contract-matrix. -
The resume door ignores the flow name in its path (low).
POST /api/v1/automation/OTHER_FLOW/runs/RUNID/resumecompletes another flow's paused run, andGETwith the wrong name reads it too. Authority is still identity-based: a member's 403 held, so this is not an authorization defect. Seen besideautomation.trigger-status-contract. -
The trigger door drops a non-object
paramsand dispatches anyway (low).{"params":"oops"}runs with an empty bag, while the resume door refuses the same shape with 400. Seen besideautomation.trigger-status-contract. -
A translation item accepts any
localestring (low to medium).PUT /api/v1/meta/translation/NAMEwithlocale: 'not a locale!!'→ 200 with_diagnostics.valid:true.LocaleSchemais a barez.string(). Seen besidei18n.strict-translation-key-rejection.
Low, not extracted:
organization/update-member-rolewithrole:''answers 400 with an empty body (no code), where every other refusal on that door has one.POST /api/v1/apps/showcase/recalcwith an empty or unknownrecordIdanswers 400FLOW_FAILEDcarrying the flow internals (showcase).- The Send reminder dialog shows a generic subtitle (
approval_reminddeclares no description). - The stock member is offered Mark Done and gets 403 (the showcase action declares no
requiredPermissions). GET /api/v1/notificationsignores unknown query keys. One runner read this as the [approvals]assignedToMe=trueis not a supported list filter on/api/v1/approvals/requests— silently ignored, returns every request #7527 shape; another found it documented (GET /api/v1/notifications 从不解析它声明的请求 schema ——cursor被静默丢弃(SDK 分页永远第一页),limit默认 20 声明 vs 50 实现 #6361). It is not filed, pending that reading.- A non-participant gets 404 on
GET /approvals/requests/IDbut 200[]on…/actions. Nothing leaks.
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
/actionsand an endpoint, but no stock flow is reachable from all three doors. - The runner used
showcase_reassign_wizardwithshowcase_bulk_reassign, andshowcase_inquiry_purgewith its endpoint. - The
/actions400 and 422 rows need a type:'flow' action. The recipe could addPUT /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 409RESOURCE_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 compileacceptstransport.kind:'carrier_pigeon'; only the boot refuses it.
approvals.approver-resolution-matrix
- The suggested fallback,
org_membership_levelowner, does not discriminate on stock, because the owner is the sole admin. Use{type:'user', member}instead.
automation.packaged-flow-clone-contract
- For
{}, A0'sdetailsnames only the first missing field.
api-backend.aggregate-contract-matrix
- The analytics: the in-memory date bucket shifts a timezone-naive
Field.dateone day EARLIER under any negative-offsettimezone(America/New_York → 2026-10-01 buckets as 2026-09-30), so it disagrees with the SQL pushdown path #24618 negative-offset shift no longer reproduces; the item text can say it is fixed.
i18n.strict-translation-key-rejection
- The steps' conventional item name
zh-CNis refused first by the item-name rule (400INVALID_REQUEST). Name a snake_case item, and score the 422INVALID_METADATA. - The
translation.zod.tsnamecomment still callszh-CNthe convention. - A5 should say the singular label shows on the record-page badge and the New dialog, while the list header and nav read
pluralLabel. - A3 cites "清空剩余 6 条 authorWarn 死键 —— book ×2 / job.id / translation.validationMessages / app.homePageId / app.areas[].order(ADR-0049,v17 限时) #4667/ADR-0049", but the live text cites ADR-0049 and spec 17.0.0.
access-security.capability-declaration-lifecycle
- step 8 expects
capabilities.0.scope, but the index is the entry's position (.2when 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 devboots from the prebuiltdist/objectstack.json. WithOS_PORT=41302exported,GET /api/v1/meta/connector/showcase_status_apistill answersbaseUrl http://127.0.0.1:3000. Yet liveconnector_actionreached 41302:ping.bodyuptime 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
revisethenreject.
- api-backend.formula-stdlib-matrix steps[5] / requires[1]: a scratch object without
sharingModelgets 422security-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_requestrecord 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.
- A3.verify says end nodes log no step, but the approve branch now logs
- approvals.quorum-m-of-n: A2 says the reject edge is unobservable, but the run logs
return_to_drafton 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 /automationPUT/DELETE/trigger/resume/toggle/clone- connector dispatch
- approvals POST family and list
- two-factor family
/searchand 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_adminagainst 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
objectstack-fleet commentedon Oct 25, 2026
Close-out for this record.
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:
cursor被静默丢弃(SDK 分页永远第一页),limit默认 20 声明 vs 50 实现 #6361).#25626 (Create User) merged at 15:24Z, after this subject was fixed.
identity-auth.admin-lifecycle-operationsis being run on17f8217bas its own record, which will be linked here.objectstack-fleet commentedon Oct 25, 2026
Addendum: #25626 merged at 15:24Z.
identity-auth.admin-lifecycle-operationswas then run on17f8217band 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.