Skip to content

QA run · #32940 round-1 FAIL items (11/11) · 8e3d4a54 · 2026-11-13 · 8 PASS / 0 PARTIAL / 3 FAIL / 0 BLOCKED / 0 NOT-RUN #33089

Closed

Description

@objectstack-fleet

qa#3 · os-tesla · session_01L9qibw6yXcLi9aRRBpPT4W

Slice A-R1F of qa#3's round 2 part A at 8e3d4a5: round 1's 11 FAIL items of #32940, re-judged at their current revisions.

Environment fingerprint

  • Framework objectstack-ai/objectstack main @ 8e3d4a54, the same tree, build and console as record-A-P0. Tier 1 pins at this sha all green (3,403 tests, 0 failed; record-A-P0).
  • Boots objectstack dev --ui --seed-admin --no-compile --no-watch on ports 41271–41277, each stopped by process group. Installs, the interceptor config change, the deploy target and the namespace-collision packages all ran from scratch copies under /tmp/qa3/A/ar1f/ws/examples; the interceptor copy was compiled once inside itself, then booted --no-compile. cli.deploy-runtime-dry-run-json ran with an isolated HOME= (use-runtime writes ~/.objectstack/cloud.json). Browser legs in 2 fresh contexts.
  • Timestamps (UTC): one runner, 09:50–10:18 (setup ≈10 min, test ≈18 min).

Scope

Round 1's 11 FAIL items of #32940, at the resolver's current revisions: multi-currency-invoice 2 · home-amount-preview-states 1 · mcp-tool-call-interceptor 1 · dataset-member-vocabulary 1 · mcp-read-file-pdf-word-extraction 2 · deploy-runtime-dry-run-json 2 · namespace-co-owner-name-refusal 4 · namespace-object-name-refusal 2 · actions-namespace-address 3 · bare-name-one-holder-refusal 3 · permission-set-address-in-execution-context 3. None is in record-A-P0; permission-set-address-in-execution-context was briefly listed under A-FIX and is judged here.

Derived item verdicts

verdict items (round 1 → now)
FAIL (3) records-forms.multi-currency-invoice (A5, still #32941) · records-forms.home-amount-preview-states (A0, still #32941; A1–A3 blocked(product-bug) by it) · platform-core.bare-name-one-holder-refusal (A0, A3 — stale spec again, re-point card card-A-1.md)
PASS (8) ai.mcp-tool-call-interceptor (stdio leg 2/2 — see the probe on #32942) · studio-authoring.dataset-member-vocabulary (fixed by #33022, 83bd36d — #32943 can be verified closed) · ai.mcp-read-file-pdf-word-extraction · cli.deploy-runtime-dry-run-json · platform-core.namespace-co-owner-name-refusal · platform-core.namespace-object-name-refusal · api-backend.actions-namespace-address · access-security.permission-set-address-in-execution-context (the last six as re-pointed by #32965 / #33021)

Fails — reproduction rule and disposition

records-forms.multi-currency-invoice · A5 and records-forms.home-amount-preview-states · A0 — product defect, existing card #32941 (open, no fix PR). Fresh stock boot, admin signed in through the form, INV-1004 → Edit: [data-testid=home-amount-preview] count 0 (expected 1, converted state); "Total incl. Tax" is plain text "€450.00"; switching to JPY and 01/15/2026 → "¥450", still no preview and no rate request. Reproduced in 2 fresh contexts. Mechanism unchanged since round 1: the expression-computed amount is readonly and CurrencyField.tsx:64 returns before HomeAmountPreview at :227. The detail page's "Converted at 0.9 on Nov 13, 2026" hint is correct. A contributor-bound member gets no preview either (amount "—", their own rate read 403).

platform-core.bare-name-one-holder-refusal · A0, A3 — stale spec, re-point card card-A-1.md. Two namespaces (qa_a, qa_b) both holding webhook qa_hook: both installs exit 0, the package-less GET /api/v1/meta/webhook/qa_hook answers 409 naming both, and a cold boot of a packages[] stack with both holders logs no webhook warning; rev 3 expects the second install refused 422 and one boot warning. #32577 (e55347d, 05:13Z) put webhook into the namespace-scoped bare-name set an hour after #32965 (cf1b55c, 04:04Z) re-pointed the clause to webhook. Control with tool: the install is refused 422 PLUGIN_REGISTER_FAILED naming the holder and the rename, and the cold boot logs exactly one "Bare-name conflict at boot" warning, for the tool. Round 1 (#32940 F-10) failed the same way on flow.

Off-clause probes (rule 8)

Per-item minutes and doors are in the probe log (record-A-R1F-clauses-1.md). No new product defect.

Parked-on #32908

Fixture notes: cli.deploy-runtime-dry-run-json should tell runners to isolate HOME (use-runtime writes the shared ~/.objectstack/cloud.json); a package declaring a webhook needs requires: ['webhooks','realtime'] or objectstack build refuses it; the only seeded USD draft (INV-1002) is re-currencied to EUR by multi-currency step 2, so preview-states should not run after it on the same DB.

Per-item checklist-accuracy notes follow.

records-forms.multi-currency-invoice

  • Seed thin: only INV-1004 (EUR) and INV-1008 (JPY) carry a non-zero amount among the foreign invoices; the other three foreign rows prove only the rate choice (0 ÷ rate = 0).

records-forms.home-amount-preview-states

  • (from the earlier browser-slice run, still applicable) A2's expected string spells the date ISO ("2024-06-01"); where the preview does mount (a scratch editable record-mode amount) the product renders "Jun 1, 2024". Not re-driven here.
  • S0 names "a USD draft invoice"; the only USD draft seeded is INV-1002, which the sibling item's step 2 re-currencies to EUR. Run this item before multi-currency's step 2 on a shared boot, or use QA-created drafts.

ai.mcp-tool-call-interceptor

  • The inline plugin's object literal needs a cast (as any) in a typed config; otherwise it boots as written.
  • A registered call's log line carries no registered key (JSON.stringify drops undefined); only the unregistered call shows registered:false. The clause reads it only on the unregistered one, so this is fine.
  • A4 should say "call after the server is ready", given the boot-window drop above.

studio-authoring.dataset-member-vocabulary

ai.mcp-read-file-pdf-word-extraction

  • The page the budget stops at varies run to run on one host (7 and 20 at 60 ms), so the note's "after page N" is not a fixed oracle; the clause correctly asserts only the opening of the sentence.

cli.deploy-runtime-dry-run-json

  • os environments use-runtime writes the target into ~/.objectstack/cloud.json (the user's home, shared by every runner on the host). Runners should set HOME to their work dir; the fixture text does not say so.

platform-core.namespace-co-owner-name-refusal

  • A3's step says "repeat the install … in base"; with the same ids the base build is an upgrade of the qa_n com.qa.n-one (installed exit 0, namespace moved to base). Fresh ids would make the leg cleaner.

platform-core.namespace-object-name-refusal

  • POST /api/v1/packages refuses label ("Unrecognized key(s) on this package manifest: label") and needs type; the fixture could spell the body: {id, name, type: 'app', version, namespace}.
  • The draft save is ?mode=draft on the same PUT; the step says "save it as a draft" without naming the switch.

platform-core.bare-name-one-holder-refusal

  • A webhook in a package needs requires: ['webhooks', 'realtime'] or objectstack build refuses the stack ("webhook 'qa_hook' is declared but requires does not include…"); the fixture text omits it.
  • The cold-boot leg is reachable with a defineStack packages[] of two bodies (no install door): this scratch app is a usable fixture for the item.

Activity

  1. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    qa#3 · os-tesla · session_01L9qibw6yXcLi9aRRBpPT4W

    Probe log (rule 8)

    • records-forms.multi-currency-invoice: 3 min, A3 re-projection on PATCH (EUR), list filter control for A4, the detail-page hint; nothing beyond A5.
    • records-forms.home-amount-preview-states: 2 min, member rate door (403), member form amount face ("—"); nothing new.
    • ai.mcp-tool-call-interceptor: 6 min — stdio client that sends initialize and the calls as soon as it spawns the server (calls ~3 s after spawn, before "✓ Server is ready"): list_objects is answered on stdout (id 2), but its [qa-interceptor] line is on neither stream; the later delete_record and describe_object lines do appear. 2 of 2 runs. So a host plugin's console.log written while the boot is still quiet is lost on the s…
    • studio-authoring.dataset-member-vocabulary: 3 min — 60-char synonym → 200 (boundary admitted); 21 synonyms → 422 at measures.0.synonyms "a member takes at most 20 synonyms…"; body restored to the fixture after. Nothing found.
    • ai.mcp-read-file-pdf-word-extraction: 2 min — the same long read twice at one budget stops at different pages (7, then 20: warm JIT), both well-formed; nothing found.
    • cli.deploy-runtime-dry-run-json: 2 min — os deploy --confirm-upgrade with a made-up finding-set token → "✗ Upgrade stopped — it would rename or retype stored fields without carrying their values", runtime still at 1.0.0. Nothing found.
    • platform-core.namespace-co-owner-name-refusal: 2 min — the qa_m holder of the same page name (N1); nothing found.
    • platform-core.namespace-object-name-refusal: 1 min — the package publish door's "No metadata items found" answer on an authored package with only a draft (as documented). Nothing found.
    • api-backend.actions-namespace-address: 3 min — uppercase namespace /actions/QA_A/… → 404 ROUTE_NOT_FOUND; unknown first segment /actions/qa_zz/qa_a_ticket/escalate → read as the bare grammar (404 "Action 'qa_a_ticket' on 'qa_zz' has no declaration…"), as acceptance[0]'s note says. Nothing found.
    • platform-core.bare-name-one-holder-refusal: 4 min — re-installing qa_b without its webhook (qa_b2) answered exit 0 but the package-less webhook read still answered 409 naming com.qa.addr-b until the next restart, after which it served only com.qa.addr-a (the dropped item is withdrawn only at restart; same shape as the earlier browser-slice runner's off-clause finding 2 on tool/flow, card status not checked here). Tool clash refused at inst…
    • access-security.permission-set-address-in-execution-context: 2 min — the enable door rewrote the package-less row's package_id to com.qa.addr-a (it updates the row it finds by (type, name), as N1 describes); nothing found.

    Per-clause tables

    records-forms.multi-currency-invoice · rev 2 · FAIL

    clause verdict evidence
    A0 pass rates read: EUR 0.92 @2025-01-01, EUR 0.9 @2026-10-14, JPY 151.5 @2025-01-01, JPY 149.25 @2026-10-14 (all manual). INV-1008 JPY 2026-11-08 amount 237864 → governing JPY 149.25 (2026-10-14 ≤ date) → 237864÷149.25 = 1593.729 → stored amount_rate 149.25, amount_home 1593.73 ✓; INV-1004 EUR 2026-11-13 amount 450 → 0.9 → 5…
    A1 pass all 7 USD seed invoices read amount_rate 1 and amount_home = amount (INV-1001 1749.56/1749.56, INV-1002 198/198, INV-1003 323.94/323.94, four zero-amount rows 0/0)
    A2 pass POST /api/v1/data/showcase_invoice {name QA-AR1F-NOCUR, account, status draft} → 201; read-back 200 currency_code null, amount null, amount_home null, amount_rate null
    A3 pass INV-1002 before: USD 2026-11-13 amount 198, home 198, rate 1; PATCH {currency_code EUR} → 200; after: EUR, amount 198, amount_home 220, amount_rate 0.9 (198÷0.9 = 220, the EUR row in force on 2026-11-13)
    A4 pass POST {currency_code JPY, invoice_date 2024-06-01} → 400 code ERR_EXCHANGE_RATE_MISSING, "Insert on 'showcase_invoice' was REFUSED: 'amount' is in JPY … ('invoice_date' = 2024-06-01), and no exchange rate for JPY has an effective date on or before 2024-06-01. The row was not written…"; list filter name = QA-AR1F-JPY202…
    A5 fail detail page of INV-1004 (dsf 2): "Total incl. Tax (Home Currency)" with hint "Converted at 0.9 on Nov 13, 2026" ✓. Edit form: [data-testid=home-amount-preview] count 0; "Total incl. Tax" is drawn as read text "€450.00"; after switching Currency to JPY and Invoice Date to 01/15/2026 (unsaved) the amount reads "¥450",…
    N0 pass no foreign invoice at rate 1, no later-dated rate, no multiplication (A0); currency-less accepted with blanks (A2); missing-rate write stored nothing (A4)

    records-forms.home-amount-preview-states · rev 1 · FAIL

    clause verdict evidence
    A0 fail admin, INV-1004 (EUR draft) Edit Invoice dialog: labels Invoice Number…Currency, Invoice Date, Total incl. Tax; [data-testid=home-amount-preview] count 0; "Total incl. Tax" is read text "€450.00"; after Currency → JPY and date → 01/15/2026, "¥450", count 0, no sys_exchange_rate request. 2 fresh browser contexts. USD…
    A1 blocked(product-bug: #32941 — the line never mounts on the invoice form, so no awaitingDa… —
    A2 blocked(product-bug: #32941, as A1) —
    A3 blocked(product-bug: #32941, as A1) contributor-bound member, own invoice: Currency → EUR, Invoice Date → 06/15/2025, preview count 0; "Total incl. Tax" reads "—" (no number); the member's GET /api/v1/data/sys_exchange_rate → 403 PERMISSION_DENIED (the fixture half holds; the console made no rate request because nothing mounted)
    N0 pass (partial reach) no computed number shown to the member (amount reads "—"); the "previewed ≠ stored" half has no preview to compare (A0)

    ai.mcp-tool-call-interceptor · rev 1 · PASS

    clause verdict evidence
    A0 pass MCP HTTP list_objects → normal result (objects[]…); log [qa-interceptor] {"door":"mcp","transport":"http","toolName":"list_objects","userId":"9cj3sucwLJCGEIZ1Evjjhba7SOZxcL8F"} = the key owner
    A1 pass delete_record {showcase_task, 7iKVRkGDGPeCuI0i} → isError {error {code PERMISSION_DENIED, message 'QA interceptor refuses delete_record', status 403}}; GET /api/v1/data/showcase_task/7iKVRkGDGPeCuI0i → 200 afterwards
    A2 pass describe_object → isError {code INTERNAL_ERROR, message 'Internal server error', status 500}; log WARN [MCP] The installed tool-call interceptor answered "describe_object" with neither a tool result nor a { outcome: 'deny', code, message } refusal, so the call was refused as a server fault…
    A3 pass tools/call qa_no_such_tool → isError text "MCP error -32602: Tool qa_no_such_tool not found"; log [qa-interceptor] {…"toolName":"qa_no_such_tool","registered":false,…}
    A4 pass os start over stdio, calls sent after the HTTP health answered 200: stderr carries [qa-interceptor] {"door":"mcp","transport":"stdio","toolName":"list_objects","userId":"9cj3…"} (and delete_record, describe_object lines, plus the A2 WARN); stdout holds only the JSON-RPC answers (delete_record PERMISSION_DENIED, de…
    A5 pass (pin) pins green at 8e3d4a5: tool-call-interceptor.test.ts 49✓, plugin-execution-context.test.ts 9✓
    N0 pass denied delete_record left the task readable (A1), over HTTP and over stdio
    N1 pass the malformed verdict answered isError INTERNAL_ERROR, never a success (A2)
    N2 pass the unregistered name got only the SDK's "Tool qa_no_such_tool not found" (A3)

    studio-authoring.dataset-member-vocabulary · rev 1 · PASS

    clause verdict evidence
    A0 pass (a) ['bill count','Bill_Count'] → 422 INVALID_METADATA, path measures.0.synonyms.1, "synonym "Bill_Count" of measure "invoice_count" repeats synonyms[0] "bill count" once case, width, spacing, _ and - are folded (ADR-0149 D1)…"
    A1 pass (b) ['status'] → 422 at measures.0.synonyms.0, "…is also the name of dimension "status" in this dataset, once case, width, spacing, _ and - are folded…"
    A2 pass (c) [' bill'] → 422 measures.0.synonyms.0 invalid_format "…no leading or trailing whitespace, no line break… The schema refuses rather than trims it…"; (d) 61 chars → 422 too_big "a synonym is at most 60 characters…"; (e) 501-char description → 422 at measures.0.description "…is 501 characters; … at most 500 per local…
    A3 pass GET after each of (a)–(e) → 404 RESOURCE_NOT_FOUND (nothing stored); valid PUT → 200 "Saved dataset 'qa_vocab_metrics' (env-wide, state=active) [seq=1]"; GET → 200, measures[0] synonyms ["bill count","账单数"], description "Count of invoices, every status."
    A4 pass MCP HTTP tools/call list_datasets {terms:['Bill-Count','账单数']} → 200; qa_vocab_metrics entry matches [{term 'Bill-Count', member 'measures.invoice_count', matchedOn 'synonym'}, {term '账单数', member 'measures.invoice_count', matchedOn 'synonym'}]; its invoice_count lists synonyms ['bill count','账单数'] and the description
    A5 pass /_console/studio/~all/metadata/dataset/qa_vocab_metrics, measure row → Advanced: "Synonyms" input value "bill count, 账单数" (data-testid dataset-measures-synonyms), "Description" textarea "Count of invoices, every status." (dataset-measures-description); Synonyms help "Words people use for this measure in a question … M…
    N0 pass no refused body stored (A3); the untrimmed synonym was refused, not trimmed (A2 c)
    N1 pass page text (Studio dataset page incl. the preview chart and table) contains "bill count" / "账单数" 0 times outside the input value; chart legend and column read the label "Invoices"

    ai.mcp-read-file-pdf-word-extraction · rev 2 · PASS

    clause verdict evidence
    A0 pass read_file {showcase_invoice_line, 3Vdid9gmPv2qkz7S, field receipt} → block 0 facts {fileId 58125195-…, name two-page.pdf, mimeType application/pdf, size 2784, field receipt, maxBytes 10485760, download {url, expiresAt}, content 'text', format 'application/pdf'}; block 1 7182 chars "QA-AR1F two-page receipt page 1 line…
    A1 pass .docx line → facts content 'text', mimeType and format 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; block 1 = the three paragraphs ("QA-AR1F Word receipt, paragraph one…", "Paragraph two…", "Paragraph three: total due 450 EUR.")
    A2 pass field + attachmentId → isError "Name one file: either field (with fileId for a multi-file field) or attachmentId, not both."; fileId without field → isError "fileId names a file within a field: send field with it."
    A3 pass boot with budget 60: long-180.pdf → facts content 'text', truncated true, note "Reading stopped at the CPU-time budget for one file (60 ms) after page 7 of 180, so the text is partial. Download the file with the link for the rest."; text block 24 302 chars ending "page 7 line 40 …". Second call: "…(60 ms) after page 2…
    A4 pass OS_MCP_READ_FILE_CPU_BUDGET_MS=abc → process exit 1, log "✗ OS_MCP_READ_FILE_CPU_BUDGET_MS must be a positive integer; got "abc". Unset it for the default (2000), or set a whole number."; port 41273 never listened
    A5 pass (pin) pins green at 8e3d4a5: mcp-file-tools.test.ts 35✓
    N0 pass the long read answered in seconds with text and the note (no hang, never empty-without-note)
    N1 pass the malformed variable refused the boot (A4), not read as unset

    cli.deploy-runtime-dry-run-json · rev 2 · PASS

    clause verdict evidence
    A0 pass os deploy --dry-run exit 0: build, then "→ Asking http://localhost:41276 for the upgrade plan (dry run — nothing is installed)…", plan "Objects + qa_deploy_item", "Nothing in this plan asks for a confirmation: os deploy installs it as it is.", "✓ Dry run: nothing was installed into http://localhost:41276. Run `os …
    A1 pass os deploy --dry-run --json, stdout and stderr captured apart: exit 0; stdout (43 lines) parses as one JSON object {target 'runtime', url 'http://localhost:41276', result 'planned', package {manifestId 'com.qa.deploy', version '1.0.0', installedVersion null}, plan {…}, environment {…}, wouldStop [], refusal null, con…
    A2 pass os deploy exit 0: "✓ Package installed into the running kernel", "✓ Live: http://localhost:41276 now serves com.qa.deploy 1.0.0."; GET /api/v1/packages lists com.qa.deploy 1.0.0; GET /api/v1/data/qa_deploy_item → 200; two rows with a note created 201
    A3 pass v1.1.0 os deploy --dry-run exit 0: "Suspected renames (no renamedFrom links them) qa_deploy_item.note → memo? — 2 row(s) hold a value…", "⚠ Deploying this build would stop for your confirmation — 1 finding(s): • qa_deploy_item.note (text) is removed while qa_deploy_item.memo (text) is added, and no renamedFrom lin…
    A4 pass (pin) pins green at 8e3d4a5: deploy.test.ts 47✓
    N0 pass the dry run installed nothing (A0); the --json stdout carried no human line (A1, A3)
    N1 pass the off-TTY run did not wait on a question (A3: exited 1 at once); the fixture is a rename, not a drop

    platform-core.namespace-co-owner-name-refusal · rev 4 · PASS

    clause verdict evidence
    A0 pass stack-n-both: os validate exit 1 and objectstack build exit 1 (no dist written), both "✗ The server would refuse this stack at boot (1 package holding a name another package of its namespace holds) • Namespace name conflict: package "com.qa.n-two" … declares the page "qa_board" in namespace "qa_n", already h…
    A1 pass com.qa.n-one (qa_n) installed exit 0. com.qa.n-two, no dependency → exit 1 "✗ Install failed (422 PLUGIN_REGISTER_FAILED): Failed to register imported manifest: Namespace conflict: namespace "qa_n" is already owned by package "com.qa.n-one", so package "com.qa.n-two" cannot be installed alongside it… (ADR-0141 D…
    A2 pass (exit-0 half) stack-n-residual: os validate exit 0 (summary only, no refusal), by design
    A2 (manifest-service half) pass (pin) pins green at 8e3d4a5: registry-namespace-co-owner-names.test.ts 56✓, manifest-service-residual-namespace-name.test.ts 33✓, namespace-co-owner-names.test.ts 29✓
    A3 pass com.qa.n-one rebuilt in ns base → "✓ Package installed" exit 0; com.qa.n-two in base, also holding page qa_board → "✓ Package installed" exit 0; GET /api/v1/packages lists com.qa.n-one base, com.qa.n-two base
    N0 pass no second qa_n co-owner installed with qa_board (A1: both builds refused, nothing installed)
    N1 pass com.qa.m-one (ns qa_m) holding page qa_board installed exit 0 beside the base holders: the rule is per namespace
    N2 pass (reading kept) the 422 namespace-ownership and the 403 NOT_OVERRIDABLE were read as the gates that answer first; validate exit 0 on the residual read as by design

    platform-core.namespace-object-name-refusal · rev 2 · PASS

    clause verdict evidence
    A0 pass stack-k-both: os validate exit 1, objectstack build exit 2 (no dist), both "✗ defineStack namespace-prefix validation failed (1 issue): ✗ Namespace 'qa_k_case' of package 'com.qa.k-case' equals the object 'qa_k_case' of package 'com.qa.k'… (ADR-0150 D6). Rename the namespace or the object." (pkg-qa-k-case alone: v…
    A1 pass qa_k installed exit 0; os package install pkg-qa-k-case/dist/objectstack.json → exit 1 "✗ Install failed (422 PLUGIN_REGISTER_FAILED): Failed to register imported manifest: Namespace 'qa_k_case' of package 'com.qa.k-case' equals the object 'qa_k_case' of package 'com.qa.k'…" (namespace and object spelled, both packa…
    A2 pass (qa_w_desk package installed exit 0 first) PUT /api/v1/meta/object/qa_w_desk?package=com.qa.w → 422 NAMESPACE_CONFLICT "The object 'qa_w_desk' of package 'com.qa.w' equals the installed namespace 'qa_w_desk' of package 'com.qa.w-desk'… (ADR-0150 D6). Rename the object."; same body &mode=draft → 200 state=draft; POST /…
    A3 pass app-qa-k-custom: os validate exit 1 "✗ The object 'qa_k_custom' of package 'com.qa.k-custom' is short-named 'custom'. The paired customization package of namespace 'qa_k' takes the namespace 'qa_k_custom' (ADR-0146), which would equal this object name (ADR-0150 D6). Rename the object."
    N0 pass the clash was refused at install (A1), never accepted
    N1 pass every refusal names both spellings (namespace and object); publish-drafts' 200 carries outcome refused and the draft stayed a draft

    api-backend.actions-namespace-address · rev 3 · PASS

    clause verdict evidence
    A0 pass POST /api/v1/actions/qa_a_ticket/escalate/RID {} → 409 {success false, error {code RESOURCE_CONFLICT, message "The action "escalate" is held by 2 packages in this environment and the caller names no package: package "com.qa.addr-a"; package "com.qa.addr-b". Nothing picks one of them: address it by its package.",…
    A1 pass /actions/qa_a/qa_a_ticket/escalate/RID → 200 {ran 'com.qa.addr-a', action 'escalate'}; /actions/qa_b/qa_a_ticket/escalate/RID → 200 {ran 'com.qa.addr-b', action 'escalate'}
    A2 pass /actions/qa_a/global/qa_a_ping → 200 {ran 'com.qa.addr-a', action 'qa_a_ping'}; /actions/qa_b/global/qa_a_ping → 404 RESOURCE_NOT_FOUND "Action 'qa_a_ping' not found on object 'global' in namespace 'qa_b'"
    A3 pass /actions/_env/global/qa_env_ping → 200 {ran 'environment'}; /actions/_env/global/qa_a_ping → 404 "Action 'qa_a_ping' not found on object 'global' in the environment"
    A4 pass /actions/qa_a/_activation/qa_a_ticket → 404 RESOURCE_NOT_FOUND "An addressed action path is /actions/:ns/:object/:action[/:recordId] or /actions/:ns/global/:action (ADR-0150 D5)"; /actions/qa_a/qa_a_ticket/escalate/RID/extra → 404 ENDPOINT_NOT_FOUND "Not found"; RID's updated_at unchanged (10:07:59.018Z) after every c…
    N0 pass the bare call ran neither handler (A0)
    N1 pass qa_b/global/qa_a_ping and _env/global/qa_a_ping answered 404, no fallback to qa_a's (A2, A3)
    N2 pass the bare call answered 409, not 200 with qa_a's result. The one-holder half (qa_b's escalate removed → bare 200 qa_a's) was not driven here: a re-install that drops an item does not withdraw it until restart (see bare-name item's probes), and round 1 drove it (200)

    platform-core.bare-name-one-holder-refusal · rev 3 · FAIL

    clause verdict evidence
    A0 fail install qa_a → "✓ Package installed" exit 0; install qa_b (also holds webhook qa_hook) → installed, exit 0; GET /api/v1/packages lists com.qa.addr-a and com.qa.addr-b; registry log "Registered webhook: com.qa.addr-a:qa_hook" and "…com.qa.addr-b:qa_hook"; GET /meta/webhook/qa_hook → 409 RESOURCE_CONFLICT "The webhook \…
    A1 pass qa_b (and the rebuilt qa_b2 without the webhook) installed exit 0 while qa_a holds flow qa_sync and agent qa_helper; package-less GET /meta/flow/qa_sync and /meta/agent/qa_helper → 409 naming both packages (per-namespace holding). The clause's trailing "webhook, connector and tool are still one holder per deployment" …
    A2 pass qa_a, holding email_template auth.password_reset, installed exit 0; package-less GET /meta/email_template/auth.password_reset → 200 the platform copy (subject "Reset your {{appName}} password")
    A3 fail cold boot of app-cold (both bodies hold webhook qa_hook in two namespaces): boot completes (health 200) and the log carries exactly one "Bare-name conflict at boot" WARN — for the tool: "package "com.qa.cold-2" declares the tool "qa_tool", already held by package "com.qa.cold-1" — rename it to "qa_k2_qa_tool"……
    N0 pass (as a negative) no second install served one of two holders under the bare webhook name: the package-less read is refused 409, not served
    N1 pass the cold boot with a held clash (tool) was not refused
    N2 pass qa_b's 200 beside qa_a's flow qa_sync, and the bare flow read 409 naming both, as the negative says

    access-security.permission-set-address-in-execution-context · rev 3 · PASS

    clause verdict evidence
    A0 pass admin POST /api/v1/data/sys_user_permission_set {user_id M, permission_set qa_a_reader} → 201, row permission_set_package "com.qa.addr-a"; M GET /auth/me/permissions → permissionSets [showcase_contributor, showcase_member_default, member_default, qa_a_reader, storage_attachment_member], qa_a_ticket allowRead true; M G…
    A1 pass INSERT sys_metadata_activation (permission, qa_a_reader, package_id 'com.qa.addr-b', active 0) → restart: M's sets no longer list qa_a_reader, qa_a_ticket entry absent; data read 403 PERMISSION_DENIED; explain {kind permission_set, name qa_a_reader, via "held — deactivated", state deactivated}; boot WARN "[security] a…
    A1 (two-holder half) pass (pin) pins green at 8e3d4a5: permission-set-address.test.ts 24✓, request-execution-context.test.ts 21✓
    A2 pass POST /api/v1/security/_activation/permission/qa_a_reader {enabled:false} → 200 {type permission, name qa_a_reader, enabled false}; ledger row UbQyREMHCr3iqWS8 package_id com.qa.addr-a, active false; M: qa_a_reader gone, data 403 PERMISSION_DENIED, explain {kind 'permission_set', name 'qa_a_reader', via 'held — deactiv…
    A3 pass stop; UPDATE that row package_id NULL; restart: M's sets lack qa_a_reader, data 403, explain "held — deactivated" (same as A2). POST …/qa_a_reader {enabled:true} → 200; row now package_id com.qa.addr-a active 1; M lists qa_a_reader again, data 200 with the record, explain "direct grant"
    A4 pass (source reading, as the clause instructs) packages/core/src/security/assemble-execution-context.ts:333 const agent = !anonymous && !account && oauth?.clientId ? oauth : undefined; and :349 permissionSetAddresses: agent ? undefined : authz.permissionSetAddresses, — the OAuth agent arm carries no addresses; the AI service account is the account arm, which…
    N0 pass the stale row did not leave M's set granting (A1)
    N1 n/a (fixture discipline kept) the step-2 foreign row was deleted before step 3, so the door wrote com.qa.addr-a's own row (A2)
  2. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    qa#3 · os-tesla · session_01L9qibw6yXcLi9aRRBpPT4W

    Close-out 2026-11-13T10:40Z.

    Extracted: #32941 · records-forms.multi-currency-invoice · acceptance[5]
    Extracted: #32941 · records-forms.home-amount-preview-states · acceptance[0]
    Extracted: #33091 · platform-core.bare-name-one-holder-refusal · acceptance[0], acceptance[3]

  3. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    qa#3 · os-tesla · session_01L9qibw6yXcLi9aRRBpPT4W

    Closed 2026-11-13T10:44Z: round 1's FAILs re-judged, three left on #32941 and a re-point card; close-out above.

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