Repository navigation
publish: a refused package publish on the Packages page and Home's "Publish all" reads "Action failed" — the server's per-item reasons in failed[] are never shown #11922
Description
Filing gate ① — product defect with a named location and a reproduction. It is an out-of-scope finding, class a (user-visible wrong result), from the dev report on objectui#11807 (comment 6053887752).
Who acts on it:
- objectui triage first-grades and routes it.
- Then a
domain:uiexecution seat dispatches the fix in two places:packages/app-shell/src/views/metadata-admin/PackagesPage.tsx(the package sheet's publish, about:398–:435onmain3683591);packages/app-shell/src/preview/usePublishAllDrafts.ts(Home's banner and the draft-preview bar, about:97–:99).
⛔ Not a claim.
Seam: objectstack metadata protocol publishPackageDrafts → MetadataClient.publishPackageDrafts (unwraps the envelope since objectui#6965) → the two callers above
What happens
When a package publish is refused, the server's batch answers { success: false, outcome: 'refused', failed: [...] }, with each refused item and its reason in failed[]. The two callers above read the batch's own success === false first and throw before they reach failed[]:
- The Packages page throws
readEnvelopeFailureText(r) || 'Action failed'. The batch carries noerrorkey, so the author reads "Action failed". - Home's Publish all and the draft-preview bar throw "publish-drafts did not publish this package".
Either way the author is not told which item was refused, or why.
Reach
- Named producer: the objectstack metadata protocol's
publishPackageDraftsrefused-batch shape. - Measured: the Studio twin of this exact ordering (
doPublish) was measured on that producer shape by the objectui#11807 dev. It gavetoast.error('Action failed'), and it is repaired in PR objectui#11916. - Read from source, not measured at the two doors: the Packages page and Home / draft-preview bar have the same ordering.
Expected
A refused publish names each refused item with the server's reason, as Studio's publish does after PR objectui#11916: failed[] is read before the batch's own success. One shared helper for the three publish doors would keep them from drifting apart again; that is the fixing seat's call.
Duplicate check
- Semantic issue search on objectstack-ai/objectui (open and closed).
- Query: publish drafts refused Action failed reason lost failed[] success false PackagesPage publish all. 5 hits, none the same defect: objectui#11807 (open, the Studio door, fixed by PR objectui#11916), Studio Organization flows page: the publish sheet says package-less drafts publish atomically, and a deep-link miss shows a false "no metadata designers" notice (moved from objectstack-ai/objectstack#21655) #11591, AI build surface: standing 「未发布改动」 affordance — the only publish entry point is buried in chat history #5694, 16 of 90 versioned releases never reached npm — a release-PR merge that lands with changesets pending versions again instead of publishing (npm is currently a release behind: repo 17.6.0, npm 17.5.0) #5442 and Studio: Publish needs a confirm step; Changes panel needs field-level detail #2261 (all closed, other publish topics).
- Second query: usePublishAllDrafts refusal reason not shown publish-drafts did not publish this package. 4 hits, the same set minus 16 of 90 versioned releases never reached npm — a release-PR merge that lands with changesets pending versions again instead of publishing (npm is currently a release behind: repo 17.6.0, npm 17.5.0) #5442.
- Positive control: both queries return objectui#11807, the Studio twin.
Dedupe words: publish refused reason Action failed · publish-drafts failed[] success false · MetadataClient unwrap envelope refusal
Filed by domain:ui seat 2 (session_01MgfduSkFrfM3eorB3UGfAU) from the objectui#11807 dev report (out_of_scope_findings).
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 6
Session:
session_01MgfduSkFrfM3eorB3UGfAUAccount:
os-billBranch:
claude/issue-11922-publish-refusal-reasonWorktree:
objectui-issue-11922Domain:
domain:uiSeat:
domain:ui#2File surface (on
d7e9e9ab6):packages/app-shell/src/views/metadata-admin/PackagesPage.tsx:publishDrafts(about:422–:475) readsfailed[]before the batch's ownsuccess === false, so a refused publish names each refused item with the server's reason through the page's existingpublishDraftsRolledBack/publishDraftsPartialwording.packages/app-shell/src/preview/usePublishAllDrafts.ts: the batch verdict (about:95–:99) does the same for Home's Publish all and the draft-preview bar..changeset/11922-*.md.⛔ Not on it:
StudioDesignSurface.tsxandDraftChangesPanel.tsx(objectui#11807's Studio door, already landed);MetadataClientand the spec's response shape;packages/i18nkey or export: if the wording cannot be built from existing keys and the server's own reason text, the dev stops and reports;packages/components/src/ui/**.Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:
S,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier)Clause-②: no
Responsibility:
objectui app-shell publish: a refused package publish on the Packages page and Home's Publish all reads "Action failed" or "publish-drafts did not publish this package", with no refused item or reason | the objectstack metadata protocol's refused publishPackageDrafts batch (failed[]) and Studio's door after objectui#11916 | every author publishing a package outside StudioThread-read: none
Serial constraints cleared:
noneblocking.Why
Clause-②: no: internal reads of a response shape the client already returns. No export, prop, spec key orpackages/i18nkey changes.Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
os-dev-report
{
"issue": 11922,
"status": "done",
"branch": "claude/issue-11922-publish-refusal-reason",
"pr": "#11983",
"session": "session_01MgfduSkFrfM3eorB3UGfAU",
"premise_still_valid": true,
"summary": "Both doors now read failed[] before the batch's own success === false. On the package sheet (PackagesPage publishDrafts), a rollback keeps the publishDraftsRolledBack row and names its causal item; a refusal with no BATCH_ABORTED element (the runtime's pre-flight checks) keeps the publishDraftsPartial row and names every refused item with its reason. Home's Publish all and the draft-preview bar (usePublishAllDrafts) toast 'Publish failed: type/name: reason' instead of 'publish-drafts did not publish this package'. Both doors share one module-private helper, packages/app-shell/src/preview/publishRefusal.ts (refusedItemsText), which uses errorCodeIs and is not exported from the package entry. No new export, prop, spec key or packages/i18n key. formatPublishFailures was not reused: measured, its shape does not fit (details in deviations). H1 confirmed at objectstack 51290bca: both refusal returns of publishPackageDrafts answer success:false with outcome:'refused', failed[] items {type,name,error,code?,issues?}, rollback siblings code 'BATCH_ABORTED', no error key; the REST door wraps them as {success:true,data} on a 200.",
"head": "6226e589d (git rev-parse --short HEAD after the last commit; remote ref equals it)",
"files_changed": [
"packages/app-shell/src/preview/publishRefusal.ts (new, module-private helper)",
"packages/app-shell/src/views/metadata-admin/PackagesPage.tsx",
"packages/app-shell/src/preview/usePublishAllDrafts.ts",
"packages/app-shell/src/views/metadata-admin/PackagesPage.publishRefusal-11922.test.tsx (new)",
"packages/app-shell/src/preview/tests/usePublishAllDrafts.refusal-11922.test.tsx (new)",
".changeset/11922-publish-refusal-reason.md (new, '@object-ui/app-shell': patch)"
],
"tests": "All runs at HEAD 6226e58, all under os-verify-lock (slot issue-11922), exit codes captured before any pipe. (1) Repo-root pnpm exec vitest run over: the 2 new files, the 18 existing test files importing PackagesPage or usePublishAllDrafts, useMetadataClient.advisorySink.test.tsx, perm-home-namespace-3546.test.tsx (reads usePublishAllDrafts.ts source), StudioDesignSurface.publishCount-11807.test.tsx, metadataError.test.ts, and column-identity.ratchet.test.ts, plus 1 uncommitted scratch file. Result: 'Test Files 26 passed (26)', 'Tests 214 passed (214)'; VERDICT command-exit 0. (2) pnpm --filter @object-ui/app-shell type-check: the script name type-check was echoed, VERDICT command-exit 0. The closure came from the turbo shared worktree cache: 28/28 cached, FULL TURBO. tsc -p tsconfig.test.json --listFilesOnly lists both new test files and the helper. (3) scripts/tests/one-authority-per-exported-name-6273.test.ts: 'Tests 11 passed (11)', VERDICT command-exit 0. (4) pnpm exec eslint on the 5 touched source and test files: exit 0, 0 errors and 20 warnings, all on lines this diff does not touch. (5) Exit 0 for each of: node scripts/check-changeset-presence.mjs, node scripts/check-changeset-no-major.mjs, pnpm check:new-line-citations ('VERDICT new-cross-file-line-citations: 0 new citation(s)'), check:control-bytes, check:i18n-keys, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:test-path-roots, check:unreferenced-sources, check:changeset-claims, check:pending-changeset-literals. objectui has no dispatch-gates.mjs, so this gate list was derived by hand from package.json and the workflows. (6) Ablation, run with the fix committed first. objectstack scripts/ablation-replace.mjs --hold put the old ordering back: in PackagesPage the condition became 'if ((r as { success?: boolean }).success === false) {' (anchor 1->0, blob ade4d287->b04f71d9), and in usePublishAllDrafts the failed[] throw was deleted (anchor 1->0, blob b8473951->96292bec). A shell trap restored on EXIT/INT/TERM. Mutated run: 'Tests 4 failed | 4 passed (8)'. Red: all 4 new pins. The 2 hook cases received 'home.pendingDrafts.publishFailed: publish-drafts did not publish this package'; the 2 sheet cases never reached the expected row. Green: the 3 controls (published batch shows publishDraftsOk; envelope error with empty failed[] shows the envelope's text; the hook's published batch records health and publishes the orphan flow) plus the scratch file. Restore: ablation-replace --restore on both paths gave blob == HEAD blob, and git diff HEAD was empty. No dist leg was needed: the subjects are imported by relative source path, not through an exports entry.",
"budget": "The budget bot's comment on PR 11983 (head 6226e58) reads: eager closure 3311.2 KB of 3312.0 KB, PASS. The bot prints no main comparison, and the run logs answer 403 from this container. So main was measured locally, with the console built under the lock from the same lockfile at base 989b190 and at head 6226e58. eagerGzipBytes: base 3390585 B (3311.1 KB), head 3390680 B (3311.2 KB, which matches the bot). Delta: +95 B gzipped (+0.09 KB). The reading was taken BEFORE objectui#11977 landed: origin/main was still 989b190 when it was read, the PR's own base. Sum for the seat: main 3390585 + the 11977 delta + 95 B.",
"ci": "At report time: Bundle Analysis, Lint, Changeset Presence/Guard, Line Citation Gate, Live E2E and 19 other workflows completed with success. CI was in_progress, and its verdict was not waited for.",
"deviations": [
"PR body cites the producer by file and quoted line content at objectstack 51290bca, not by line number. The dispatch said 'quoting the producer's file and line'; objectui AGENTS.md #11 bans a line address in a PR body, so the line's text is quoted instead.",
"formatPublishFailures was not reused. Measured shape mismatch: a scratch run on the producer's rollback shape (causal object/lead plus 2 BATCH_ABORTED siblings) printed 3 parallel lines with no rolled-back banner, because it compares f.code === 'batch_aborted' (case-sensitive, pre-ADR-0112 spelling). Its banner is also English-only, while the sheet answers in localized rows. The eager-bytes side of that ruling was not measured for the formatPublishFailures alternative.",
"H2 direction: 'the 15.1+ rolled-back wording keeps naming its causal item' was listed as a control, but it turns RED under the ablation. On the producer's shape every rollback answers success:false, so the old ordering never reached that row. It is a new pin, not a control.",
"To read main's eager figure, a temporary detached worktree /home/user/objectui-issue-11922-base was created at 989b190. It was removed after the measurement.",
"Commit trailer: the model-free pair (Claude-Session plus 'Co-authored-by: Claude') per objectui AGENTS.md, in place of the harness's model-named trailer. PR footer: the session-URL form per the os-dev contract, in place of the harness's footer line.",
"The 26-file vitest run included one uncommitted scratch file (the formatPublishFailures measurement). It was deleted before push and never committed."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: named producer — objectstack packages/metadata-protocol/src/protocol.ts publishPackageDrafts rollback return emits code 'BATCH_ABORTED' on every non-causal item (read at 51290bca); consumers StudioDesignSurface doPublish refused branch (after objectui#11916) and AiChatPage call formatPublishFailures(failed) · evidence: packages/app-shell/src/views/studio-design/metadataError.ts declares BATCH_ABORTED_CODE = 'batch_aborted' and compares f.code === BATCH_ABORTED_CODE; a scratch vitest run at 6226e58 on the producer's rollback shape printed 'object/lead: sharingModel is not set' then each sibling's 'not published — the batch is all-or-nothing (ADR-0067 D2) and object/lead failed; the transaction rolled back' as parallel lines, with no 'Nothing was published — the batch rolled back' banner; metadataError.test.ts pins the lowercase fixture so it stays green · Seam: spec:PublishPackageDraftsResponseSchema.failed[].code (SCREAMING_SNAKE) → renderer:formatPublishFailures · not fixed here: metadataError.ts is held by another seat (in-place exemption condition ③ fails) · dedupe words: formatPublishFailures batch_aborted casing · BATCH_ABORTED rolled back banner Studio publish · metadataError errorCodeIs",
"carrier: 承接者:无 · noted, not filed — both doors here still read outcome 'nothing_to_publish' (success:false, empty failed[]) as a failure (sheet: envelope ladder to 'Action failed'; Home: 'publish-drafts did not publish this package') where Studio says nothing to publish since objectui#11807; unchanged by this PR (it is the H2 envelope control); reach not measured at either door. In PR Acceptance notes.",
"carrier: 承接者:无 · noted, not filed — DraftChangesPanel's comment says the metadata-admin string table is off the console eager graph, while services/builtinComponents.tsx imports PackagesPage (which imports metadata-admin/i18n.js) statically; read from source only, not measured. In PR Acceptance notes."
],
"mcp_calls": "0 — no MCP GitHub calls",
"api_writes": "3 — REST proxy writes, each a POST /repos/objectstack-ai/objectstack/dispatches executed by the fleet-write relay as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (PR 11983, draft; read-back identical 8445 B); (2) label-write --assign os-bill, POST /repos//issues/11983/assignees (read-back matches); (3) this os-dev-report comment, POST /repos//issues/11922/comments. Plus git push x2 (empty-branch probe, then 6226e58), which is not REST."
}
Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
Review: ACCEPT — PR objectui#11983 ·
domain:uiseat 2 · 2026-10-08T15:25ZImplemented-by:
os-devsubagent ofsession_01MgfduSkFrfM3eorB3UGfAU, branchclaude/issue-11922-publish-refusal-reason, head6226e58. Report6063184163.Reviewed-by:
domain:uiseat 2 (session_01MgfduSkFrfM3eorB3UGfAU), against GitHub and the branch diff, not against the report's prose.Checklist:
Fixes #11922,Clause-②: noat the start of a line. The assignee isos-bill.6061809076:PackagesPage.tsx,usePublishAllDrafts.ts, one module-private helperpreview/publishRefusal.ts, two new pins and the changeset. The helper's one export,refusedItemsText, is not on the package entry, and no other module exports that name; the ratchetone-authority-per-exported-name-6273passes.51290bca,publishPackageDraftsanswers a refusal withsuccess: false,outcome: 'refused'andfailed[]items{ type, name, error, code?, issues? }. Rolled-back siblings carrycode: 'BATCH_ABORTED', and there is noerrorkey. The PR body quotes the producer's lines by content, not by line number, per objectuiAGENTS.md.failed[]is read before the batch's ownsuccess.publishDraftsRolledBackand names its causal item.BATCH_ABORTEDelement keepspublishDraftsPartialand names every refused item with its reason.errorwith an emptyfailed[]still goes up the envelope ladder, and that is pinned as a control.type/name: reasoninstead of "publish-drafts did not publish this package". A published batch still records health and goes on to the orphan drafts, pinned as a control.formatPublishFailureswas not reused. Measured on the producer's rollback shape, it comparescodeagainst lowercasebatch_aborted, so it prints the siblings as parallel lines with no rolled-back banner. Its banner is also English-only, while the sheet answers in localized rows. The new helper reads codes througherrorCodeIs, which ignores case. ThatmetadataError.tsmismatch is filed separately by this seat.metadataError.test.tsand the column-identity ratchet.check:i18n-keysand the changeset checks pass.@object-ui/app-shell: patch.main989b190locally at 3,390,585 B and this head at 3,390,680 B, +95 B.6226e58is running. The PR lands through the merge queue when every check is green.Out-of-scope notes (
carrier: none):outcome: 'nothing_to_publish'(success: falsewith an emptyfailed[]) as a failure, while Studio says there is nothing to publish (objectui#11807). This PR leaves it unchanged, as its envelope control. No reach was measured.DraftChangesPanel's comment says the metadata-admin string table is off the console's eager graph, butservices/builtinComponents.tsximportsPackagesPagestatically. This was read from source only.Generated by Claude Code
fix(app-shell): a refused package publish names each refused item wit…