Skip to content

Declared overrides: a mapping override publishes but is never served, doc and mapping overrides cannot be restored, and an override's label can be hidden by translation #30062

Open

Description

@objectstack-fleet

epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

The maintainer: 「全部立,继续测试验证」 (2026-11-04), on the seat's evaluation of which metadata types should support override.

Measured by the seat through the metadata API and in a browser on main 63b86b385d, on examples/app-crm and examples/app-showcase, each overriding through its paired customization package. No domain:* label is set: triage routes this card.

Business reason

ADR-0146 D2 promises one mechanism: an item in the customization package replaces the base's item, and removing it brings the base's back. These gaps break that promise in ways a customer cannot see or undo. A published change that does nothing looks like success. A customization that cannot be removed leaves the customer stuck with it. A renamed page that keeps its old name looks like the rename failed.

Defects

1. A mapping override publishes and is not served. showcase_inquiry_feed, with overrides: save 200, publish published, then GET /api/v1/meta/mapping/showcase_inquiry_feed returns the base's body, with no overrides. SEALED_ROW_SERVED_OVERRIDE_TYPES in packages/metadata-protocol/src/protocol-package-bindings.ts:350 holds page, app, dataset, doc and book. Its note says mapping "is overridable and sealed too, and is not here: no card has measured its reads."

2. Doc and mapping overrides cannot be removed. DELETE /api/v1/meta/doc/showcase_docs_guide?package=com.example.showcase.custom answers 403, "provided by a managed package and is sealed against removal", and the override stays served. Mapping answers the same. The same call succeeded for view, dashboard, report, email_template, page, app, dataset, book and flow.

  • packages/spec/src/kernel/metadata-plugin.zod.ts:933 and :1191: mapping and doc are supportsOverlay: false, which refusePackagedBaseRemoval (packages/metadata-protocol/src/protocol.ts:9286) treats as sealed.
  • packages/metadata-protocol/src/protocol-packaged-base-refusal.ts:510 and :540: the pair-row admission is flow only.

3. An override's own label can be hidden by the base's translation. On the zh-CN CRM:

Item Override's value Served
Page crm_welcome label OVpage 欢迎页
Dataset opportunity_metrics label and description, and a measure label Changed The base's zh-CN text
View crm_lead.all and dashboard pipeline_dashboard label Changed The override's text
Report showcase_hours_by_status label OV-报表-1104 Runtime shows the override; the Studio header shows 工时按状态分布

A page's content did change, so this is about labels and descriptions, not the override itself. A new translation item in the pair does take effect (showcase_task read 任务 and then the new text), so a customer has a workaround, but nothing points to it.

4. The All metadata tile disagrees with the door. 全部元数据 marks 流程 只读, while a read-only flow's header offers 定制.

5. A refusal offers a way out that does not exist. A sharing_rule override is told to "create your own sharing_rule under a new name", and that create answers 403 NOT_CREATABLE. The same sentence cites ADR-0146 D6 for types that are outside D6's security catalog, and reads "a api" (protocol-packaged-base-refusal.ts:713).

Acceptance

  1. A mapping override is served by the reads and used at import, or the save refuses it loudly. Do not leave a published override that does nothing. Add it to the measured list, with a test.
  2. Removing a pair's override succeeds for every type isOverridableMetadataType admits that a pair can hold, and the base's item is served again. Pin this per type. A removal of a base's own item stays refused.
  3. Label precedence is one rule across types and across runtime and Studio. The seat's proposal: a translation in the pair, then the override's own label, then the base's translation. The maintainer may overrule this on the card.
  4. The tile and the door agree for every type.
  5. Each refusal names a remedy that works for that type: for example a Setup record for sharing rules and queues, and a new package version for a code-only type.

Not measured

An import through an overridden mapping, because the override is not served today. Report and email template behaviour beyond the label: the report did render; no email was sent.

Re-check

git grep -n "SEALED_ROW_SERVED_OVERRIDE_TYPES: ReadonlySet" origin/main -- packages/metadata-protocol/src/protocol-package-bindings.ts

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#26676#1 · zhuangjianguo · session_cdb7a717def74e719988f089fbaa18ff

    The maintainer, 2026-11-04: 「30079这种不是应该在元数据应用中自己去开发自定义操作吗?你的意见是批量换负责人放到内核吗?其他全部同意」.

    Ruling on acceptance item 3: the seat's proposal stands. Label precedence is a translation in the pair, then the override's own label, then the base's translation.

  2. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p1 kept · domain:server · 2026-11-04T12:59Z

    ⛔ Not a claim.

    • Read fresh. Three gaps in declared overrides (ADR-0146 D2): a mapping override publishes and is never served; doc and mapping overrides cannot be removed (403, sealed); and the base's translation hides an override's own label. A published change that does nothing, or cannot be undone, so p1 kept.
    • Fix site: packages/metadata-protocol (protocol-package-bindings.ts, protocol-packaged-base-refusal.ts), plus the spec supportsOverlay flags that the PR names.

    Generated by Claude Code

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Claim: PM loop round 1
    Session: session_01Utp6CYVV6fcAQrNTDQRvPb (seat) · dev = project card thread session_01Utp6CaHjE2N5aEp4ogQnWY
    Account: os-bill
    Branch: claude/project-thread-yenpdr (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-30062
    Domain: domain:server
    Seat: domain:server#5
    File surface: packages/metadata-protocol/src/** (pair-row removal admission, served-override set, refusal text, label resolution) and its tests; the label-resolution seam wherever measurement places it inside domain:server packages; item 4's tile only if its fix is in ui/** and minimal; one changeset. ⛔ packages/spec/**, docs/adr/**, skills/**, .claude/**, AGENTS.md (stop on breach; explain in the report)
    Container & model: M–L, mode:thread, model: default tier (opus) — dispatch-gates --tier at 31fe289f: no path-derived mandate, effort: xhigh (p1)
    Clause-②: no — removing a pair's own override and serving a published mapping override follow ADR-0146's chartered revert ("Restore package original" = delete the overriding item from .custom, so the base's document is served again) and D2; if item 1 lands as a loud save refusal, that arm narrows and owes a contract-review-tier review before the queue
    Metadata-protocol: semantic
    Responsibility: metadata-protocol's flow-only pair-row admission and its served-override set (reading at 0fd363d1, not built) | no platform path removes a doc or mapping override today | every customer of a .custom pair on 18.3.0 and main
    Thread-read: 6631274683
    Premise: holds — at 0fd363d1, SEALED_ROW_SERVED_OVERRIDE_TYPES = page, app, dataset, doc, book (no mapping); isPairRowRemoval admits only CONDITIONS_DELIVERED = {flow}
    Serial constraints cleared: #30106 (seat 3, Claim 6646484259, branch claude/project-thread-j915rv) may read protocol-served-overrides.ts; triage marks a possible metadata-protocol intersection — the dev merges main before the PR and after #30106 lands. No other in-flight claim names these paths.

    Ruling carried: acceptance item 3, the seat's proposal stands (6631250894). Seat 4 yielded this card to seat 5 in the project. Order: project file server-seat5/dispatch-30062.md, delivered to the card thread.

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Split · 2026-11-05T01:03Z. The card thread measured that acceptance item 3 (label precedence, ruled in 6631250894) can only be met in packages/spec/src/system/i18n-resolver.ts: translatePage, translateDataset, translateApp and translateBook take no packagedBase option, and a pair translation never wins on any type. Item 3's spec half is carried by #30193 (no domain:*, for triage). The PR on this card delivers items 1, 2, 4 and 5 as Refs #30062, not Fixes. At its landing this card is released back to the queue with item 3's server half (the protocol's getPackaged*Base accessors for page, dataset, app and book, and the PACKAGED_BASE_ACCESSORS rows) as pm:blocked, Blocked-by: #30193.

  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
    os-dev-report

    {
      "issue": 30062,
      "status": "done",
      "branch": "claude/project-thread-yenpdr",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30226",
      "session": "session_01Utp6CaHjE2N5aEp4ogQnWY",
      "premise_still_valid": true,
      "summary": "Delivers acceptance items 1, 2, 4 and 5 (PR body: Refs #30062 (items 1, 2, 4, 5), per the seat's ruling; item 3 is split to the spec lane and its server half stays on this card). Item 1: mapping joins SEALED_ROW_SERVED_OVERRIDE_TYPES, so a pair's mapping override is served by the by-name read the import door and the connector pull use. Item 2: isPairRowRemoval admits the pair's own row for every open overridable type (was flow only), so removing a doc or mapping override no longer answers 403 and every read serves the base's item again; a base-named removal keeps main's answer per kernel. Item 5: the declared_type_not_overridable sentence cites the type's own basis and names a remedy that works for it (same code, status and rule). Item 4: PageShell.tsx typeStateWord reads the Customize doors (studioOffersCustomize), not allowEnvironmentOverlay; StudioCustomizeControls.tsx untouched.",
      "tests": "metadata-protocol full: 312 files passed (4 skipped), 22375 tests passed (26 skipped); typecheck exit 0. objectql full: 548/548 files, 10910/10910 tests; typecheck exit 0. runtime meta-object-extension-item-door-fit.test.ts 6/6. ui: the six test files importing PageShell or DirectoryPage 149/149; turbo type-check --filter=@object-ui/app-shell 68/68 tasks. Ablations (scripts/ablation-replace.mjs wrap; objectql legs rebuilt metadata-protocol and passed ablation-dist-preflight present, then absent after restore; every leg restored blob == HEAD with git diff HEAD empty): A1 isPairRowRemoval flow-only: 7/78 red. A2 mapping out of the served set: 6/71 red. A3 pair check widened to the base: 2/71 red (doc, mapping, env kernel, base-named). A4 typeStateWord back to allowEnvironmentOverlay: 15/114 red. A5 refusal back to the old D6 'create your own' sentence: 16/87 red.",
      "gates": "Local: node scripts/pm/dispatch-gates.mjs --commands derived 57 commands, plus 8 changeset families once the changeset was added; each run with its exit code recorded before any pipe. dispatch-gates --ran: '65 derived famil(ies) accounted for — 64 run, 1 NOT-MEASURED', exit 0. NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET: 32 packages outside this closure have no dist), left to CI. check-plugin-teardown-shape --self-test exit 3 on the shallow clone, exit 0 after fetching the pinned fixture commit. check:type-check-debt exit 3 on a lock queue timeout, exit 0 re-run under the lock. Outside the derivation, also run: check:authz-resolver, check:error-code-casing, check:overlay-whitelist-table, check:changeset-fixed, all exit 0. pnpm lint exit 0; ui eslint on the two ui files 0 errors; check-nul-bytes exit 0. CI: the PR's check-runs are in_progress at report time (head 69812d8212).",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "13 paths, +448 / -61 against origin/main: source +173 / -45 (7 files, 4 of them comment-only), tests +259 / -16 (5 files), changeset +16 (1 file)",
      "files_changed": [
        "packages/metadata-protocol/src/protocol-package-bindings.ts",
        "packages/metadata-protocol/src/protocol-packaged-base-refusal.ts",
        "packages/metadata-protocol/src/protocol-diff-delete-load.ts (comments)",
        "packages/metadata-protocol/src/protocol-lock-state.ts (comments)",
        "packages/metadata-protocol/src/protocol-registry-hydration.ts (comments)",
        "packages/metadata-protocol/src/protocol.ts (comment)",
        "packages/metadata-protocol/src/protocol-package-bindings.sealed-override.test.ts",
        "packages/metadata-protocol/src/protocol.packaged-base-refusal.test.ts",
        "packages/objectql/src/protocol-custom-override-bare-slot-envelope.test.ts",
        "packages/objectql/src/protocol-flow-custom-override.test.ts",
        "ui/packages/app-shell/src/views/metadata-admin/PageShell.tsx",
        "ui/packages/app-shell/src/views/metadata-admin/DirectoryPage.stateVocabulary-29705.test.tsx",
        ".changeset/30062-declared-override-mapping-removal-remedies.md"
      ],
      "deviations": [
        "Closing line is Refs #30062 (items 1, 2, 4, 5), not the order's Fixes #30062: seat ruling after the item 3 fork report.",
        "Item 3 not implemented: it needs packages/spec/src/system/i18n-resolver.ts (fork condition); readings are in the PR's Acceptance notes.",
        "NODE_OPTIONS=--max-old-space-size=6144 for the closure build (spec DTS emit) and the gate runner, above the 4096 default.",
        "A ui run of the whole metadata-admin directory (721 test files) was stopped by its recorded PIDs after holding the lock about 15 minutes; narrowed to the six files that import PageShell or DirectoryPage, the full ui set is left to CI.",
        "origin/main was merged once at 474c030b before the PR; it has since moved 5 commits with no path overlap, and #30106 has not landed, so the second merge waits for #30106.",
        "Changeset level minor on @objectstack/metadata-protocol and @object-ui/app-shell (Metadata-protocol: semantic); app-shell is private but carries changesets in this repo.",
        "PR opened with no labels and no assignees; this session subscribed to the PR's activity (harness default)."
      ],
      "mcp_calls": "6 — mcp__github__issue_read get x2, issue_read get_comments x2, pull_request_read get x1 (PR #30183 body as a template), subscribe_pr_activity x1 (claude-code-remote, not a GitHub write). No GitHub MCP write.",
      "api_writes": "2 — relay repository_dispatch pr_create (run 41955305846, read_back landed/identical, PR #30226); this os-dev-report comment via post-stamped. git push is not a REST write.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: b · reach: exception: release-text · skills/objectstack-platform/SKILL.md ADR-0146 paragraph says the read honours a pair's declared override 'today only for a view, dashboard, report, email_template, translation or flow' (stale since page/app/dataset/doc/book, now mapping) and says nothing of the removal · dedupe words: skills ADR-0146 paragraph, declared override served types, Skills-docs follow-up · carrier: seat 5 (Skills-docs follow-up line in the PR body)",
        "carrier: #30063 / #30064 · noted, not filed: whichever of #30063 and this PR lands second flips the hard-coded page 只读 pins in DirectoryPage.stateVocabulary-29705.test.tsx (:129 tile, :178-:186 header) to 可定制; the new agreement rows derive from STUDIO_CUSTOMIZE_TYPES and follow on their own"
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb

    Seat ACCEPT on PR #30226 (items 1, 2, 4, 5) at head 5663983b: #30226 (comment) · pr_ready + automerge_enable sent 2026-11-05T03:18Z. This card stays open at merge: item 3 server half → pm:blocked, Blocked-by: #30193.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpm:dispatchedpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions