Skip to content

Bare-name phase 2: the namespace-prefix lint warns on every bare non-object name; first-party templates and examples adopt the prefix (ruling C on #30798) #30804

Open

Description

@objectstack-fleet

epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu

Filing-gate category: ② execution of a maintainer ruling. Decision #30798 ruled C, maintainer verbatim (Claude Code session, 2026-11-06): 「同意 c」: every package-authored metadata name carries its namespace, phased. Routing, verbatim: 「能交给车队开发的你不要自己开发」.

Phase 2 of 3 (lint, templates, examples). It can run in parallel with phase 1.

Problem

The existing naming/namespace-prefix rule (packages/cli/src/commands/lint.ts:319-326) flags only intra-package duplicates, and its message says "Distinct packages may reuse the same name freely; the namespace prefix is an optional convention, not a collision-avoidance requirement". That is now the opposite of the ruled contract. ADR-0048 §5's "[done] lint warns on non-prefixed app/page/dashboard/flow/action/report/dataset" is out of date.

Ask

  1. Re-widen the rule to warn on every bare package-authored top-level name: every type except names derived from a prefixed object (fields, object extensions, container views <object>.<key>) and names already namespaced (translations <ns>_<locale>). Rewrite the message to state the contract and the rename.
  2. Correct ADR-0048 §5's lint bullet in the same PR.
  3. Prefix the names in the first-party templates and examples (examples/*, create-objectstack templates), so a new project starts compliant. Record the before/after count of bare names; it is the migration baseline phase 3 needs.

Out of scope: the published AI-authoring skills (sibling card, domain:skills), refusing at defineStack (phase 3), and the scenario cards (#30795).

Reader: the domain:devx lane seat, from pm:queue.


Generated by Claude Code

Activity

  1. added
    priority:p1High: required for production / M2
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 6, 2026
  2. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-elon-musk · session_016WV4cymvo9YoyLwKCXXBNw

    Claim: PM loop round 5
    Session: session_016WV4cymvo9YoyLwKCXXBNw
    Account: os-elon-musk
    Branch: claude/project-thread-uogs4i (the card thread's platform-assigned branch; a measured platform exception to claude/issue-<n>-<slug>) · card thread session session_016WV4cyadQ5Zhih2y1GNTQm
    Worktree: objectstack-issue-30804
    Domain: domain:devx
    Seat: domain:devx#1
    File surface: PR 1 covers packages/cli/src/commands/lint.ts (naming/namespace-prefix) with its tests and a @objectstack/cli changeset, plus packages/cli/src/commands/generate.ts and the generator tests that spell scaffold names. The os generate scaffolds are first-party templates under ruling C, and generate-scaffold-validates.test.ts pins them to zero findings, so they take the namespace prefix in the same PR (amended 2026-11-06, dev report). The ADR-0048 §5 lint bullet (docs/adr/0048-cross-package-metadata-collision.md, Tier H) goes in its own one-file PR. PR 2 covers the metadata names in examples/* and packages/create-objectstack/src/templates/**, plus the tests and docs that spell those names. Not the published skills (#30805), not defineStack (#30806), not the scenario cards (#30795).
    Container & model: M, mode:thread, model: default tier, effort: xhigh (p1). Two PRs: the rule first, then the renames, so the rename PR lands on a rule that already says the contract.
    Clause-②: no — the rule stays severity: 'warning', and no door refuses anything new (refusal is phase 3, #30806).
    Metadata-protocol: none
    Responsibility: execution of maintainer ruling C on #30798 (「同意 c」), routed to the fleet (「能交给车队开发的你不要自己开发」).
    Thread-read: none
    Premise: holds — on origin/main, naming/namespace-prefix (packages/cli/src/commands/lint.ts ≈ L300–326) still warns only on intra-package duplicates, and its message still says "the namespace prefix is an optional convention".
    Serial constraints cleared: no open PR touches packages/cli/src/commands/lint.ts or ADR-0048. Two open PRs touch neighbouring files that PR 2 must not edit until they land or must merge around: #30792 (create-objectstack/src/templates/AGENTS.md, blank/README.md) and #30552 (examples/app-showcase/e2e/global-setup.ts). Checked 2026-11-06T04:25Z. Phase 1 (#30803, domain:engine) runs in parallel by the card's own word.

  3. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-elon-musk · session_016WV4cyadQ5Zhih2y1GNTQm
    os-dev-report

    {
     "issue": 30804,
     "status": "done",
     "phase_part": "PR 1 of 2 (lint rule + tests); PR 2 (examples and templates) follows after PR 1 merges",
     "branch": "claude/project-thread-uogs4i",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/30842",
     "head": "c4ad5c80",
     "session": "session_016WV4cyadQ5Zhih2y1GNTQm",
     "premise_still_valid": true,
     "summary": "Premises measured on origin/main 100303c0: naming/namespace-prefix only reported intra-package duplicates, its message called the prefix an optional convention, and the ADR-0048 §5 lint bullet was stale. The rule now warns on every bare top-level name in the 28 judged collections of PLURAL_TO_SINGULAR (objects, views and docs are judged elsewhere), with the rename as fix. It exempts overrides items, packages without a namespace, and names that are the namespace or start with <ns>_, <ns>. or sys_ (one predicate, carriesPackageNamespace). The duplicate finding stays without a fix and without the optional-convention sentence. Bounded in-place fix accepted by the seat: os generate prefixes every scaffolded non-object name through the same predicate. Card assignee untouched.",
     "baseline_counts": {
      "measured_at": "origin/main 100303c0, under this PR's rule, before PR 2",
      "examples/app-todo": {
       "bare": 20,
       "by_type": {
        "actions": 8,
        "reports": 5,
        "flows": 4,
        "dashboards": 1,
        "datasets": 1,
        "hooks": 1
       }
      },
      "examples/app-crm": {
       "bare": 7,
       "by_type": {
        "positions": 3,
        "dashboards": 1,
        "datasets": 1,
        "permissions": 1,
        "hooks": 1
       }
      },
      "examples/app-showcase": {
       "bare": 12,
       "by_type": {
        "positions": 10,
        "sharingRules": 2
       },
       "strict_reading": "14 if <ns>. does not carry the namespace (adds capabilities 2)"
      },
      "examples/app-multi-package": {
       "bare": 1,
       "by_type": {
        "apps": 1
       },
       "note": "multi_crm in package crm -> crm_multi_crm"
      },
      "create-objectstack blank template": {
       "bare": 0,
       "note": "only blank_note; every other barrel empty (measured by inspection: the template has no node_modules to load)"
      },
      "examples/embed-objectql": {
       "bare": 0,
       "note": "declares no manifest namespace"
      },
      "duplicates": 0
     },
     "tests": "Rewrote lint-namespace-prefix.test.ts: one bare name per judged collection (it.each over the 28), each exemption on its own (prefixed, name===ns, sys_, <ns>. with its billing.refund twin, objects, fields, views, extensions, translations, docs, functions, overrides with a warning twin, no namespace), message and severity pins, and the duplicate sentence pinned verbatim. Updated the per-package suite (#17821) and three generator suites whose pins encoded bare scaffold names. cli vitest (unit+integration): 590 files passed / 1 skipped, 7272 tests passed. Nightly e2e tier on 19 generate/init/scaffold/lint files: 250 tests passed. cli typecheck exit 0 (test layer with --max-old-space-size=8192 after a default-heap OOM). eslint --no-inline-config on the 9 changed files exit 0. spec check:liveness exit 0 (no ledger cites the renamed duplicateNameIssues).",
     "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at c4ad5c80: exit 0, 61 commands. All 61 ran and exited 0. Two first exited 3 (PREREQUISITE NOT MET): check-plugin-teardown-shape --self-test needed its pinned fixture 621a4876 fetched into the shallow clone, and check:dual-build-cjs-loads needed 7 packages built. Both were re-run green. --ran reconciliation: exit 0, 61 derived / 61 run / 0 NOT-MEASURED. Record: gates-ran-c4ad5c80.txt, inlined in the PR body.",
     "ci_lane_check": "Answered to the seat before opening: no lane fails on these warnings. lintConfig is reached only by os lint and os lint --eval, never by validate, build or compile; nothing runs lint --strict on an example or template; check:i18n-coverage counts only i18n/ rules; and the tests that lint real examples filter by rule or assert exit 0.",
     "line_budget": "n/a, no skills/** file touched; +621/-248 across 10 files, well under the 3000-line split threshold",
     "deviations": [
      "The ADR-0048 §5 bullet correction is NOT in this PR (seat route change): the one-file patch is at /mnt/project-files/pm-devx-seat1/30804/adr-0048-s5-bullet.patch and applies cleanly to main. If no one opens it, this thread opens it from this branch after PR 1 merges and before PR 2, saying Refs #30804.",
      "packages/cli/src/commands/generate.ts is in the PR as a bounded in-place fix (the seat accepted it and amended the claim's file surface). Without it, every fresh scaffold drew the new warning and generate-scaffold-validates went red.",
      "Dotted capability names (<ns>.<short>) are treated as carrying the namespace. This is the default the seat recommended and put to Elon; it is still open."
     ],
     "files_changed": [
      ".changeset/30804-lint-namespace-prefix-every-name.md",
      "packages/cli/src/commands/generate.ts",
      "packages/cli/src/commands/lint.ts",
      "packages/cli/src/utils/project-namespace.ts",
      "packages/cli/test/generate-object-namespace-prefix.test.ts",
      "packages/cli/test/generate-scaffold-validates.test.ts",
      "packages/cli/test/generate-stack-reach.test.ts",
      "packages/cli/test/lint-handwritten-checks-package-fold.test.ts",
      "packages/cli/test/lint-namespace-prefix-per-package.test.ts",
      "packages/cli/test/lint-namespace-prefix.test.ts"
     ],
     "changeset": "'@objectstack/cli': patch (no skip-changeset)",
     "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "10 read-only: issue_read x6, list_pull_requests x1, pull_request_read x3 (one is the read-back of #30842); 0 MCP writes",
     "api_writes": "2 via fleet-write relay: pr_create (objectstack#30842, draft, no labels, read back identical, 13833 bytes) and this comment; plus git push (not REST). One earlier pr_create dispatch was refused locally by the payload validator (empty labels list), and zero writes were sent.",
     "open_questions": [
      "Dotted capability names: does showcase.export_data count as carrying namespace showcase? Default yes; with Elon via the seat. A strict ruling drops one clause from carriesPackageNamespace, and PR 2 then renames 2 capabilities plus 3 requiredPermissions references.",
      "For phase 3 (#30806): functions are outside PLURAL_TO_SINGULAR, so this rule does not judge them. The #30798 audit named function handlers as a collision class."
     ],
     "pr2_notes": "PR 2 must also update content/docs/ui/doc-pages.mdx L70-83 ('no longer load-bearing for uniqueness'). It does not need the held files (templates/AGENTS.md, blank/README.md, app-showcase/e2e/global-setup.ts) for the renames measured so far; this will be re-checked when PR 2 starts.",
     "security_findings": "none",
     "out_of_scope_findings": [
      {
       "class": "none (stale description)",
       "reach": "skills/objectstack-platform/SKILL.md:121 describes the old duplicate-only rule",
       "carrier": "#30805"
      }
     ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-elon-musk · session_016WV4cymvo9YoyLwKCXXBNw

    Ruling · #30804 · dotted capability names · 2026-11-06T11:09Z

    The maintainer answered「同意」at 2026-11-06T11:08Z, accepting the director analysis's recommendation (thread「分析 #30804 和 #30802 两个裁决」, analysis at /mnt/project-files/fable-director/30804-30802-decision-analysis.md):

    1. A dotted capability name <ns>.<short> carries the package namespace (showcase.export_data in package showcase). The dot clause holds for capability names only, because no other type's name pattern admits a dot. carriesPackageNamespace in PR fix(cli): os lint warns on every bare package-authored metadata name, and os generate writes them prefixed #30842 stays as written.
    2. For phase 3 (Bare-name phase 3: defineStack and the save door refuse a bare package-authored name; ADR-0129 and ADR-0048 amended; migration of stored and external references (ruling C on #30798) #30806): move carriesPackageNamespace into packages/spec/src/kernel/namespace-prefix.ts as the one predicate that cli and spec share.

    A correction to the earlier framing: under the strict reading, the rename would have been showcase_export_data, not showcase_showcase.export_data.

    Next: PR #30842 lands as written. The one-file ADR-0048 §5 bullet PR follows it, then PR 2 (the renames in examples and templates).

  5. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-elon-musk · session_016WV4cymvo9YoyLwKCXXBNw

    Landed · PR 1 #30842 merged as 1697d5ca9c · 2026-11-06T11:33Z. pm:dispatched stays because the card is still open. PR 2 (Part of #30804) renames the bare example names onto the lint and is next. The ADR-0048 §5 bullet PR follows it and carries Fixes #30804. One question is open with Elon for PR 2: whether the platform-requested permission set guest_portal (packages/rest/src/form-routes.ts:653, ADR-0138 "fate: keep") is exempt from the prefix rule. The seat recommends a named exemption.

  6. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:devx#1 · os-elon-musk · session_016WV4cyadQ5Zhih2y1GNTQm
    os-dev-report

    {
     "issue": 30804,
     "status": "done",
     "phase_part": "PR 2 of 2 (example renames + guest_portal exemption); the ADR-0048 §5 one-file PR with Fixes #30804 follows after this merges",
     "branch": "claude/project-thread-uogs4i",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/30927",
     "head": "367de6725",
     "base": "main 0e882086b (includes phase 1 #30836)",
     "session": "session_016WV4cyadQ5Zhih2y1GNTQm",
     "premise_still_valid": true,
     "summary": "Every bare name the four namespaced examples author now carries its namespace: app-todo 20, app-crm 6, app-showcase 12, app-multi-package 1, each renamed to the fix PR 1's warning gives. Every reference moved with them: dataset/report/dashboard refs, app nav, action handler bindings, flow triggers and approver positions, position: actor ids, sharing-rule recipients, seeded sys_user_position rows, translation keys, the example tests, 18 dogfood tests and 9 QA checklist area files. The crm permission set guest_portal is not renamed: os lint now exempts it through PLATFORM_REQUESTED_BARE_NAMES (lint.ts), citing form-routes.ts:653 and ADR-0138 'fate: keep' (option (a), the seat's recommendation, pending Elon). content/docs/ui/doc-pages.mdx no longer says the prefix is 'no longer load-bearing for uniqueness'.",
     "counts": {
      "measured_with": "lintConfig on each example's objectstack.config.ts, rule naming/namespace-prefix",
      "before_at": "main 1697d5ca9 (PR 1 merged)",
      "after_at": "this PR",
      "examples/app-todo": {
       "before": 20,
       "before_by_type": {
        "dashboards": 1,
        "reports": 5,
        "datasets": 1,
        "actions": 8,
        "flows": 4,
        "hooks": 1
       },
       "after": 0,
       "duplicates_before_after": [
        0,
        0
       ]
      },
      "examples/app-crm": {
       "before": 7,
       "before_by_type": {
        "dashboards": 1,
        "datasets": 1,
        "positions": 3,
        "permissions": 1,
        "hooks": 1
       },
       "after": 0,
       "duplicates_before_after": [
        0,
        0
       ],
       "note": "6 renamed; guest_portal stays under the (a) exemption"
      },
      "examples/app-showcase": {
       "before": 12,
       "before_by_type": {
        "positions": 10,
        "sharingRules": 2
       },
       "after": 0,
       "duplicates_before_after": [
        0,
        0
       ]
      },
      "examples/app-multi-package": {
       "before": 1,
       "before_by_type": {
        "apps": 1
       },
       "after": 0,
       "duplicates_before_after": [
        0,
        0
       ]
      },
      "create-objectstack blank template": {
       "before": 0,
       "after": 0,
       "note": "not touched"
      },
      "examples/embed-objectql": {
       "before": 0,
       "after": 0,
       "note": "no manifest namespace; not touched"
      }
     },
     "tests": "Example suites: showcase 46 files / 544 tests, todo 8 / 240, crm 7 / 48, all passed (on the final base too). cli: lint-namespace-prefix + 3 generate suites, 4 files / 115 tests passed. Dogfood real boots: the 18 changed test files + sharing-rule-criteria-required, 19 files / 205 passed; upgrade-18x-harness, multi-package-artifact, install-local-purge-sample-data, 3 / 34 passed; after the rebase onto phase 1, bare-name-one-holder + multi-package-artifact, 2 / 13 passed (needed objectql rebuilt: dogfood resolves it from dist). os validate in all four examples exit 0. eslint --no-inline-config on changed files exit 0. typecheck for example-todo, example-crm, example-showcase, example-multi-package, dogfood and cli exit 0.",
     "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 94 commands at 73064de88 and the same 94 at the rebased head; all 94 ran and exited 0; --ran at 367de6725: 94 derived / 94 run / 0 NOT-MEASURED. Also ran check-issue-citations --census (exit 0). Three CI-only commands that need the runner matrix and RUNNER_TEMP were not run locally. Record inlined in the PR body.",
     "line_budget": "+384/-323 across 80 files, under the 3000-line split threshold, so no per-example split",
     "changeset": "'@objectstack/cli': patch (the guest_portal exemption); the examples and dogfood are private packages",
     "deviations": [
      "content/docs/ui/doc-pages.mdx is corrected here (PR 1's report said PR 2 owes it): it now states the doc prefix is the package-wide naming contract and keeps the ADR-0048 package-scoped resolution text.",
      "Commit messages carry no card relation (check:commit-card-trailers refused the first push; reworded before anything was published)."
     ],
     "open_questions": [
      "guest_portal: is it exempt from the prefix rule? Built on (a). If the ruling is to prefix it, the constant, its condition and its test come out, and form-routes.ts:653 plus ADR-0138's ledger must learn the new name first (a runtime change outside this card). Phase 3 (#30806) needs the same answer."
     ],
     "left_unchanged_on_purpose": "Self-contained fixtures that spell the same words but load no example (ui tests, runtime/lint/metadata-protocol/plugin unit tests, multi_crm fixtures in cli and metadata tests, the position-name-fold census, docs/qa/scenarios/*.json, sharing-rule-criteria-required's invented sales_rep recipient); illustrative names in content/docs/**; the upgrade harness's 18.0 snapshots and populate-fixture.ts; CHANGELOG.md files; dashboard widget ids; approver group: labels.",
     "held_files": "templates/AGENTS.md, blank/README.md (#30792) and app-showcase/e2e/global-setup.ts (#30552) were not needed and not touched.",
     "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
     "mcp_calls": "read-only: issue_read x1 (card comments); subscribe_pr_activity on #30927; 0 MCP writes",
     "api_writes": "2 via fleet-write relay: pr_create (objectstack#30927, draft, no labels, read back identical, 16433 bytes) and this comment; plus git push (not REST)",
     "security_findings": "none",
     "out_of_scope_findings": [
      {
       "class": "broken manual script",
       "reach": "pnpm --filter @objectstack/example-todo test:mcp (examples/app-todo/test/mcp-actions.e2e.ts) exits 1 at its step 3 on main 1697d5ca9 as well: the seed and the step-3 insert fail with 'Organization is required' because the script boots with no organization. Steps 1-2 pass on both. No workflow or script runs it.",
       "carrier": "none yet; for the seat to route"
      }
     ]
    }
    

    Generated by Claude Code

  7. added
    pm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-set
    on Nov 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxDomain lane — seat card indexed by label:pm:seatpm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority: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