Repository navigation
docs(spec): onSuccess.navigate and a url target say an in-app path is an app-qualified console route (#25458) - #26435
Conversation
…n app-qualified console route (#25458) Claude-Session: https://claude.ai/code/session_01WGufzi6gpRSxJRE6UzJn2x Co-authored-by: Claude <noreply@anthropic.com>
…ng (#25458) Claude-Session: https://claude.ai/code/session_01WGufzi6gpRSxJRE6UzJn2x Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 146 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9688cace0a27bca7f7565a9b93520bb9dc793749 && git checkout 9688cace0a27bca7f7565a9b93520bb9dc793749
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 75afeffdf564ae0bd4c0baa18791f765d10a91a8 a7e78c3d2ff370f8485c669b3b6a6c0087c9f6b2 && git checkout -B drift-repro 75afeffdf564ae0bd4c0baa18791f765d10a91a8 && git merge --no-ff a7e78c3d2ff370f8485c669b3b6a6c0087c9f6b2
node scripts/docs-audit/affected-docs.mjs --json 75afeffdf564ae0bd4c0baa18791f765d10a91a8 |
Contract reviewServed-tier: Inputs read: card #25458 body and its 3 comments (triage audit line 6431826065, claim 6432980678, os-dev-report 6433346009); PR #26435 body, 7-path file list and net diff against ① Derived judgmentsAccept-set: unchanged — right. The hunks in Public surface: describe text and generated references only — right. The four regenerated Declared vs enforced — every new claim is delivered by the cited code:
hotcrm#2247 ruling C item 2(b) — inside it. The card quotes the ruling as "ask for the wording to say so, or for a Runtime-string hygiene. Neither new describe carries a tracker number or ADR id; Nits (not blocking): both docblocks still cite the console classifier as ② Semver level
③ Boundary flagsos-dev-report 6433346009:
Check-runs on the head, read 2026-10-27T04:00Z (47 runs): 26 success (incl. Implemented-by: VERDICT: PASS |
席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #25458
Clause-②: no
Metadata-protocol: none
维护者速读
onSuccess.navigate与type: 'url'动作的target现在写明:应用内路径是控制台路由,记录页是/apps/APP/OBJECT/record/ID,APP 是应用的路由段(包 id,应用名也能解析);规范里的示例与协议文档的示例同步改正。/开头的应用内路径」,没说要带应用段,作者照写/crm_opportunity/ID就走偏了;hotcrm#2247 裁决 C 第 2(b) 项要求把这一点写清楚,且不新增写法。packages/spec/src/ui/action.zod.ts(onSuccess 文档块新增的 console route 一段,以及navigate的 describe)、content/docs/protocol/objectui/actions.mdx(URL Actions 一节)、.changeset/25458-navigate-console-route.md。grep -n "console route" packages/spec/src/ui/action.zod.ts,预期 4 处命中(target 的文档块与 describe、onSuccess 的文档块与 navigate 的 describe)。What changes
Wording only, on the route ruling C on objectstack-ai/hotcrm#2247 ordered as item 2(b). No schema accepts or refuses anything it did not before; no new authorable form (no
${ctx.app}member, no object-plus-record target).packages/spec/src/ui/action.zod.ts,onSuccessdocblock: a new paragraph says that an in-app path is a console route, written without the console's mount prefix (/_consoleunder the framework CLI). The record page is/apps/APP/OBJECT/record/ID, and the object's list is/apps/APP/OBJECT.APPis the app's route segment (ADR-0048): its package id, e.g.app.objectstack.hotcrm. The app'snameresolves too, and it is the only segment that reaches an app other than the first in a package that ships several. A./path resolves against the current route. The contract declares no app-relative form, so write the app segment.navigate: '/apps/crm/tasks/${result.id}'becomes'/apps/crm/tasks/record/${result.id}'. The old one worked only through the console's shorthand redirect, which fires only when the last segment looks like a record id.onSuccess.navigate.describe(): the same facts in one sentence after the scheme set.targetdocblock and.describe()(thetype: 'url'scheme set): an in-app path is a console route, and a record is/apps/APP/OBJECT/record/ID. It points toonSuccess.navigatefor whatAPPis, so the explanation lives in one place.content/docs/protocol/objectui/actions.mdx, URL Actions: the same sentence. The exampletarget: /_console/dashboards/sales_overviewbecomes/apps/crm/dashboard/sales_overview. The old one carried the mount prefix the router adds itself, and the console has nodashboardsroute at the root; the dashboard route isdashboard/:dashboardNameunder/apps/:appName/*.gen:schema && gen:docs:content/docs/references/ui/action.mdx,ui/component.mdx,data/object.mdxandkernel/metadata-plugin.mdx(the last three embedActionSchema'starget)..changeset/25458-navigate-console-route.md:'@objectstack/spec': patch.The console's routes, quoted from
mainat9a0108cd:ui/apps/console/src/App.tsx:332, the app mount:Route path="/apps/:appName/*" element={AppContent}.ui/packages/app-shell/src/console/AppContent.tsx:1443, the record route inside it:Route path=":objectName/record/:recordId". At:1478is the shorthand":objectName/:maybeRecordId", which redirects only whenlooksLikeRecordIdholds (at least 6 URL-safe characters, not a reserved second segment).ui/packages/app-shell/src/utils/appRoute.ts:46,appRouteSegment: the package id_packageId, falling back toname.matchAppBySegmentmatches the package id first and then the name.Tests
Head
a7e78c3d.pnpm --filter @objectstack/spec build: lock VERDICT command-exit 0.pnpm --filter @objectstack/spec test: Test Files 727 passed (727), Tests 22009 passed, 1 todo (22010). Lock VERDICT command-exit 0.src/ui/action.test.ts,src/ui/action-on-success.test.tsandsrc/ui/action-url-target-scheme-set.test.tspass, 322 tests.pnpm --filter @objectstack/spec check:generated: exit 0, all 14 generated artifacts up to date.Acceptance notes
ui/.ui/packages/app-shell/src/utils/hostInConsolePath.tsis wired intouseConsoleActionRuntime.tsxandRecordDetailView.tsx. Onmaintoday, a rooted path whose first segment names no console route, such as/crm_opportunity/${result.id}, is hosted under the app the user is in. It no longer redirects Home. The wording does not promise that behaviour: the triage line and the dispatch exclude an app-relative form. The docblock names it as the console's accommodation and not a form the schema promises. The description and its example now match what the console does for the form they teach.packages/spec/src/ui/dashboard.zod.ts(actionUrl, ~:143/:151),packages/spec/src/ui/view.zod.ts(the empty-state link url, ~:1971) andpackages/spec/src/ui/component.zod.ts(the action row'stargetandonSuccess, ~:4066, :4085, :4166). This is noted here and not filed as a card; carrier: none.skills/objectstack-ui/rules/actions.md:71already writes the app-qualified record route (/apps/crm/opportunity/record/...). It agrees with the new text and is untouched (governed surface).navigation-target.ts. The file today isui/packages/core/src/actions/navigationTarget.ts. This is a naming drift outside the wording asked for here; noted, not touched.Verification
dispatch-gates (head a7e78c3)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 100 derived commands over 7 changed paths, 56 changed lines.The first pass gave 93 exit 0 and 7 exit 3 (PREREQUISITE NOT MET). I then built the closures
@objectstack/lint...,@objectstack/objectql...and@objectstack/client-react...(turbo, 37 of 37 tasks; lock VERDICT command-exit 0) and rangit fetch --unshallow origin main. After that, six of the seven re-ran to exit 0:check-plugin-teardown-shape.mjs --self-test,check:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-driftandcheck:lean-entry-closure.NOT MEASURED:
pnpm check:dual-build-cjs-loads, exit 3. It needs every workspace package'sdist(a fullpnpm build), so I left it to CI.--ranreconciliation:✓ dispatch-gates --ran: 100 derived famil(ies) accounted for — 99 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).Generated by Claude Code