You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
17.6.0 release verification run: the standing P0 smoke plus the 23 checklist items most exposed to 17.6.0's changes, against the 17.6.0 release build. Text only; the durable truth stays in docs/qa/platform-checklist/areas/.
Environment fingerprint
Framework (subject):objectstack-ai/objectstack617f25f8 (chore: version packages (#20639)), the commit @objectstack/*@17.6.0 was published from (tags @objectstack/<pkg>@17.6.0). Built in a dedicated worktree: pnpm install --frozen-lockfile && pnpm build → Tasks: 72 successful, 72 total.
Console: objectui pin .objectui-sha = 31971ff1e28f, built by pnpm objectui:build under Node v22.22.2 (the container's v22.22.0 is below the pinned objectui's jsdom engine floor; environment note). packages/console/dist/.objectui-sha = the pin. Single-zod canary over the shipped assets: exactly one zod version literal {major:4,minor:6,patch:5} (2450 files read). Spec-injection check: the bundle carries this tree's @objectstack/spec only.
Checklist: items, RUNNER.md and scripts/checklist-select.mjs taken from main at 393ae878; the revision of every item run is recorded below.
App / boots:examples/app-showcase, OS_PORT=<p> objectstack dev --ui --seed-admin -p <p> -d file:/tmp/qa1760/<lane>/<item>.db — one file DB and one port per item, lanes on disjoint ranges 41000–42199 with the egress proxy port 41333 excluded. Banner Seeds: com.example.showcase 132 rows; Flows: 30 flow(s) 20 bound … 7 draft. Members minted by admin invite-member + sign-up/email (stock audience posture invite_only), identity proved by GET /auth/get-session before each persona cell.
Execution: 9 parallel runner subagents (L1–L9) + 4 independent verifiers (V1–V4, RUNNER rule 7), Claude Code session session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-02 03:55–05:25Z. Environment prep ≈ 30 min (framework build 7m40s, console build ≈ 15 min); per-lane runner time 14–41 min, of which 4–8 min env prep each.
Scope
One record for one release-verification selection, by maintainer direction: priority:P0 (node scripts/checklist-select.mjs priority:P0 --json → 19 runnable) + 23 named 17.6-risk items = 42 items. Hidden as blocked (not run): access-security.no-active-org-session-semantics. Planned (not run, not counted):records-forms.picklist-shared-across-objects, records-forms.picklist-org-append — see "Checklist-accuracy findings".
Totals: 30 PASS / 3 PARTIAL / 9 FAIL / 0 BLOCKED / 0 NOT-RUN. Of the 9 fails, 4 are product defects (2 of them on P0 items, both already tracked) and 5 are checklist clauses that 17.6.0 or earlier design deliberately contradicts. Every P0 fail and every new product-defect candidate was re-derived by an independent verifier from a fresh reproduction.
FIXED by c6954d6 (#21133) — both #21056 bodies now 400 DATASOURCE_ADMIN_ERROR naming config.url / config.username
F5
approvals.account-app-entry · A7
fail (objectui#11326)
STILL FAILING at the pin — now English on every path, SPA included; fixed upstream in objectui d0fba91aa, which is not an ancestor of 31971ff1e28f (verifier V4)
F6
studio-authoring.first-run-loop · A1
fail (objectui#11327)
FIXED by the pin (one zod instance, objectui#11353) — the New package dialog renders all fields and POST /api/v1/packages → 201
Per-clause verdicts
Clauses are numbered A1..An (acceptance) and N1..Nn (negative) in array order. Evidence is server truth unless it says screenshot.
P0
access-security.rls-both-sides (rev 5) — PASS
#
verdict
evidence
A1
pass
member A lists exactly A's two notes, B exactly B's one (2 runs)
A2
pass
foreign by-id GET → 404 RECORD_NOT_FOUND both ways
anonymous POST and GET on /data/showcase_inquiry → 401 before and after binding guest → showcase_guest_portal; 17.6.0's deny baseline gives anonymous callers no channel to a permission set until #21158; the public-form lane still answers 201
A7
pass
164 pin cells + 24 delegate sys_* cells, one verdict each
N1–N2
pass
admin payload controls 201; no withheld cell answered 2xx
access-security.owd-sharing-matrix (rev 3) — PASS
#
verdict
evidence
A1
pass
private: B list excludes, by-id 404, PATCH 403 unchanged; owner 200
A2
pass
public_read: B lists + reads 200, PATCH 403 unchanged
A3
pass
ops (modifyAll) PATCH of foreign announcement 200
A4
pass
public_read_write: contributor PATCH 200; member 403
A5
pass
controlled_by_parent: list excludes, by-id 404, PATCH 403; owner 200
15 inline-credential shapes refused at all three doors (build exit 2 / POST /datasources 400 / PUT /meta 422); every refusal names external.credentialsRef
A2
blocked(environment)
credentialsRef shapes publish (build + admin door 201); "connects" unprovable — no real Postgres / Mongo in the sandbox
A3
pass
0 planted values across every admin-door and meta-door body
A4
pass
hasSecret / redactedConfigKeys distinguish set from unset
A5
pass
legacy alias rows (planted with the server stopped) redacted on both doors
A6
pass
unknown driver's password / authToken absent on read
A7
pass
echoed redacted config preserves the stored credential
A8
pass
member 403 on every read door incl. external_catalog and sys_secret; anonymous 401
N1
pass
0 planted values
N2
pass
fixed since #21056: both mongo pairings → 400 DATASOURCE_ADMIN_ERROR naming config.url / config.username
Setup 45/45 and Account 8/8 render for admin; Browse Marketplace catalog content blocked(environment) — named "Failed to load marketplace · Forbidden" (egress to cloud.objectos.ai denied)
A2
pass
all 9 Setup groups; ?id=studio → items []
A3
pass
member: Setup → "This app can't be opened"; Account opens
A4
pass
member meta/app?id=setup → items []
A5
pass
Account nav 8 vs 8
A6–A7
pass
gated / off-capability entries absent as specified
records-forms.crud-roundtrip (rev 8) — PARTIAL
#
verdict
evidence
A1
pass
form create → 201, read back verbatim
A2
pass
PATCH changes only annual_revenue (+ updated_at)
A3
pass
delete 200; filtered 0; by-id 404
A4
pass
list reflects each mutation after full reload
A5
pass
History shows CREATE and UPDATE with option labels and the real actor
A6
pass
CJK name round-trips byte-exact; $search=华宁 finds it
A7
pass + blocked(fixture)
clone → new id, values copied, autonumber / formula re-derived, cloner owns; readonly-column half unobservable on the stock seed
A8
pass
clone of an RLS-invisible source → 404 RECORD_NOT_FOUND; admin count unchanged
Approve → 200; tally 0/2 → 1/2, persona dropped from pending
A5
pass
?request= cold load opens the drawer
A6
pass
record link keeps the com.objectstack.account segment
A7
fail
zh-CN selected: nav 待我审批 (server-served), but h1 "Approvals Inbox", tabs "My Pending / Submitted by me / All", badge "Pending" on every path; only i18n-locale-en-*.js fetched
N1–N2
pass
inbox rendered every load; Setup absent
studio-authoring.first-run-loop (rev 3) — PASS
#
verdict
evidence
A1
pass
fixed since #21056: New package dialog renders Display name / Package ID / Object namespace / Version / Type / Description; Create → POST /api/v1/packages 201, same document
A2
pass
published object served with exactly the 3 authored status options
A3
pass
Records grid add → row in GET /data/repairs_repair_ticket
A4
pass
app in the launcher; list shows the label chip, not the raw value
A5
pass
one "Server is ready", one PID throughout
A6
pass
authoring into the read-only package → 422 WRITABLE_PACKAGE_REQUIRED / 403 NOT_OVERRIDABLE / 403 ITEM_LOCKED; nothing stored
N1–N2
pass
no silent acceptance; labels not raw values
17.6-risk items
access-security.fls-mask-and-strip (rev 3) — PASS
#
verdict
evidence
A1
pass
contributor PATCH name → 200, persisted
A2
pass
contributor PATCH budget → 403 "Field write denied … [budget]"; value and updated_at unchanged
login row (actor = member, sys_session) and config_change row served; the admin's delete row → 0 rows on the data API, although stored with correct attribution in the telemetry DB — 17.6.0 30c530e5 (#21194)
A2
pass
/apps/setup/system/audit-log: page rows equal the API rows
A3
pass
Action select config_change re-issues GET …/sys_audit_log?$filter={"action":"config_change"}
A4
pass
drawer shows separate Before / After JSON panels (checked on an update row — no delete row is reachable in 17.6.0)
A5
pass
page ↔ API reconcile both directions
A6
pass
POST / PATCH / DELETE → 405 OBJECT_API_METHOD_NOT_ALLOWED; nothing forged
N1–N2
pass
every event wrote a row; writes refused
access-security.public-form-intake (rev 2) — FAIL
#
verdict
evidence
A1
pass
anonymous GET /api/v1/forms/contact-us → 200 with exactly name/email/company/message
A2
pass
forged owner/org/created_by never land
A3
pass
forged status / source → landed new / web
A4
pass
anonymous submit 201, row persisted (17.6.0's deny baseline does not reach this route)
A5
pass
GET /forms/contact-us/lookup/owner_id → 404 ENDPOINT_NOT_FOUND
string / number / boolean / null / ISO date strings answer the local computation; bigint and Date by pin
A2
pass
object comparand → 400 quoting the accepted types; no rows
A3
pass
pin: a bigint beyond ±2^53 is refused (REST not applicable, as the item records)
A4
pass
relation / virtual / scalar dotted heads → 400 INVALID_FIELD with the class prescription
A5
fail (stale)
POST /query → 400 VALIDATION_FAILED at query.where.f_number.$eq; GET $filter and the engine → 400 INVALID_FILTER — the #20116 door split (cfc3bcf1#20247, dd1b8031#20325), same as query-contract-matrix rev 3
all 13 presets: macro query = literal-window query = local computation (clock 2026-10-02 UTC recorded first; boundaries checked on both sides)
A2
pass
13 discriminating rows
A3
fail (assertion)
bare {"signed_on":"today"} (the step-5 example) → 400 INVALID_FILTER with the temporal-door message, not bareDateRangePresetComparandMessage; the preset message appears only in ordering positions ($gte:"this_week" → 400 VALIDATION_FAILED with it) — by design (18.filter-preset-ordering-comparand-refused.ts); the guarded failure (200 with zero rows on a date field) never occurs
none / map / constant / split / join each produce the expected row values
A2
fail (stale)
javascript mapping → 400 UNSUPPORTED_TRANSFORM naming the missing server-side sandbox, 0 rows — but the message no longer names framework#2611: f115b1f (#21188) states the decision in words
A3
pass
lookup resolves the id; unknown name fails its row reference_not_found
A4
pass
JSON through a csv mapping → 400 MAPPING_FORMAT_MISMATCH; xlsx accepted
missing name / label → 400 VALIDATION_FAILED; nothing created
A2
pass
clone differs from source only in name / label / status: draft; no ancestry keys
A3
pass
clone bound as draft; both flows fire once per urgent create; notice = FLOW_CLONE_NOTICE
A4
pass
same-name 409; unknown source 404; bad name 400; unknown body key 400
A5
pass
subflow reference preserved
A6
pass
PUT /automation/<clone> 200, persisted
A7
fail
durability half now PASSES (cold restart: GET 200, still fires — cb4c31d#20907); reachability half FAILS — no Studio rail lists the clone (verifier V2 confirmed)
automation.flow-toggle-kill-switch (rev 2) — PASS
#
verdict
evidence
A1–A4
pass
runs 0 → 1; off: 1 → 1; /_status flips both ways; on: → 2; unknown flow toggle 404
after publish the authored tab and form layout apply, no restart
A4
fail (assertion)
GET /meta/view?object=repair_asset serves the authored bodies as repair_asset.default / repair_asset.form; the container name never appears — the object door returns expanded items by design (expandViewContainer, #7163)
html pages render compiled static boards; react page binds live data (5 = /data total) and edits rows
A5
pass
OS_PAGE_REACT=off disables react pages with the named message; html pages still render
A6
pass
react fault → "React page error"; html fault → "HTML page failed to compile (3)" in the editor preview
Fails — reproduction rules and dispositions
Product defects:
R1 · access-security.crud-permission-matrix · A1 — product defect, already tracked at #21057 (fails closed: over-refusal, not an exposure). Verifier V1: CONFIRMED.
Fresh boot; admin invites + signs up a delegate D and a target T.
Admin POST /api/v1/data/sys_user_permission_set {"user_id":D,"permission_set_id":<id of showcase_field_ops_delegate>} → 201; POST /api/v1/data/sys_business_unit_member {"business_unit_id":"bu_field_ops","user_id":D} → 201.
D POST /api/v1/data/sys_user_position {"user_id":T,"position":"contributor","business_unit_id":"bu_west_coast"}.
Expected 2xx (adminScope = Field Operations + subtree). Actual 403 PERMISSION_DENIED "delegated 'insert' on sys_user_position rejected — business unit 'bu_west_coast' is outside the delegated subtree" — also for bu_field_ops itself. Admin with the identical payload → 201.
Mechanism oracle: every seeded sys_business_unit row reads organization_id: null; after admin PATCHes the active org onto the seeded units, D's create → 201 and an out-of-subtree create (bu_hq_finance) stays 403.
R3 · automation.packaged-flow-clone-contract · A7 (reachability half) — product defect, not previously filed (it was the FOLLOW-UPS §8 D18 row, marked "safe to file"). Verifier V2: CONFIRMED.
Admin POST /api/v1/automation/showcase_urgent_task_alert/clone {"name":"qa_urgent_alert_clone","label":"QA urgent alert clone"} → 200.
POST /api/v1/data/sys_metadata/query {"where":{"name":"qa_urgent_alert_clone"}} → package_id: null, scope: platform.
GET /api/v1/meta/flow?package=com.example.showcase → 30 flows without the clone; bare GET /api/v1/meta/flow → 31 with it.
Console /_console/studio → "No writable packages yet"; /_console/studio/com.example.showcase/automations lists the 30 packaged flows, not the clone; …?surface=flow%3Aqa_urgent_alert_clone redirects to another flow.
Expected (ADR-0126 §1.3 / §7.1, the Setup page's "Editing happens in Studio") the clone is listed on a Studio Automations rail; actual no Studio surface at the pin lists or opens a package-less flow (the rail is loadPackageSurfaces(client,'flow',packageId)).
R4 · approvals.account-app-entry · A7 — product defect in the console, objectui#11326, still present at the pin (fixed upstream in objectui d0fba91aa, not an ancestor of 31971ff1e28f). Verifier V4: CONFIRMED (the zh catalogue at the pin holds every expected string, so the clause is not stale).
Fresh boot; sign in; open /_console/apps/com.objectstack.account/component/approvals/inbox.
Avatar → Preferences → Language → 中文(中国); then a full load of the same URL.
Expected h1 / tabs / badge in Chinese (审批中心 · 待我审批 / 我发起的 / 全部 · 待审批). Actual "Approvals Inbox", "My Pending / Submitted by me / All", "Pending"; localStorage['objectui-locale']="zh-CN", <html lang="zh-CN">, the server-served nav label 待我审批; only i18n-locale-en-*.js fetched although i18n-locale-zh-*.js is in dist. Mechanism at the pin: packages/i18n/src/locales/registry.ts keys built-in loaders by base language, and the provider asks with the region-tagged code.
Checklist clauses (no product defect — the docs PR linked in the close-out re-points them):
R5 · access-security.audit-log-browser · A1 — stale clause. Admin DELETE /api/v1/data/showcase_task/<id> → 200; admin GET /api/v1/data/sys_audit_log?filter={"action":"delete"} → expected (clause) 1 row, actual total 0; the row is stored with correct attribution (direct read of the telemetry DB). Changed deliberately by 30c530e5 (#21194): the ledger serves a non-system reader, administrators included, only rows about records it can read (17.6 notes, "The compliance ledger and the activity stream…").
R6 · api-backend.filter-comparand-conformance · A5 — stale clause.POST /api/v1/data/showcase_field_zoo/query {"where":{"f_number":{"$eq":{"x":1}}}} → 400 VALIDATION_FAILED (fields[0].field = query.where.f_number.$eq); GET …?$filter={"f_number":{"$eq":{"x":1}}} → 400 INVALID_FILTER; engine door → INVALID_FILTER. Every door refuses with the same contract sentence and none returns rows; the code differs because #20116 moved the POST refusal into the request schema (cfc3bcf1#20247, dd1b8031#20325) — the split query-contract-matrix rev 3 already records.
R7 · api-backend.date-range-preset-matrix · A3 — assertion defect.POST /api/v1/data/showcase_account/query {"where":{"signed_on":"today"}} → 400 INVALID_FILTER with the temporal-door message; {"where":{"signed_on":{"$gte":"this_week"}}} → 400 VALIDATION_FAILED with bareDateRangePresetComparandMessage. The preset message is deliberately an ordering-position refusal (18.filter-preset-ordering-comparand-refused.ts: "Ordering positions only at the schema door"); an equality on a date field is refused by the temporal door. The guarded failure (200 with zero rows) does not occur.
R8 · records-forms.import-transform-matrix · A2 — stale clause.PUT /api/v1/meta/mapping/qa_l7_js with one entry transform:"javascript"; POST /api/v1/data/showcase_inquiry/import {"format":"csv",…,"mappingName":"qa_l7_js"} → 400 UNSUPPORTED_TRANSFORM naming the missing server-side sandbox, 0 rows; the message no longer names framework#2611 since f115b1f (#21188: refusals state each decision in words instead of a tracker number).
R9 · studio-authoring.view-authoring-live · A4 — assertion defect.PUT /api/v1/meta/view/qa_repair_asset_views?mode=draft&package=<writable pkg> with {name, object:"repair_asset", list, form}; publish; GET /api/v1/meta/view?object=repair_asset → repair_asset.default and repair_asset.form carrying the authored config; the container name appears 0 times. The object door returns expanded <object>.<key> items by design (expandViewContainer, #7163).
datasource-credential-refusal-matrix A2: no real Postgres / MySQL / Mongo in the sandbox (ECONNREFUSED).
crud-roundtrip A7 readonly half: no readonly column is settable over HTTP on the stock seed.
setup-packaged-automation-board A6: needs a persona with setup.access but without manage_metadata (e.g. organization_admin); a plain member never reaches Setup.
dashboards global-filters D2 needs a writable package (the showcase package is read-only in Studio; duplicate → 422 DUPLICATE_SOURCE_NOT_A_BASE).
Container memory (15 GB, 4 CPUs) was contended with 9 lanes: several vitest runs were SIGKILLed and Chromium renderers crashed until launched with --disable-dev-shm-usage; every affected run was repeated and its verdict rests on the repeat.
Killing a recorded pnpm wrapper PID leaves the objectstack dev child listening; teardown needs the process tree or the port's listener.
The showcase's dist/objectstack.json is converted forward on load at boot (ADR-0087 page-component-filter-record-to-rule-array) — harmless.
Close-out (extracted cards, checklist-accuracy findings, the docs PR) follows in a comment.
17.6.0 release verification run: the standing P0 smoke plus the 23 checklist items most exposed to 17.6.0's changes, against the 17.6.0 release build. Text only; the durable truth stays in
docs/qa/platform-checklist/areas/.Environment fingerprint
objectstack-ai/objectstack617f25f8(chore: version packages (#20639)), the commit@objectstack/*@17.6.0was published from (tags@objectstack/<pkg>@17.6.0). Built in a dedicated worktree:pnpm install --frozen-lockfile && pnpm build→Tasks: 72 successful, 72 total..objectui-sha=31971ff1e28f, built bypnpm objectui:buildunder Node v22.22.2 (the container's v22.22.0 is below the pinned objectui'sjsdomengine floor; environment note).packages/console/dist/.objectui-sha= the pin. Single-zod canary over the shipped assets:exactly one zod version literal {major:4,minor:6,patch:5}(2450 files read). Spec-injection check: the bundle carries this tree's@objectstack/speconly.RUNNER.mdandscripts/checklist-select.mjstaken frommainat393ae878; the revision of every item run is recorded below.examples/app-showcase,OS_PORT=<p> objectstack dev --ui --seed-admin -p <p> -d file:/tmp/qa1760/<lane>/<item>.db— one file DB and one port per item, lanes on disjoint ranges 41000–42199 with the egress proxy port 41333 excluded. BannerSeeds: com.example.showcase 132 rows;Flows: 30 flow(s) 20 bound … 7 draft. Members minted by admininvite-member+sign-up/email(stock audience postureinvite_only), identity proved byGET /auth/get-sessionbefore each persona cell.session_018zT8d8NpiQ1ExhuNd5TxY6, 2026-10-02 03:55–05:25Z. Environment prep ≈ 30 min (framework build 7m40s, console build ≈ 15 min); per-lane runner time 14–41 min, of which 4–8 min env prep each.Scope
One record for one release-verification selection, by maintainer direction:
priority:P0(node scripts/checklist-select.mjs priority:P0 --json→ 19 runnable) + 23 named 17.6-risk items = 42 items. Hidden as blocked (not run):access-security.no-active-org-session-semantics. Planned (not run, not counted):records-forms.picklist-shared-across-objects,records-forms.picklist-org-append— see "Checklist-accuracy findings".automated.ref, run from the subject tree)verify --rlsexit 0; private-owd 5/5; invoice-seed-isolation 12/12plugin.test.ts17/17showcase-smoke.spec.ts49 passed (4.8m)Totals: 30 PASS / 3 PARTIAL / 9 FAIL / 0 BLOCKED / 0 NOT-RUN. Of the 9 fails, 4 are product defects (2 of them on P0 items, both already tracked) and 5 are checklist clauses that 17.6.0 or earlier design deliberately contradicts. Every P0 fail and every new product-defect candidate was re-derived by an independent verifier from a fresh reproduction.
vs #21056 (2026-10-01,
ef1ed17f, Consoledb11afd4967c: 13 PASS / 6 FAIL)617f25f8, Console31971ff1e28f)99398542, #21104, in the subject tree); item PASSorganization_id: null(verifier V1 confirmed)c6954d6(#21133) — both #21056 bodies now400 DATASOURCE_ADMIN_ERRORnamingconfig.url/config.usernamed0fba91aa, which is not an ancestor of31971ff1e28f(verifier V4)POST /api/v1/packages→ 201Per-clause verdicts
Clauses are numbered A1..An (acceptance) and N1..Nn (negative) in array order. Evidence is server truth unless it says screenshot.
P0
access-security.rls-both-sides (rev 5) — PASS
verify --rls: per-persona21 PROVEN (21 consistent, 0 HOLES) · 3 NOT PROVEN; totalall personas: 38 PROVEN (38 consistent, 0 HOLES) · 226 NOT PROVEN;10 of 10 declared position(s) probed; CRUD tail15 verified, 0 gaps, 0 FAILED, 1 needs-fixture, 8 skippedaccess-security.write-path-guards (rev 3) — PASS
lead_score→ 201,x-objectstack-dropped-fields: lead_score;reason=readonly, stored nulllead_score:99→ 200, same header, null afterowner_id=<other>→ 403 "requires the transfer grant"; count 0owner_id= callerreason=readonly_when; mixed updateMany drops per row (results[0].droppedFields)options.continueOnError:true→ violating row VALIDATION_FAILED, compliant row persistedlead_score)access-security.crud-permission-matrix (rev 4) — FAIL
sys_user_positioncreate → 403 "outside the delegated subtree" (3 boots + verifier 2 boots)sys_business_unit,sys_business_unit_member,sys_permission_set,sys_position403;sys_usercreate/delete 405/data/showcase_inquiry→ 401 before and after binding guest →showcase_guest_portal; 17.6.0's deny baseline gives anonymous callers no channel to a permission set until #21158; the public-form lane still answers 201sys_*cells, one verdict eachaccess-security.owd-sharing-matrix (rev 3) — PASS
access-security.anonymous-deny-surfaces (rev 3) — PASS
_status, batch, security/explain, 3 analytics faces → 401 UNAUTHENTICATEDGET /api/v1/forms/contact-us→ 200ai.mcp-stdio-fail-closed (rev 4) — PASS
--log-level info: "principal-bound to OS_MCP_STDIO_API_KEY identity … (RLS/FLS/tenant applied)"api-backend.query-contract-matrix (rev 3) — PASS
$-object, POST AST, GET$filter) = the expected id sets over a 14-row baseline$top/$skipandlimit/offsetexact slices$select/fieldsexact keys; dottedaccount.name→ 400 INVALID_FIELD namingexpand$nin→ 400 VALIDATION_FAILED atquery.where.status.$nin(both spellings); GET → 400 INVALID_FILTER$pageSize→ 400 UNSUPPORTED_QUERY_PARAM; unknown field → 400 INVALID_FIELD$in []→ 0 rows;$nin []→ 14/14{"limit":"ten"}→ 400; undeclared key → 400 INVALID_FIELDapi-backend.packaged-action-disabled-dispatch (rev 3) — PASS
organization_idrun_actiondisabled → isError ACTION_DISABLED 409; re-enabled okautomation.packaged-flow-disable-durable (rev 2) — PASS
sys_metadata_activationrow, noorganization_idkey/_status {enabled:false, bound:false}; boot line (atOS_LOG_LEVEL=info) names it unboundplatform-core.seed-integrity (rev 3) — PASS
14:30:00, password masked)Seeds: com.example.showcase 132 rows, no dropped-record linecli.dev-boot-contract (rev 3) — PASS
/_console/login form; form sign-in →/_console/homewith cookie + token--admin-password changed99: old password 200, new 401-d,OS_DATABASE_URL,--database-driver memory, nothing-chosen (persists), legacydev.db(one notice, no empty sibling) each resolve as specified; config tier by pin--freshtempdir used, gone after SIGINT; #5594 carve-out survives↪ server bound to port 41532 (requested 41531); health 200 theredist/objectstack.jsonwarned with newest source + fix; bootsplatform-core.boot-health (rev 6) — PASS
{"status":"ok","version":"17.6.0"}in 38.7 s{"status":"ready","state":"running"}NOT bound — disabled by deployment policylines/_console/200 HTML; apps[showcase_app, setup, account]integration-system.datasource-credential-refusal-matrix (rev 2) — PARTIAL
POST /datasources400 /PUT /meta422); every refusal namesexternal.credentialsRefhasSecret/redactedConfigKeysdistinguish set from unsetexternal_catalogandsys_secret; anonymous 401config.url/config.usernameplatform-core.console-login (rev 4) — PASS
/_console/homelauncher; cookie + localStorage token (2 runs)meta/app200, no login redirectPOST /auth/sign-outthe old bearer → 401/_console/login?redirect=…platform-core.nav-surfaces-render (rev 5) — PASS
platform-core.builtin-apps-nav-render (rev 4) — PASS
cloud.objectos.aidenied)?id=studio→ items []meta/app?id=setup→ items []records-forms.crud-roundtrip (rev 8) — PARTIAL
annual_revenue(+updated_at)$search=华宁finds itapprovals.account-app-entry (rev 2) — FAIL
approvals:inboxregistration[showcase_app, account], inbox entry present?request=cold load opens the drawercom.objectstack.accountsegmenti18n-locale-en-*.jsfetchedstudio-authoring.first-run-loop (rev 3) — PASS
POST /api/v1/packages201, same documentGET /data/repairs_repair_ticket17.6-risk items
access-security.fls-mask-and-strip (rev 3) — PASS
updated_atunchangedbudget_remainingrecomputesselect,$selectall omit budget/spent/budget_remaining keys; filter / sort / cross-field{"$field":"budget"}→ 403 (17.6.0 #20954); console hides the Financials section; admin sees allaccess-security.record-access-explain (rev 2) — PASS
POST /security/explain→record:{visible:true, decidedBy:"vama_bypass"}visible:false, decidedBy:"sharing", no EXPLAIN_FAILEDmanage_users)access-security.audit-log-browser (rev 2) — FAIL (stale clause)
sys_session) and config_change row served; the admin'sdeleterow → 0 rows on the data API, although stored with correct attribution in the telemetry DB — 17.6.030c530e5(#21194)/apps/setup/system/audit-log: page rows equal the API rowsconfig_changere-issuesGET …/sys_audit_log?$filter={"action":"config_change"}access-security.public-form-intake (rev 2) — FAIL
GET /api/v1/forms/contact-us→ 200 with exactly name/email/company/messagenew/webGET /forms/contact-us/lookup/owner_id→ 404 ENDPOINT_NOT_FOUND/_console/f/contact-ussubmit → 201, "Thanks!" panel (screenshot)__proto__body inertaccess-security.packaged-flow-write-door-parity (rev 1) — PASS
PUT /meta/flow/showcase_urgent_task_alert→ 403 NOT_OVERRIDABLE (?package=→ 403 ITEM_LOCKED); unchangedPUT /automation/showcase_urgent_task_alert→ 403 NOT_OVERRIDABLE, same lock message — the item's "EXPECTED FAIL" is stale since4b45afae(#20817)DELETE /automation/…→ 403 NOT_OVERRIDABLE; GET still 200api-backend.filter-comparand-conformance (rev 2) — FAIL (stale clause)
Dateby pin/query→ 400 VALIDATION_FAILED atquery.where.f_number.$eq; GET$filterand the engine → 400 INVALID_FILTER — the #20116 door split (cfc3bcf1#20247,dd1b8031#20325), same as query-contract-matrix rev 3api-backend.aggregate-contract-matrix (rev 1) — PASS
count(field)skips nullsnullkeyarray_agg/string_agg→ 400 with the retirement text;median→ 400 enum; never 500api-backend.date-range-preset-matrix (rev 1) — FAIL (assertion defect)
{"signed_on":"today"}(the step-5 example) → 400 INVALID_FILTER with the temporal-door message, notbareDateRangePresetComparandMessage; the preset message appears only in ordering positions ($gte:"this_week"→ 400 VALIDATION_FAILED with it) — by design (18.filter-preset-ordering-comparand-refused.ts); the guarded failure (200 with zero rows on a date field) never occursdashboards.cube-query (rev 3) — PASS
/analytics/meta?cube=showcase_deliverylists the measures and dimensions (nodone_rate, as rev 3 expects)/datagroupBy = raw tallyfilters/query/formatbodies → 400 with their retirement hintsdashboards.dataset-report-authoring (rev 1) — PASS
dataset+valuesonly/dataSUM by status (244.0)/datagroupBy [status, priority]joinedblock type → 422; dangling dataset → publish 422dashboards.global-filters-rescope (rev 2) — PASS
/datacounts under the same filterskpi_awaiting_review) =/data(2 / 0)optionsFromlist from a server GROUP BYdashboards.strict-widget-rejects-stray-keys (rev 2) — PASS
chartFlavour→ 422 echoing the key; near-keys get did-you-meanrecords-forms.field-type-matrix (rev 2) — PASS
f_*field renders its own widgetrecords-forms.import-transform-matrix (rev 1) — FAIL (stale clause)
framework#2611:f115b1f(#21188) states the decision in wordsreference_not_foundrecords-forms.named-import-mapping (rev 1) — PASS
automation.packaged-flow-subflow-disable-refusal (rev 1) — PASS
36d043b#20724,0d9349f#20759)automation.packaged-flow-clone-contract (rev 1) — FAIL
status: draft; no ancestry keysFLOW_CLONE_NOTICEPUT /automation/<clone>200, persistedcb4c31d#20907); reachability half FAILS — no Studio rail lists the clone (verifier V2 confirmed)automation.flow-toggle-kill-switch (rev 2) — PASS
/_statusflips both ways; on: → 2; unknown flow toggle 404automation.setup-packaged-automation-board (rev 2) — PARTIAL
nav_packaged_automationentry; sidebar click lands on…/component/automation/packaged/meta/flowpackaged set; clone absentsetup.access)integration-system.datasource-admin-lifecycle (rev 3) — PASS
manage_platform_settingsPOST /testdraftok:true, nothing persistedalready-bound/migrated/refusedoutcomes, no 400splatform-core.metadata-authoring-roundtrip (rev 2) — PASS
_drafts; publish → served and rendered as a tabstudio-authoring.view-authoring-live (rev 1) — FAIL (assertion defect)
GET /meta/view?object=repair_assetserves the authored bodies asrepair_asset.default/repair_asset.form; the container name never appears — the object door returns expanded items by design (expandViewContainer, #7163)studio-authoring.custom-page-source-tiers (rev 1) — PASS
/datatotal) and edits rowsOS_PAGE_REACT=offdisables react pages with the named message; html pages still renderFails — reproduction rules and dispositions
Product defects:
R1 · access-security.crud-permission-matrix · A1 — product defect, already tracked at #21057 (fails closed: over-refusal, not an exposure). Verifier V1: CONFIRMED.
POST /api/v1/data/sys_user_permission_set {"user_id":D,"permission_set_id":<id of showcase_field_ops_delegate>}→ 201;POST /api/v1/data/sys_business_unit_member {"business_unit_id":"bu_field_ops","user_id":D}→ 201.POST /api/v1/data/sys_user_position {"user_id":T,"position":"contributor","business_unit_id":"bu_west_coast"}.403 PERMISSION_DENIED "delegated 'insert' on sys_user_position rejected — business unit 'bu_west_coast' is outside the delegated subtree"— also forbu_field_opsitself. Admin with the identical payload → 201.sys_business_unitrow readsorganization_id: null; after admin PATCHes the active org onto the seeded units, D's create → 201 and an out-of-subtree create (bu_hq_finance) stays 403.R2 · access-security.public-form-intake · A7 — product defect. Detail withheld pending maintainer (RUNNER rule 2). Verifier V1: CONFIRMED.
R3 · automation.packaged-flow-clone-contract · A7 (reachability half) — product defect, not previously filed (it was the FOLLOW-UPS §8 D18 row, marked "safe to file"). Verifier V2: CONFIRMED.
POST /api/v1/automation/showcase_urgent_task_alert/clone {"name":"qa_urgent_alert_clone","label":"QA urgent alert clone"}→ 200.POST /api/v1/data/sys_metadata/query {"where":{"name":"qa_urgent_alert_clone"}}→package_id: null, scope: platform.GET /api/v1/meta/flow?package=com.example.showcase→ 30 flows without the clone; bareGET /api/v1/meta/flow→ 31 with it./_console/studio→ "No writable packages yet";/_console/studio/com.example.showcase/automationslists the 30 packaged flows, not the clone;…?surface=flow%3Aqa_urgent_alert_cloneredirects to another flow.loadPackageSurfaces(client,'flow',packageId)).R4 · approvals.account-app-entry · A7 — product defect in the console, objectui#11326, still present at the pin (fixed upstream in objectui
d0fba91aa, not an ancestor of31971ff1e28f). Verifier V4: CONFIRMED (the zh catalogue at the pin holds every expected string, so the clause is not stale)./_console/apps/com.objectstack.account/component/approvals/inbox.localStorage['objectui-locale']="zh-CN",<html lang="zh-CN">, the server-served nav label 待我审批; onlyi18n-locale-en-*.jsfetched althoughi18n-locale-zh-*.jsis in dist. Mechanism at the pin:packages/i18n/src/locales/registry.tskeys built-in loaders by base language, and the provider asks with the region-tagged code.Checklist clauses (no product defect — the docs PR linked in the close-out re-points them):
R5 · access-security.audit-log-browser · A1 — stale clause. Admin
DELETE /api/v1/data/showcase_task/<id>→ 200; adminGET /api/v1/data/sys_audit_log?filter={"action":"delete"}→ expected (clause) 1 row, actual total 0; the row is stored with correct attribution (direct read of the telemetry DB). Changed deliberately by30c530e5(#21194): the ledger serves a non-system reader, administrators included, only rows about records it can read (17.6 notes, "The compliance ledger and the activity stream…").R6 · api-backend.filter-comparand-conformance · A5 — stale clause.
POST /api/v1/data/showcase_field_zoo/query {"where":{"f_number":{"$eq":{"x":1}}}}→ 400VALIDATION_FAILED(fields[0].field = query.where.f_number.$eq);GET …?$filter={"f_number":{"$eq":{"x":1}}}→ 400INVALID_FILTER; engine door → INVALID_FILTER. Every door refuses with the same contract sentence and none returns rows; the code differs because #20116 moved the POST refusal into the request schema (cfc3bcf1#20247,dd1b8031#20325) — the split query-contract-matrix rev 3 already records.R7 · api-backend.date-range-preset-matrix · A3 — assertion defect.
POST /api/v1/data/showcase_account/query {"where":{"signed_on":"today"}}→ 400INVALID_FILTERwith the temporal-door message;{"where":{"signed_on":{"$gte":"this_week"}}}→ 400VALIDATION_FAILEDwithbareDateRangePresetComparandMessage. The preset message is deliberately an ordering-position refusal (18.filter-preset-ordering-comparand-refused.ts: "Ordering positions only at the schema door"); an equality on a date field is refused by the temporal door. The guarded failure (200 with zero rows) does not occur.R8 · records-forms.import-transform-matrix · A2 — stale clause.
PUT /api/v1/meta/mapping/qa_l7_jswith one entrytransform:"javascript";POST /api/v1/data/showcase_inquiry/import {"format":"csv",…,"mappingName":"qa_l7_js"}→ 400UNSUPPORTED_TRANSFORMnaming the missing server-side sandbox, 0 rows; the message no longer namesframework#2611sincef115b1f(#21188: refusals state each decision in words instead of a tracker number).R9 · studio-authoring.view-authoring-live · A4 — assertion defect.
PUT /api/v1/meta/view/qa_repair_asset_views?mode=draft&package=<writable pkg>with{name, object:"repair_asset", list, form}; publish;GET /api/v1/meta/view?object=repair_asset→repair_asset.defaultandrepair_asset.formcarrying the authored config; the container name appears 0 times. The object door returns expanded<object>.<key>items by design (expandViewContainer, #7163).Fixture gaps and environment notes
guestanchor; ADR-0090 D9 is declared and seeded but not enforced #21158 gives anonymous callers a permission-set channel (17.6.0 deny baseline); the reason is a dependency, not a fixture.ECONNREFUSED).setup.accessbut withoutmanage_metadata(e.g.organization_admin); a plain member never reaches Setup.duplicate→ 422 DUPLICATE_SOURCE_NOT_A_BASE).cloud.objectos.ai(marketplace catalog).--disable-dev-shm-usage; every affected run was repeated and its verdict rests on the repeat.pnpmwrapper PID leaves theobjectstack devchild listening; teardown needs the process tree or the port's listener.dist/objectstack.jsonis converted forward on load at boot (ADR-0087page-component-filter-record-to-rule-array) — harmless.Close-out (extracted cards, checklist-accuracy findings, the docs PR) follows in a comment.
Generated by Claude Code