Repository navigation
Commit 9d313f3
refactor(examples): every example-authored metadata name carries its package namespace (#30927)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D9HSxC7WngZADjXgb6UHCVp)_
domain:devx#1 · os-elon-musk · session_016WV4cyadQ5Zhih2y1GNTQm
Part of #30804
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:四个示例里包作者写的 40 个裸元数据名全部加上命名空间前缀(todo 20、crm 6、showcase
12、multi-package 1),连同所有拼写它们的地方(引用、种子、翻译键、测试、QA 清单)。另有一处 `os lint`
小改:平台按原名索取的权限集 `guest_portal` 不再被要求改名。
- **为什么改**:裁决 C(#30798「同意 c」)第二阶段的改名一半;PR 1(#30842)的 lint 已合并,本 PR
之后四个示例在该规则下 0 条警告。
- **风险与回滚**:只动示例(都是 private 包)、测试和文档,外加 `@objectstack/cli` 一个 patch。已有的
showcase 开发库里还是旧岗位名,重新播种即可。回滚即 revert。
- **先看**:① `examples/app-showcase/src/security/positions.ts`
与它在流程、共享规则、种子里的引用;② `lint.ts` 的 `PLATFORM_REQUESTED_BARE_NAMES`。
- **两分钟验证**:在任一示例目录跑 `os lint`,`naming/namespace-prefix` 应为 0 条;或 `pnpm
--filter @objectstack/example-showcase exec vitest run`。
- **需要你做的**:裁一个开放问题——`guest_portal` 是否豁免前缀规则(本 PR 按 (a) 豁免实现,见
Acceptance notes)。裁定前本 PR 保持草稿。
## What changes
**Every bare name the examples author now carries the package
namespace.** Each rename is the `fix` PR 1's `naming/namespace-prefix`
warning gives, and every reference that spells the name moves with it.
| Example (namespace) | Renamed |
|:--|:--|
| `app-todo` (`todo`) | dashboard `task_dashboard`; reports
`completed_tasks`, `tasks_by_owner`, `tasks_by_priority`,
`tasks_by_status`, `time_tracking`; dataset `task_metrics`; actions
`clone_task`, `complete_task`, `defer_task`, `delete_completed`,
`export_csv`, `mass_complete`, `set_reminder`, `start_task`; flows
`task_reminder`, `overdue_escalation`, `task_completion`,
`quick_add_task`; hook `task_logic` |
| `app-crm` (`crm`) | dashboard `pipeline_dashboard`; dataset
`opportunity_metrics`; positions `sales_rep`, `sales_manager`,
`finance_approver`; hook `opportunity_stage_probability` |
| `app-showcase` (`showcase`) | positions `contributor`, `manager`,
`exec`, `auditor`, `ops`, `field_ops_delegate`, `client_liaison`,
`client_portal_user`, `finance`, `legal`; sharing rules
`share_new_inquiries_with_field_ops`,
`share_key_account_qualified_contacts_with_managers` |
| `app-multi-package` (package `crm`) | app `multi_crm` →
`crm_multi_crm` |
Each new name is `<namespace>_<old name>`. The references that moved
with them:
- dataset, report and dashboard references, and the app navigation's
`dashboardName`;
- the action handlers `register-handlers.ts` binds by name, and the
flows' trigger and target names;
- flow approver steps (`{ type: 'position', value }`), `position:<name>`
actor ids, sharing-rule recipients (`sharedWith`), and the showcase's
seeded `sys_user_position` rows (`seed-approval-demo.ts`);
- translation bundles keyed by these names (todo zh-CN and ja-JP, crm,
showcase);
- the example tests, the 18 dogfood tests that boot an example and spell
one of these names (plus one dogfood fixture's comment), and 9 QA
platform-checklist area files (their `path#symbol` anchors included; the
`"change"` history lines are left as written).
Not renamed, on purpose: dashboard widget ids such as `id:
'tasks_by_status'`, which are not metadata names; approver `group:`
labels such as `finance`, which are not position names; and the crm
permission set `guest_portal`, which is the open question below.
**`os lint` leaves the platform-requested `guest_portal` permission set
alone** (`'@objectstack/cli': patch`). The public form doors' submit
context requests the permission set named exactly `guest_portal`
(`permissions: ['guest_portal']`,
`packages/rest/src/form-routes.ts:653`), and the grant's result masker
resolves a set registered under that name. ADR-0138's ledger keeps the
name ("fate: keep") and cites
`examples/app-crm/src/security/sales-positions.ts#GuestPortalProfile` as
its reference declaration. Renaming it to `crm_guest_portal`, which the
warning suggested, would leave the masker with nothing to find. The
exemption is one exported constant, `PLATFORM_REQUESTED_BARE_NAMES` in
`packages/cli/src/commands/lint.ts` (`{ permissions: ['guest_portal']
}`), so phase 3 (#30806) can read the same list. The same spelling in
any other collection, or any other permission set name, is still judged,
and the test pins both twins.
**`content/docs/ui/doc-pages.mdx`** no longer says the namespace prefix
is "no longer load-bearing for uniqueness". It now says the doc prefix
is the same contract `naming/namespace-prefix` applies to every
package-authored name, and it keeps saying that the runtime resolves
docs per package (ADR-0048).
## Why
Ruling C on #30798 (maintainer, verbatim 「同意 c」): every package-authored
metadata name carries its namespace, phased. PR 1 (#30842, merged as
`1697d5ca9c`) made `os lint` warn on every bare name. This PR brings the
examples, which authors copy from, onto that rule. The one-file ADR-0048
§5 bullet PR follows this one and carries `Fixes #30804`.
## Acceptance notes
- **Open question for a ruling: is `guest_portal` exempt?** This PR
builds on option (a), the seat's recommendation: a named exemption in
the lint, with the citation above. If the ruling is that it must be
prefixed, the constant, its one condition and its test come out, and the
form door at `form-routes.ts:653` and ADR-0138's ledger have to learn
the new name first. That is a runtime change outside this card. Phase 3
(#30806) needs the same answer.
- **Bare-name counts under `naming/namespace-prefix`**, measured with
`lintConfig` on each example's `objectstack.config.ts`. Duplicates are 0
in every row, before and after.
| Config | Before (main `1697d5ca9`) | After (this PR) |
|:--|--:|--:|
| `examples/app-todo` | 20 (actions 8, reports 5, flows 4, dashboards 1,
datasets 1, hooks 1) | 0 |
| `examples/app-crm` | 7 (positions 3, dashboards 1, datasets 1,
permissions 1, hooks 1) | 0 (6 renamed, `guest_portal` exempt) |
| `examples/app-showcase` | 12 (positions 10, sharingRules 2) | 0 |
| `examples/app-multi-package` | 1 (apps 1) | 0 |
| `create-objectstack` blank template | 0 | 0 (not touched) |
| `examples/embed-objectql` | 0 (no manifest namespace) | 0 (not
touched) |
Two of these renames also clear the cross-repo name coincidences phase
1's ADR-0048 text (#30836) measured: the datasets `task_metrics`
(app-todo) and `opportunity_metrics` (app-crm) shared a bare name with
HotCRM's; they are now `todo_task_metrics` and
`crm_opportunity_metrics`.
The showcase's two dotted capabilities (`showcase.export_data`,
`showcase.restricted_ops`) carry the namespace under Elon's
2026-11-06T11:08Z ruling (#30804, comment 6683456244), so they are not
renamed.
- **Fixtures left as written, on purpose.** These test files spell the
same words as their own self-contained fixtures and load no example, so
their names are not the examples' names: the ui workspace tests, the
runtime, lint, metadata-protocol and plugin unit tests, the `multi_crm`
fixtures in the cli and metadata tests, the position-name-fold census,
`docs/qa/scenarios/*.json`, and
`sharing-rule-criteria-required.dogfood.test.ts` (its `sales_rep`
recipient is invented for the test; the showcase has no such position).
The illustrative names in `content/docs/**` (for example `"positions":
["sales_rep"]` in `permissions/authentication.mdx`) are not tied to an
example either. The upgrade harness's historical database snapshots
(`packages/qa/dogfood/test/upgrade-harness/fixture-18.0.0-next.5/*.sql`)
and `populate-fixture.ts` record an 18.0 boot and stay as they are. The
`CHANGELOG.md` files are not hand-edited.
- **Held files not touched.**
`create-objectstack/src/templates/AGENTS.md`, `blank/README.md` (#30792)
and `examples/app-showcase/e2e/global-setup.ts` (#30552) needed no
change, and the showcase e2e specs spell none of the renamed names.
- **An existing showcase dev database** keeps its old position rows
until it is reseeded. The examples are private packages, and no
published data changes.
- **Out of scope, found on the way.** `pnpm --filter
@objectstack/example-todo test:mcp`
(`examples/app-todo/test/mcp-actions.e2e.ts`) exits 1 at its step 3 on
main `1697d5ca9` too: the seed and the step-3 insert fail with
`Organization is required` because the script boots with no
organization. Steps 1 and 2, which spell the renamed action names, pass
on both. No workflow or script runs it. Reported on the card for the
seat to route.
## Verification
- `os validate` in each of the four examples: exit 0.
- Example suites: app-showcase 46 files / 544 tests, app-todo 8 / 240,
app-crm 7 / 48, all passed.
- cli: `lint-namespace-prefix`, `generate-object-namespace-prefix`,
`generate-scaffold-validates` and `generate-stack-reach`, 4 files / 115
tests passed.
- Dogfood, real boots: the 18 changed dogfood test files plus
`sharing-rule-criteria-required`, 19 files / 205 tests passed;
`upgrade-18x-harness`, `multi-package-artifact` and
`install-local-purge-sample-data`, 3 files / 34 tests passed. After
rebasing onto `0e882086b` (which brought phase 1, #30836):
`bare-name-one-holder` and `multi-package-artifact`, 2 files / 13 tests
passed, and the three example suites again passed in full.
- `node scripts/check-platform-checklist.mjs`: OK, every `path#symbol`
anchor in the changed area files resolves.
- `os lint` scope check: `naming/namespace-prefix` reports 0 bare names
and 0 duplicates in all four examples (table above).
- eslint `--no-inline-config` on every changed `.ts`/`.mjs` file: exit
0. `typecheck` for example-todo, example-crm, example-showcase,
example-multi-package, dogfood and cli: exit 0 each.
- Local gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `73064de88` derived 94 commands; all 94
ran and exited 0. After the rebase, the derivation at `367de6725` lists
the same 94 commands, and `--ran` there reconciles 94 derived / 94 run /
0 NOT-MEASURED. The non-`--commands` listing also named
`check-issue-citations.mjs --census` (ran, exit 0) and three CI-only
commands that need the runner's matrix and `RUNNER_TEMP` (not run
locally).
<details><summary>Gates run at 73064de88 (94)</summary>
```text
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-adr-links.mjs :: exit 0
node scripts/check-adr-links.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-docs-section-name.mjs :: exit 0
node scripts/check-docs-section-name.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/check-section-landing-index.mjs :: exit 0
node scripts/check-section-landing-index.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/ci/snapshot-next.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm --filter @objectstack/lint run check:doc-security-posture :: exit 0
pnpm --filter @objectstack/spec run check:docs :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:skill-examples :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm --filter @objectstack/spec run check:yaml-examples :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:cli-test-child-env :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:doc-anchors :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:doc-frontmatter :: exit 0
pnpm check:docs-audit-scope :: exit 0
pnpm check:docs-redirects :: exit 0
pnpm check:docs-single-h1 :: exit 0
pnpm check:docs-spec-enumerations :: exit 0
pnpm check:docs-transcript-drift :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:examples-live-imports :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:i18n :: exit 0
pnpm check:i18n-coverage :: exit 0
pnpm check:i18n-walk-parity :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:platform-checklist :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:published-readme-links :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:react-page-adapter-contract :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:vendor-version-stamps :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
(`packages/spec` not touched.)
- [x] 2. Every name I added uses the casing for its kind.
- [x] 3. No formatter ran; `pnpm lint` passes. (eslint
`--no-inline-config` on every changed file: exit 0.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
(`@objectstack/cli` is the only published package touched; the examples
and dogfood are private.)
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (n/a)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
- [x] The *Before Submitting* list in CONTRIBUTING.md is done.
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_016WV4cyadQ5Zhih2y1GNTQm
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent acd190b commit 9d313f3
79 files changed
Lines changed: 386 additions & 325 deletions
File tree
- .changeset
- content/docs/ui
- docs
- qa/platform-checklist/areas
- screenshots
- examples
- app-crm
- src
- apps
- dashboards
- datasets
- hooks
- security
- translations
- test
- app-multi-package
- src/packages
- core
- orders
- app-showcase
- src
- automation/flows
- data/seed
- docs
- security
- system/translations
- test
- app-todo
- src
- actions
- apps
- dashboards
- datasets
- flows
- objects
- reports
- translations
- views
- test
- packages
- cli
- src/commands
- test
- qa/dogfood/test
- fixtures
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
74 | 74 | | |
75 | 75 | | |
76 | 76 | | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
81 | 83 | | |
82 | 84 | | |
83 | 85 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2736 | 2736 | | |
2737 | 2737 | | |
2738 | 2738 | | |
2739 | | - | |
| 2739 | + | |
2740 | 2740 | | |
2741 | 2741 | | |
2742 | 2742 | | |
2743 | 2743 | | |
2744 | 2744 | | |
2745 | 2745 | | |
2746 | | - | |
| 2746 | + | |
2747 | 2747 | | |
2748 | 2748 | | |
2749 | 2749 | | |
| |||
2754 | 2754 | | |
2755 | 2755 | | |
2756 | 2756 | | |
2757 | | - | |
| 2757 | + | |
2758 | 2758 | | |
2759 | 2759 | | |
2760 | 2760 | | |
| |||
3224 | 3224 | | |
3225 | 3225 | | |
3226 | 3226 | | |
3227 | | - | |
| 3227 | + | |
3228 | 3228 | | |
3229 | 3229 | | |
3230 | 3230 | | |
| |||
3254 | 3254 | | |
3255 | 3255 | | |
3256 | 3256 | | |
3257 | | - | |
| 3257 | + | |
3258 | 3258 | | |
3259 | 3259 | | |
3260 | 3260 | | |
| |||
0 commit comments