fix(pages): author page:header actions as action ids, per the protocol - #1656
Merged
Conversation
`PageHeaderProps.actions` is `z.array(z.string())` — "Action IDs to show in header" (@objectstack/spec 17.3.0). The four record pages authored whole `ActionDef` objects there instead, which `objectstack lint` reported as 16 `component-props-invalid` warnings. Convert all four to id arrays; the same sixteen buttons are named on the same four headers, in the same order. Every id was resolved against the app's own action registry: each names an action that exists and is reachable from the page's object (the runtime keys the registry on `<objectName>:<action.name>`). A new guard in `test/action-references.test.ts` keeps that true — a bare string carries no compile-time check, so the conversion would otherwise trade a shape error for a dangling reference. The four `KNOWN_UNCONFORMING` exemptions in `test/metadata-references.test.ts` retire with the non-conformance they recorded. Their docblock paragraph, which argued the source should follow objectui's current renderer, is replaced by the 2026-09-06 ruling that settled it: a metadata project does not depend on `@object-ui/components`, and this repo declares no `@object-ui/*` dependency at all. No assertion in that file changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-steve
marked this pull request as ready for review
September 6, 2026 06:07
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1653
ui/PageHeaderProps:actionstakes action id strings, notActionDefobjects. The four record pages authored objects there, andobjectstack lintwas reporting every entry correctly. This converts them, retires the exemptions that recorded the non-conformance, and pins that the ids resolve.Re-measured on this branch's base
Base:
28bf0d998f0a93a4654e1117f2b64d965e4d758f(origin/mainat cut time). The card warned its figures were PR #1605-era readings; all three were re-derived here and all three match.28bf0d9component-props-invalidobjectstack lintwarnings, totalKNOWN_UNCONFORMINGlines@object-ui/*dependenciesThe one remaining warning is
sales_home_page/ai_briefing :: description(component-props-unknown-key) — #1216, deliberately untouched, and itsKNOWN_UNCONFORMINGentry stays.Baseline, verbatim from
pnpm linton the base:After:
The contract, read off the pinned package
From
node_modules/@objectstack/spec/dist/ui/index.js(17.3.0), insidePageHeaderProps:The ledger agrees:
packages/spec/authorable-surface/ui.jsoncarries"ui/PageHeaderProps:actions"live, beside a retired sibling written"ui/PageHeaderProps:icon [RETIRED]".Every id was resolved, and the resolver was shown refusing
The conversion trades a compile-checked import for a bare string, so a typo would swap a shape error for a dangling reference — the worse defect. All 16 ids were resolved against the app's own registry (31 registered actions, read from the built stack): an id resolves when some action carries that
nameand is reachable from the page's object, since the runtime registers a body action underOBJECTNAME:ACTIONNAMEand the dispatcher probes the object name first.account_detail_page(crm_account)log_calllog_meetingschedule_meetingcase_detail_page(crm_case)escalate_caseclose_caselog_calllead_detail_page(crm_lead)convert_leadschedule_followuplog_calllog_meetingschedule_meetingopportunity_detail_page(crm_opportunity)generate_quoteclone_opportunitylog_calllog_meetingschedule_meetingAll 16 also declare
record_headerin their ownlocations, so each is header-eligible by the protocol's placement vocabulary. That reading is reported, not gated on — this PR adds no rule the card did not ask for.A one-off script proved nothing on its own, so the check is now a guard in
test/action-references.test.ts, the file that already owns "action references resolve". It carries its own refusal leg: the same resolver must still reject a name no action carries, and a real name scoped to a different object.Ablation — both legs mutated on disk, both restored by hash
Run against the committed tree, so the restore leg has something to restore to.
Leg 1 — one id mutated to
convert_lead_typo; on-disk proofold-spelling=0 new-spelling=1;vitest exit = 1:Leg 2 — one
KNOWN_UNCONFORMINGheader line put back; on-disk proofbefore=0 after=1;vitest exit = 1:So the four lines genuinely had to go: leaving one would have failed the guard's own stale-exemption arm.
Restore proved by hash, not by exit code — after each leg, the file's
git hash-objectequals itsHEADblob (e3792acc…for the page,d5788796…for the guard) andgit diff HEAD --name-onlyis empty. Control — the unmutated tree, same two files:2 passed, 47 tests, exit 0.Verify
pnpm verifygreen end to end (validate && typecheck && lint && lint:i18n-gate && hygiene && hygiene:tokens && build && test), at commit05158b0:The token ratchet moved down on both anchored layers (interaction 37,572 → 37,366; total 136,751 → 136,546); no ceiling was raised, and
business semanticsis untouched, so the README's~85kbanner band is unaffected.One declared deviation from the card
The card said to delete the four
KNOWN_UNCONFORMINGlines and leave the rest oftest/metadata-references.test.tsbyte-identical. No assertion, helper or fixture in that file changed — but one comment did: the docblock paragraph directly above the set, which existed to explain those four entries. It argued that the source should satisfy objectui's currentpage:headerrenderer rather than the spec, and stated that authoring ids "would delete every header button from four record pages". Leaving it would have kept the overturned reasoning in the tree, attached to an exemption that no longer exists, for the next agent to cite.It is rewritten in the form this same file already uses for a retired exemption — see the
sections[].collapsibleparagraph two entries down, kept and re-headed "RESOLVED UPSTREAM, exemption removed" — and it now records the 2026-09-06 ruling, verbatim and untranslated, that settled which side moves. Flagging it here rather than choosing quietly; the diff on that file is the four lines plus that one paragraph, and nothing else.Scope
Renderer behaviour is not reasoned about anywhere in this change. This repo declares zero
@object-ui/*dependencies and cannot install them, so it cannot measure that surface — which is why it has no business in this repo's reasoning. Renderer-side id resolution is objectui#6252 / #7182, ruled 2026-09-02 (option C, "ids are the contract").#1216is not addressed here.#1279's unlock criteria still need rewriting against this card's conclusion — a record-keeping action, out of scope for this PR.🤖 Generated with Claude Code
Generated by Claude Code
Generated by Claude Code