Repository navigation
manifest.namespace refuses a leading digit or underscore, but its refusal sentence and TSDoc rule never say so — 1leave / _leave satisfy every stated clause and are refused #19831
Description
Activity
objectstack-fleet commented
on Sep 23, 2026 ContributorAuthorMore actions定级
pm:queue·priority:p3·domain:specPath: platform-core
Triage: lands in
packages/spec/src/kernel/manifest.zod.ts(namespace) ⇒domain:spec; rationale: the refusal sentence and the TSDoc rule omit the leading-letter clause the regex enforces, so an author following the documented rule is refused without a usable prescription (North Star rule 4); small, text-only, rarely reached ⇒ p3.分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T10:24Z。立卡门 ①,类 (c)。本席读完了卡面(本卡尚无评论)。本席的读数(
origin/main3ad89c1bcc)packages/spec/src/kernel/manifest.zod.ts:390:正则/^[a-z][a-z0-9_]{1,19}$/,拒绝句Namespace must be 2-20 chars, lowercase alphanumeric + underscore;- 同文件
:382的 TSDoc 规则:2-20 characters, lowercase letters, digits, and underscores only.
⇒ 「首字符必须是小写字母」这一条,正则在执行,拒绝句与文档都没说。与卡面一致。
判定
p3:拒绝是响亮的,只是处方缺一条;会碰到的只是首字符写成数字或下划线的命名空间。改动是一句文字 + 一行文档。⚠️ 扫描范围比卡面多一处:同一句拒绝语逐字还出现在packages/spec/src/marketplace/package.zod.ts,并被packages/spec/src/marketplace/package-namespace.test.ts引用。改句子时两处一起改,测试里钉旧句子的地方一并更新;⛔ 只改一处会让两个入口给出不同的处方。⚠️ 串行:在飞的 PR fix(metadata-protocol): duplicatePackage parses an explicit targetNamespace through the manifest namespace declaration #19829([finding] duplicatePackage validates its DERIVED namespace but takes an explicit targetNamespace raw — and that value is spliced into every copied object name, which the object-name regex then refuses #19577)让duplicatePackage逐字使用这句拒绝语。认领前先看 fix(metadata-protocol): duplicatePackage parses an explicit targetNamespace through the manifest namespace declaration #19829 是否已落地;未落地就排在其后,落地后把它新加的断言一并扫进来。⛔ 不并入 fix(metadata-protocol): duplicatePackage parses an explicit targetNamespace through the manifest namespace declaration #19829。- 读作 Bug(声明的规则与执行的规则不一致);
type字段中继设不了。
Generated by Claude Code
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsClaim: PM loop —
manifest.namespace's refusal sentence and TSDoc rule omit the leading-letter clause its regex enforces, so1leave/_leaveare refused with no usable prescription, dispatched at 2026-09-23T12:56Z
Session:session_013RDBh5DqXd2xnLwvHLgLFr
Branch:claude/issue-19831-namespace-leading-letter-prescription
Worktree:objectstack-issue-19831
Domain:domain:spec
Seat:domain:spec#1
File surface:packages/spec/src/kernel/manifest.zod.ts, region only: thenamespacekey (its TSDocRules:line and the regex's refusal sentence), plus its tests, whatever the generators rewrite (regenerated, ⛔ never hand-edited), and.changeset/. ⛔ Every other key ofManifestSchemais out.
Container & model:S,mode:subagent,model: opus (default judgment tier)
Clause-②: no
Thread-read: 5793132438
Serial constraints cleared: census over all 22 open PRs at 2026-09-23T12:56Z (299 file rows; lit control 67packages/spec/rows).manifest.zod.tsis also edited by PR #19637 (#18697, draft,size/xl). Its hunks are the import line at the top and theversionkey; ⛔ none is in thenamespacedeclaration, so the regions are disjoint. Its generatedcontent/docs/references/kernel/manifest.mdxhunk sits beside thenamespacerow, and PR #19789 also regenerates that page. ⇒ If this round moves the generated page, it names the move, and a merge is resolved byscripts/pm/os-regen-merge.shplus a quoted-exact assertion, ⛔ never by hand. PR #19829, which the card cites, has merged.Why this qualifies while product P0/P1s are open
The refusal sentence is runtime text shipped to authors, and every door that parses
manifest.namespacesurfaces it. It states rules that1leaveand_leaveboth satisfy, then refuses them. NORTH-STAR rule 4 counts published text that is wrong as a product defect (「错的必须被响亮拒绝并给处方」). Triage graded it p3; it is ⛔ not tooling or contract hygiene.
Generated by Claude Code
objectstack-fleet commented
on Sep 23, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 19831, "status": "done", "branch": "claude/issue-19831-namespace-leading-letter-prescription", "pr": "https://github.com/objectstack-ai/objectstack/pull/19869", "session": "session_013RDBh5DqXd2xnLwvHLgLFr — this run (mode:subagent; matches the Session line of claim 5795244696, whose Branch line names this branch)", "premise_still_valid": true, "summary": "Premise re-measured from source at origin/main 0e90a8d1c5. `1leave`, `_leave`, `a`, a 21-char name and `Leave` are all refused through ManifestSchema.shape.namespace as one invalid_format issue carrying 'Namespace must be 2-20 chars, lowercase alphanumeric + underscore'. `leave`, `ab` and a 20-char name are accepted. The refusal is now 'Namespace must be 2-20 chars, start with a lowercase letter, and contain only lowercase letters, digits and underscores'. The TSDoc Rules line is now '2-20 characters, starting with a lowercase letter; lowercase letters, digits, and underscores only (1leave and _leave are refused).' The regex is byte-identical, and the same 8 probes give identical verdicts after the change. The step-1 sweep found a second incomplete author-facing restatement in packages/spec: the byte-identical sentence on PackageSchema.namespace in marketplace/package.zod.ts. It is fixed in the same PR, as dispatch step 2 authorizes, and through it CreatePackageRequestSchema and TemplateManifestSchema change too. A new pin holds all four namespace fields to the manifest's exact sentence. Two verbatim pins of the old text were updated, both in packages/spec/src/marketplace/package-namespace.test.ts. metadata-protocol reads the sentence at run time, so no pin there needed an edit. No generated artifact moved, and content/docs/references/kernel/manifest.mdx is unchanged. The changeset is @objectstack/spec patch. Deviation to note: the claim's File surface names only the manifest.zod.ts namespace region, while this PR also edits marketplace/package.zod.ts and package-namespace.test.ts under dispatch steps 2 and 4, so the claim's surface is owed an amendment by the seat. The assignee was already set (os-support-ai) and was not touched. Commits carry the model-free trailer pair that the dispatch and AGENTS.md require, not the model-named Co-Authored-By the harness attribution text offered. The branch is based on 0e90a8d1c5, and origin/main is 4 commits ahead at 2bbb462335. None of the incoming commits touches a file in this diff or contains the sentence, so no merge was made.", "tests": "All at HEAD 27704f4cc2 unless noted. (1) New pins in packages/spec/src/kernel/manifest.test.ts: 1leave and _leave are refused as exactly one invalid_format issue whose message matches /start with a lowercase letter/. The sentence still names 2-20 chars and the charset. Lit control: leave, crm, my_app_2, a1 and a 20-char name parse, on the field and in a whole manifest. New four-field sentence-equality pin in package-namespace.test.ts. Targeted run: 2 files, 89/89 passed. (2) FIRING CONTROL at 48ea3d9960 (same packages/spec tree), through scripts/ablation-replace.mjs with a shell trap restoring from HEAD. Leg 1 restored today's sentence in manifest.zod.ts only: anchor x1 to x0, blob 285e94098c07 to 90c0f8f4a514, RED with 4 failed / 85 passed (both leading-letter pins, the charset pin, the four-field sentence pin). Leg 2 restored it in package.zod.ts only: blob dbd089ddd520 to bd90bc089fad, RED with 3 failed / 86 passed (the four-field pin plus both verbatim pins). Restored run GREEN 89/89. Restore was proven for both files by blob == HEAD blob and an empty git diff HEAD. Direction was red as expected. (3) pnpm --filter @objectstack/spec build: exit 0, no tracked file moved. check:generated: all 15 generated artifacts up to date, nothing regenerated. dist carries the new sentence in 18 files and the old one in 0. (4) pnpm --filter @objectstack/spec test (vitest --project local): Test Files 525 passed (525), Tests 15503 passed | 1 todo. The spec 'repo' vitest project was not run locally and is declared to CI. (5) pnpm --filter @objectstack/spec typecheck (tsc + check:scripts-typecheck + check:test-typecheck): exit 0, and the test-typecheck-debt ledger held. (6) turbo build of the @objectstack/metadata-protocol^... closure (12/12 tasks), then pnpm --filter @objectstack/metadata-protocol test: Test Files 188 passed | 3 skipped (191), Tests 2673 passed | 19 skipped (2692). A verbose run of protocol.duplicate-package-target-namespace.test.ts gave 13/13, including 1leave and _leave refusing with the declaration's sentence. (7) GATES: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 83 commands, all run, and --ran printed '83 derived famil(ies) accounted for — 83 run, 0 NOT-MEASURED'. On the first pass check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt exited 3 (PREREQUISITE NOT MET, workspace dist absent). After turbo run build --filter='./packages/*' --filter='./packages/*/*' (72/72 tasks) all three exited 0, and type-check-debt printed 'none above its recorded number'. Also exit 0: six roster gates whose roster sits in a touched directory (check-changeset-fixed, check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:error-code-casing, check:filter-alias-parity). (8) Lint was a proven narrowing. Population: eslint's own isPathIgnored is false for all 4 touched .ts files. Count: eslint --no-inline-config --format json reported 4 files, 0 errors, 0 warnings. Invariance: eslint.config.mjs never enables type-aware linting (no parserOptions.project), so the diff cannot move a verdict on an untouched file. Full pnpm lint is left to CI. (9) needs:contract-review is absent from PR 19869 (labels empty at read-back). The --pair reading is NOT MEASURED, reason: scripts/pm/check-clause2-carriers.mjs does not exist at 27704f4cc2. Not run locally and declared to CI: the Test Core, Dogfood, Build Core and Temporal Conformance jobs, and the workspace, examples and downstream-contract typecheck lanes. The public type surface is byte-unchanged (check:api-surface is green) and only a runtime string moved.", "mcp_calls": "0", "api_writes": "2 — (a) pr_create through the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204), which ran 35870406352 and opened PR 19869 as a draft with POST /repos/objectstack-ai/objectstack/pulls. The body was read back byte-identical (10693 bytes). (b) This os-dev-report comment through scripts/pm/post-stamped.mjs. Its transport resolved to the relay: POST /repos/objectstack-ai/objectstack/dispatches, whose run makes POST /repos/objectstack-ai/objectstack/issues/19831/comments. Also 3 git pushes through write-pace (the empty branch probe, the fix commit, the changeset commit), which are not REST writes. Zero label writes, since the dispatch forbids labels. All reads were GET only.", "open_questions": [ { "question": "The unreleased .changeset/19577-duplicate-package-explicit-namespace.md (line 15) quotes the OLD sentence verbatim as the text duplicatePackage returns. After this PR that quote no longer describes what the runtime produces. The dispatch forbids edits outside packages/spec except test pins, so it was not touched. Who amends it, and when?", "options": [ "A: the seat widens this card's file surface, and the one-line amendment lands in PR 19869 before merge. Replace the quoted fragment 'Namespace must be 2-20 chars, lowercase alphanumeric + underscore' with 'Namespace must be 2-20 chars, start with a lowercase letter, and contain only lowercase letters, digits and underscores'.", "B: leave it. PR 19869's own changeset states the new sentence and names duplicatePackage, so if both land in the same release the CHANGELOG carries the correction next to the stale quote.", "C: a separate docs-only PR after this one merges. If the 19577 changeset is released first, it becomes a released-entry amendment under the AGENTS.md CHANGELOG rule." ], "recommendation": "A. It is one mechanical line in an unreleased input, and fixing it before the release that consumes it keeps the published sentence true. B leaves a contradiction in one CHANGELOG, and C becomes a released-entry amendment if the timing slips." } ], "out_of_scope_findings": [ "class: c · Same defect class as this card, on the sibling key the dispatch rules out. manifestIdRefusal in packages/spec/src/kernel/manifest.zod.ts (it serves manifest.id and PackageSchema.manifestId) says 'lowercase dot-separated segments; hyphens allowed inside a segment, underscores are not.', but MANIFEST_ID_PATTERN also requires each segment to open with a letter. Measured from source at 0e90a8d1c5: com.example.2app and com.2example.app are refused with exactly that sentence and no suggestion, though they satisfy every clause it states. com.example.-app is refused the same way. Producer: authors writing manifest.id, and the publish payload's manifestId. Not fixed, because the dispatch forbids any other ManifestSchema key. Seat to file. Dedupe words: 'manifestIdRefusal segment must start with a letter' · 'manifest.id refusal leading digit segment' · 'Invalid package id lowercase dot-separated segments' · 'reverse-domain refusal omits leading-letter rule'.", "carrier: the domain:spec seat (see open_questions A/B/C) · .changeset/19577-duplicate-package-explicit-namespace.md line 15 quotes the pre-change sentence as duplicatePackage's refusal text. It is unreleased and outside packages/spec, so it was not edited. Noted in the PR's Acceptance notes, not filed.", "carrier: 承接者:无 · packages/spec/src/kernel/namespace-prefix.ts line 17 has the internal comment 'Namespace charset accepted by manifest.namespace (2-20 chars)' directly above the regex literal. It is partial but not author-facing, so it is not in class a/b/c. packages/cli/src/commands/package/publish.ts line 86 docblock names 'cloud/package.zod.ts' for the publish payload, and the declaration lives at marketplace/package.zod.ts: a stale path in a comment, nit, not filed." ] }
Generated by Claude Code
os-support-ai commented
on Sep 23, 2026 CollaboratorMore actionsFile-surface amendment to claim
5795244696, at 2026-09-23T13:59Z. The branch is unchanged, and this is ⛔ not a second claim.The dispatch's step 2 authorised fixing any other incomplete author-facing restatement inside
packages/spec, and its step 4 authorised updating tests that pin the old sentence. The round found one of each, so PR #19869's actual file list goes beyond the claim'snamespaceregion:packages/spec/src/marketplace/package.zod.ts:PackageSchema.namespace, which carried the byte-identical incomplete sentence. Through it,CreatePackageRequestSchemaandTemplateManifestSchemaread the new sentence too.packages/spec/src/marketplace/package-namespace.test.ts: two verbatim pins of the old text, plus a new four-field sentence-equality pin.
Census over the other 21 open PRs: neither file, and no
.changeset/19577-*file, appears in any of them.Left for the seat (⛔ not this PR): the unreleased
.changeset/19577-duplicate-package-explicit-namespace.mdquotes the pre-change sentence asduplicatePackage's refusal text. PR #19869's own changeset states the new sentence and namesduplicatePackage, so the CHANGELOG carries the correction next to that quote. Editing another card's pending changeset follows ruling D's route (#18375), so it is ⛔ not done here.
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsLanding — PR #19869 flipped ready + auto-merge by
domain:specseat 4, 2026-09-24T05:44ZDone on the maintainer's instruction, provenance:
- who: the maintainer;
- words: 「帮我处理」 for a list of twelve PRs "只差一份 at-tier 复核的 PASS 记录", then the landing route 「我直接落地」 chosen in the same exchange;
- where: the chat of session
session_019c3Hi6ZMU1p6m6aA6Bz45d(domain:spec#4).
This does not take over the claim: the claim, the branch and the card stay with the claiming seat, and this seat only lands the PR.
- Contract review: at-tier PASS, record
5808336753on PR fix(spec): manifest.namespace refusal and TSDoc name the leading-letter rule #19869, on the head the PR carries now. - Landing prechecks, re-read immediately before the flip: head unchanged; every check-run completed
successor skipped by design;check-governed-merges.mjsreads 0 governed paths; the PR is under 5,000 lines;mergeable_stateisclean. ⚠️ Owed before the next release, outside this PR: the pending.changeset/19577-duplicate-package-explicit-namespace.md:15(@objectstack/metadata-protocol) quotes a refusal text the runtime no longer emits after this PR. Correcting it is the DELIBERATE CORRECTION class and needs the maintainer's confirmation; the CHANGELOG this PR writes is a different package's file, so it does not carry the correction (record ③).
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsLanded — PR #19869 →
96451ec105, 2026-09-24T06:07Zdomain:specseat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d), landing record for the landing done on the maintainer's instruction (provenance in this seat's landing comment above).- The card closed
completedthroughFixes #19831. The squash96451ec105has one parent and is an ancestor oforigin/main. - Mis-close check: of the cards closed since 2026-09-24T06:00Z, each was closed by its own PR; none by a stray keyword.
pm:dispatchedremoved. The assignee and the claim belong to the claiming seat and are left untouched.
Generated by Claude Code
- The card closed
- added a commit that references this issue
on Sep 28, 2026
Filing gate: ① a defect with a named landing site — the
namespacedeclaration ofManifestSchemainpackages/spec/src/kernel/manifest.zod.ts. Finding class (c): an AI trap. An author following the documented rule writes a value the regex refuses, and the refusal cannot say why.Filed by the
domain:engineexecution seat 1 (session_01TEhopqrWQYBycZzyJHpAZr) from theout_of_scope_findingsof this seat's #19577 dev (PR #19829). Re-read by this seat onorigin/mainc11852406, ⛔ not adopted from the report. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.What the declaration says, three ways
/^[a-z][a-z0-9_]{1,19}$/— the FIRST character must be a lowercase letterNamespace must be 2-20 chars, lowercase alphanumeric + underscoreRules:line2-20 characters, lowercase letters, digits, and underscores only.⇒⚠️ This seat re-read the declaration text, not the built output.
1leaveand_leavesatisfy every clause the sentence and the TSDoc state, and the regex refuses both. The dev measured this on the built spec:ManifestSchema.shape.namespace.safeParse('1leave')andsafeParse('_leave')both refuse, with exactly that sentence. That is the dev's measurement on its branch base.Why it matters now, not only in principle
defineStackmanifests and every door that parsesmanifest.namespacesurface it.duplicatePackagerefuse an explicittargetNamespacewith this sentence verbatim, the declaration's own remedy by design. The refusal an author gets for1leaveis therefore the sentence that does not explain it. That PR's changeset states the leading-letter rule in its own prose. A changelog is not the refusal, though, and the fix belongs at the producer.Suggested shape (⛔ not a ruling)
Make the sentence and the TSDoc rule say what the regex enforces, e.g.
Namespace must be 2-20 chars: a lowercase letter, then lowercase letters, digits or underscores. Then sweep the tree for pins that assert the old sentence (a message change is a published-byte change; the owning seat decides the changeset level).Filing-gate answers
packages/specafter triage routes it (the domain table putspackages/specindomain:spec). ⛔ This seat writes nodomain:*.closedincluded:Namespace must be 2-20 chars message leading letter regex manifest namespace→ 3 hits, all closed, none this defect (nearest [finding]ManifestSchema.version's own TSDoc@example "2.1.0-beta.1"is refused by its regex — copy the documented example andparsethrows #17461,ManifestSchema.version's TSDoc example refused by its regex — the same shape on a different key);manifest namespace refusal message starts with letter→ 1 hit, closed finding(metadata-protocol): 30 refusal messages open with a bracketed tag that restates the code the same throw declares — the shape #12975 rules out, and it reaches the wire #16245, unrelated.Dedupe words:
Namespace must be 2-20 chars·manifest.namespace regex message mismatch·namespace leading letter refusal·namespace TSDoc rule starts with letterGenerated by Claude Code