Skip to content

fix(rest): the /meta dashboard and view reads hand the translator the packaged base, so a published org overlay beats the packaged catalog - #20832

Merged
objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-20730-meta-packaged-base-resolver
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/issue-20730-meta-packaged-base-resolver

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20730

Clause-②: no

What this changes

An org's published edit to a packaged dashboard or view is now what the /meta item and list reads serve, in every locale. Before, the reads served the bundle's translation of the string the package shipped.

packagedObjectBaseOf in packages/rest/src/meta-item-read-gate.ts is now the one per-type packaged-base resolver that the triage asked for. It reads one table, PACKAGED_BASE_ACCESSORS:

type protocol accessor
object getPackagedObjectBase(name) (unchanged)
dashboard getPackagedDashboardBase(name)
view getPackagedViewBase(name), by the served item's qualified OBJECT.VIEW_KEY registry name

translateMetaDocument (the item read) and translateMetaList (the list read) now resolve the protocol for every type in that table instead of for object only. Both /meta transports (the REST server's routes and the runtime's HTTP dispatcher) call these two functions. There is no second resolver; a future type with a packaged-base accessor adds its row to the table. The translation rule itself (ADR-0029 D9.2a, an explicit override beats a packaged default) is unchanged in @objectstack/spec/system. This PR only hands the translator the base it could not see.

packages/rest/src/rest-server.ts is not touched: it delegates to these functions and already hands them its protocol. packages/metadata-protocol and packages/spec are read, not edited.

Pins

packages/rest/src/meta-dashboard-view-i18n-explicit-override.test.ts (52 tests) runs over the REAL ObjectStackProtocolImplementation and a REAL SchemaRegistry, through the /meta routes. The packaged items are registered the way the boot registers them, and the org overlay rows are seeded the way a published overlay stores them.

  • §1: the resolver asks each type for its own accessor. It asks nothing for action, app, dataset, page, report, toString or constructor. It answers undefined for an empty name, a missing accessor or a throwing accessor.
  • §2 dashboard: for the item read and the list read, for an admin and a member of the same org, in en and zh-CN:
    • after an overlay and a publish, the edited widget serves the edit;
    • the unedited widget stays translated;
    • after a reset, the shipped title is served, translated.
    • Control: a packaged dashboard whose catalog has no widget titles serves an overlay edit exactly as before.
  • §3 view: the same three cells for showcase_task.in_progress. The unedited view is showcase_task.urgent.

One line in scripts/engine-double-contract.pinned.json, written by check-engine-double-contract --write for the new findOne double. The double calls assertEngineFindOnePredicate.

Ablations (one-shot, at 87f1867ea, source-resolved)

Each ablation went through scripts/ablation-replace.mjs. The anchor hit once in every case, and each restore was proven by the blob hash matching HEAD and by an empty git diff HEAD.

mutation result
resolver answers object only (blob 38a35644 to 4aeefa5c) 17 failed / 46 passed of 63. The failures are all 16 edit cells plus the §1 dispatch case. The unedited, reset and control cells and the object suite stay green.
list read resolves the protocol for object only 8 failed / 44 passed of 52. The failures are exactly the 8 list-read edit cells.
item read resolves the protocol for object only 8 failed / 44 passed of 52. The failures are exactly the 8 item-read edit cells.

Measured in a real boot

Scratch probe, not committed: bootStack(showcaseStack, { orgContext: true }), the seeded admin plus a signed-up member of the same org, on tree e830f24cb. The probe ran three phases: pristine; overlaid (admin PUT ?mode=draft then POST publish, each answering 200, on system_overview, on the showcase control showcase_ops_dashboard and on showcase_task.in_progress); and reset (admin DELETE, answering 200). In every phase it read /meta/dashboard/NAME, /meta/view/NAME, /meta/dashboard, /meta/view, /meta/app and /meta/object for both callers in en and zh-CN.

Before (the rest dist rebuilt from the ablated resolver; ablation-dist-preflight found the marker in 2 built files) compared with after (HEAD): 12 served leaf fields differ, all in the overlaid phase:

  • system_overview widget_total_users.title on the item and list reads, admin and member, en and zh-CN (8). It went from Total Users / 用户总数 to Total Users (edited-20730).
  • showcase_task.in_progress label on the item and list reads, admin and member, zh-CN (4). It went from 进行中 to In Progress (edited-20730). An en reader was already served the edit before this change.
  • 0 diffs in the pristine and reset phases, on the control dashboard, on every other dashboard and view, and on the app and object lists.

The restore leg rebuilt rest, and ablation-dist-preflight --absent found the marker absent from all 6 built files. The card cites 16 changed fields from the parent card's probe. That probe covered a different set of reads, so the two counts are not comparable. Here the dashboard alone accounts for 8.

The rendered board, measured in a browser

The console was built from objectui db11afd4967c (this repo's .objectui-sha) with scripts/build-console.sh and served by pnpm dev -- --fresh at 8ee4569fa. The browser was headless Chromium from /opt/pw-browsers/chromium, signed in through the console's form as the seeded admin, with the browser locale set to en and to zh-CN.

  • After the overlay was published, the console's own /api/v1/meta/dashboard responses carried widget_total_users.title = Total Users (edited-20730) in both locales, and its /api/v1/meta/view responses carried label = In Progress (edited-20730).
  • The drawn board at /_console/apps/setup/dashboard/system_overview still showed Total Users (en) and 用户总数 (zh-CN).
  • The view at /_console/apps/showcase_app/showcase_task/view/in_progress:
    • en: the tab showed the edit, and the breadcrumb showed In Progress;
    • zh-CN: both the tab and the breadcrumb showed 进行中.
  • After the reset, both were served and drawn as shipped.

So the server half is fixed, and the console still re-resolves these strings against the bundle in the browser. That half is objectui's. The measurement is handed to the seat to file, as the triage directed.

Docs and changeset

  • content/docs/ui/translations.mdx gains "An edit beats the packaged catalog", which states the dashboard rule and the view rule side by side (which strings are compared, and how each is matched), the three consequences, and the object rule by reference.
  • .changeset/20730-meta-packaged-base-dashboard-view.md: a patch for @objectstack/rest. It says in words that the console still draws the packaged translation.

Verification

  • pnpm --filter @objectstack/rest test: 233 files, 4524 passed, 77 skipped. test:repo: 1 file, 8 passed. typecheck: tsc --noEmit plus check:test-typecheck OK, and the new file is in the test program. All at 0a60a2f61, after merging origin/main.
  • Readers of the edited module in other packages:
    • runtime meta-list-projection-parity: 658 passed;
    • runtime meta-item-read-gate-parity and meta-list-read-gate-parity: 118 passed;
    • http-conformance hono-meta-list-read-gate: 6 passed.
  • dispatch-gates --commands at 8ee4569fa derived 97 families. All 97 were run and reconciled with --ran: 97 run, 0 NOT-MEASURED, 0 UNRUN. check:engine-double-contract failed at 0a60a2f61 (the new double was not yet in the ledger) and passed at 8ee4569fa after the --write. The 20 changeset and doc families were re-run at 2b8df02e7 and all exited 0.
  • Lint, narrowed and proven at 2b8df02e7:
    • Population: eslint.config.mjs matches **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}, so 2 of the 5 changed paths are in it (the others are .md, .mdx and .json).
    • eslint --no-inline-config --format json on those 2 files: 2 files, 0 errors, 0 warnings.
    • The config enables no type-aware linting (0 hits for parserOptions.project or projectService), so this diff cannot move a verdict on an untouched file.

Acceptance notes


Generated by Claude Code

…their packaged base, so a published org overlay beats the packaged catalog

packagedObjectBaseOf becomes the one per-type packaged-base resolver:
object answers getPackagedObjectBase as before, dashboard answers
getPackagedDashboardBase and view getPackagedViewBase (by the served
item's qualified registry name). translateMetaDocument and
translateMetaList resolve the protocol for every type the table covers.

Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB
Co-authored-by: Claude <noreply@anthropic.com>
…packaged catalog; changeset for @objectstack/rest

Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB
Co-authored-by: Claude <noreply@anthropic.com>
Written by check-engine-double-contract --write for the dashboard and view
packaged-base pin file.

Claude-Session: https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

8 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
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 15 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 73155fedcacc215565c4eef6d9899977e0707010 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 262804cfd94548466e8794783360042b5a27d024 — the merge of head 2b8df02e7aca4b62cbf44ea8860d6f8a638916aa into base 73155fedcacc215565c4eef6d9899977e0707010, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 262804cfd94548466e8794783360042b5a27d024 && git checkout 262804cfd94548466e8794783360042b5a27d024
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 73155fedcacc215565c4eef6d9899977e0707010 2b8df02e7aca4b62cbf44ea8860d6f8a638916aa && git checkout -B drift-repro 73155fedcacc215565c4eef6d9899977e0707010 && git merge --no-ff 2b8df02e7aca4b62cbf44ea8860d6f8a638916aa

node scripts/docs-audit/affected-docs.mjs --json 73155fedcacc215565c4eef6d9899977e0707010

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 2b8df02e7aca4b62cbf44ea8860d6f8a638916aa
Local-runs: none

Inputs read: card #20730 body and its five comments (5901102672, 5901360064, 5904663679, 5906742753, 5908785750); PR #20832 body and file list; the net diff git diff 261c529f0 refs/review/pr-20832 (merge-base against origin/main, 5 files, +474/-16, the same five paths the file list and the dev report name); the check-runs on the head, collapsed latest-per-name; at the merge-base 261c529f0: getPackagedObjectBase, getPackagedDashboardBase, getPackagedViewBase and lookupArtifactItem (packages/metadata-protocol/src/protocol.ts), TranslateDocumentOptions.packagedBase, translateDashboard, translateView, translateGlobalFilter, valueOverridesPackagedBase and the translator dispatch table (packages/spec/src/system/i18n-resolver.ts), the pre-state of translateMetaList / translateMetaDocument / packagedObjectBaseOf, both transports' resolveProtocol (rest-server.ts, packages/runtime/src/domains/meta.ts), expandViewContainer and the engine's view registration, ADR-0126's tier table and ADR-0029 D9.2a, check-engine-double-contract.mjs and its pinned ledger, clause2-line.mjs, check-changeset-no-major.mjs, check-doc-authoring.mjs ROOTS, and the pm-dispatch filing gate. Governed surfaces: none of the five paths is one (Governed Surface Queue Guard success).

Check-runs on the head, converged (the one run still in_progress when the brief was written, Lint & Repo Gates, completed success at 2026-09-30T10:21:01Z; polled in the background until every run completed): 35 names, all on 2b8df02e7, 33 success, 2 skipped (Console Pin Gate, path-filtered with no .objectui-sha change; Packed-tarball smoke (opt-in)), 0 failed. The seven required contexts are all success: Lint & Repo Gates, TypeScript Type Check, Test Core, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard. Those conclusions are the gate verdicts this record relies on; nothing was built, run or re-run here.

① Derived judgments

(a) The resolver — one table, three accessors, both callers. RIGHT.

  • packagedObjectBaseOf now reads PACKAGED_BASE_ACCESSORS, a module-private ReadonlyMap of object to getPackagedObjectBase, dashboard to getPackagedDashboardBase, view to getPackagedViewBase. Each row hands the translator the base its own rule compares against: object is unchanged (the owner's pre-fold declaration, what translateObject compares — ADR-0029 D9.2a); dashboard is lookupArtifactItem('dashboard', name), the packaged body keyed by the dashboard name, which is the key the catalog (dashboards.NAME.widgets.ID.title) and translateDashboard both use; view is lookupArtifactItem('view', name) keyed by the served item's registry name. That name IS the qualified OBJECT.VIEW_KEY: expandViewContainer names each expanded item ${object}.${key} and the engine registers every one under it, the item read passes document.name and the list read passes each element's item.name, and the accessor's own docblock demands exactly that name and refuses the bare key. lookupArtifactItem prefers the composite packageId:name entry, so the base handed over is the packaged body and never the overlay hydrated under the plain key — the comparison runs against the right side.
  • Unknown type: Map.get answers undefined and the function returns before it reads the name or the protocol — the same early exit the old type !== 'object' guard gave, and a Map rather than an object literal, so toString / constructor cannot resolve to an accessor (§1 pin). Empty name, a protocol without the accessor and a throwing accessor still answer undefined, the edges unchanged.
  • Both callers gate on the same table: translateMetaList resolves the protocol once per page when PACKAGED_BASE_ACCESSORS.has(metaType), translateMetaDocument the same per document, and both hand the result through packagedObjectBaseOf, which re-gates. So every type in the table and nothing else — of the seven translatable types, action, app, dataset, page get no protocol resolution and no base, exactly as before. Both transports already hand resolveProtocol unconditionally (RestServer.metaItemTranslationSources / metaListTranslationSources, and the runtime's metaTranslationSources returns the MetaDomainProtocol it was given), so no transport edit was needed and none was made; rest-server.ts is untouched as the claim's stop line demanded.
  • One consequence read and found harmless: on a view list the container element the boot registers under the bare object name now also reaches getPackagedViewBase, which answers the container; translateView compares its absent label and valueOverridesPackagedBase answers false for a non-string value, so that element translates exactly as before.

(b) The behaviour the card asks for. RIGHT, each claim pinned; nothing served differently for a caller or type the card did not name.

  • meta-dashboard-view-i18n-explicit-override.test.ts (52 tests) runs the real ObjectStackProtocolImplementation over a real SchemaRegistry through the registered /meta routes, registering the packaged items the way the engine does (dashboard by name; the view container under the bare object name AND each expanded item under OBJECT.VIEW_KEY) and seeding the overlay as the published org row (package_id: null, the org, state: 'active'); the 14th constructor argument is i18nServiceProvider, verified against the constructor at the merge-base.
  • §2 dashboard and §3 view each cover the eight cells — item and list read, admin and member of one org, en and zh-CN — three times: the edited widget / view serves the edit; the unedited widget (widget_organizations) / the unedited view (showcase_task.urgent) stays translated; with no overlay row (the state after a reset) the shipped string is served, translated. The en cell matters: the bundle's en repeats the shipped string, which is the shape platform-objects ships and the shape that made an en reader lose the edit. The showcase control (a dashboard whose catalog carries only a label) serves an overlay edit on both reads with its label still translated. The object path: its accessor row is byte-unchanged and the PR's ablation of the resolver to object-only leaves the object suite green.
  • The card's pins from triage 5901360064 and pointer 5904663679 are each one of those cells. The reset pin is served at the read boundary by absence of the row; the write verb itself is not driven in the pin, and the PR's real-boot probe (DELETE answering 200, 0 served diffs in the reset phase) covers that leg.
  • Reach beyond the card: none. The only new served behaviour is on dashboard and view, both named by the card; the probe's 12 changed leaf fields are all in the overlaid phase on the two overlaid items (8 dashboard cells; 4 view cells in zh-CN, en having served the edit already), with 0 diffs on the control, every other dashboard and view, and the app and object lists. The card's 16 came from the parent's probe over a different read set, which the PR says rather than reconciles away.

(c) Changeset and docs. RIGHT.

  • .changeset/20730-meta-packaged-base-dashboard-view.md: @objectstack/rest: patch. Every sentence checks against the diff and the merge-base: the four routes named are the item and list doors for the two types; "the translators already let an edited string win when handed the item as the package shipped it, and the metadata protocol already answers that item" is translateDashboard / translateView plus the two accessors on main since 1940afdaf and 9ad654487 (both ancestors of the merge-base); "the change is in the translation step that both /meta transports share" is the two shared functions; "a view is looked up by its full name" is (a). The four consequences are the four pinned cells. "This fixes what the metadata reads serve, not yet what the console draws" scopes the claim to what the diff delivers and states the measured console behaviour at the pin db11afd4967c in words. "Nothing to migrate: no key, export or route changed" is true. The body carries no tracker number; the filename's 20730- prefix is the convention every one of the 120 changesets at the merge-base follows. Check Changeset success.
  • content/docs/ui/translations.mdx, new H3 "An edit beats the packaged catalog" under "How a locale is chosen", directly after the sentence about what the REST metadata endpoints serve. Its table was checked string by string against the translators: dashboard label / description; each widget's title, description and sub-caption matched by widget id (the sub-caption is options.description on the document under the bundle key subCaption, and the page names it by that key); each global filter's label and static option labels matched by the filter key (name, else field) and the option value — all in translateDashboard / translateGlobalFilter; view label / description, each bulk action's label, confirmText, confirmLabel and its params' label, help, placeholder matched by name — all in translateView's docblock and body. "Dashboards and views are the translated types an organization can edit in place" is ADR-0126 tier A (view, dashboard, report, translation, email_template) intersected with the translator table (view, action, object, app, dashboard, dataset, page) — exactly those two. "Never shipped counts as edited" is packagedPart answering {} for a missing part, against which any authored string diverges. The claim is scoped to "the metadata reads serve"; the object rule is stated by reference to data-modeling/object-extensions, which exists. No tracker number (the page is inside check-doc-authoring's content ROOT). No new page, so meta.json owes nothing.
  • One observation, not a defect of this diff: the pre-existing sentence just above the new section ("so the Console and any SDUI client get translated metadata without doing lookups themselves") is now measured false for edited strings at the pinned console. It is the objectui defect's prose, and the objectui card's landing is where it gets amended.

(d) scripts/engine-double-contract.pinned.json. RIGHT — exactly the row the gate demands and nothing more. One row added (831 to 832): packages/rest/src/meta-dashboard-view-i18n-explicit-override.test.ts / findOne / pinned: 1, in the ledger's sort position (file, then verb). The test's findOne double calls assertEngineFindOnePredicate(table, q), which is the findOne slice's pinCall; the find double has no slice in this gate (the read side is check-where-matcher-conformance.mjs), so no second row is owed. The gate's own header says the ledger is written by --write, never hand-edited, which is how the row arrived (8ee4569fa).

② Semver level

@objectstack/rest patch and Clause-②: no — RIGHT. The Clause-② question (「本卡放宽接受集或扩大公开面吗」, clause2-line.mjs) is answered no truthfully: no key is added to any published payload (the served fields are the same fields, now carrying the org's own value where the rule already said they should), no export is added (PACKAGED_BASE_ACCESSORS is a module-private const), no route, query parameter or write path changes, so no accept set moves. The behaviour change is a defect fix that brings two types under the rule ADR-0029 D9.2a records and the object arm already applied. The line is at line start in the PR body, which is where check-changeset-no-major.mjs reads it (its docblock: "the Clause-②: line is a PR body line").

③ Boundary flags

Deviations (7), each answered:

  1. Ledger row outside the claimed surface — accepted; judged in ①(d) as exactly the gate-demanded row.
  2. Pin file named beside its object twin — accepted; the new file extends the twin's host shape (RestServer, registered routes, an overridden resolveExecCtx) with a real registry and real protocol.
  3. origin/main merged into the branch (0a60a2f61) — accepted; the net diff against the merge-base is the five files and nothing foreign.
  4. Stop line held, rest-server.ts untouched — accepted and verified in ①(a): both transports already hand the protocol.
  5. Changeset and docs scoped to the metadata reads — accepted and verified in ①(c).
  6. Heavy runs under os-verify-lock, background starts, teardown by recorded pid — procedural, not on the diff; no record item.
  7. Cleanup after the report, outcome unreported — procedural; nothing on the head depends on it. The seat may confirm the worktree is gone; not a review matter.

Open questions: none declared, none found.

Out-of-scope findings (3):

  1. Class a against objectui — the evidence supports the class and the reach it claims. reach: per the filing gate is a public entry with one measured wrong result: the console UI at /_console/apps/setup/dashboard/system_overview and /_console/apps/showcase_app/showcase_task/view/in_progress, measured in a browser at objectui db11afd4967c (this repo's pin) on framework 8ee4569fa, in en and zh-CN, drawing the shipped strings while the console's own /api/v1/meta/dashboard and /api/v1/meta/view responses carry the published edit — the wrong answer is the gap between those two readings, and the pristine and reset phases draw as shipped, so it is the edit that is lost. The dashboard source site is named at the pin (DashboardRenderer.tsx tWidgetTitle); the view tab and breadcrumb path is declared untraced, so the card's reach is what was drawn, not a source claim for the view half. Dedupe words are supplied. It is the seat's to file in objectui, as triage 5901360064 directed.
  2. Stale docblocks (RestServer.metaItemTranslationSources / metaListTranslationSources, runtime metaTranslationSources) still say "object base" — comments only; the behaviour is the shared functions, verified correct. Carrier PR feat(rest): GET /data/:object/export?template=true answers an xlsx import template (#18386) #20683 for rest-server.ts; the runtime file has none and rides its next edit. Noted, not filed — right.
  3. packagedObjectBaseOf keeps its object-only name because RestServer.packagedObjectBase (held by PR feat(rest): GET /data/:object/export?template=true answers an xlsx import template (#18386) #20683) calls it — noted, not filed — right; a rename lands with the next edit of that file.

Implemented-by: claude/issue-20730-meta-packaged-base-resolver
Reviewed-by: session_01VvcEokUG1tvVxkceYfR5XB

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 10:25
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 7afdc5c Sep 30, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20730-meta-packaged-base-resolver branch September 30, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants