Skip to content

fix(spec): manifest.namespace refusal and TSDoc name the leading-letter rule - #19869

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19831-namespace-leading-letter-prescription
Sep 24, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19831-namespace-leading-letter-prescription

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19831
Clause-②: no

manifest.namespace is enforced by ^[a-z][a-z0-9_]{1,19}$, so its first character must be a lowercase letter. The refusal sentence and the TSDoc Rules: line only stated the length and the charset. 1leave and _leave satisfied every clause an author was shown, and the regex still refused them. This PR makes both texts state what the regex enforces. The regex is byte-identical, so the accept set does not move.

What changes

surface before after
ManifestSchema.namespace refusal (packages/spec/src/kernel/manifest.zod.ts) Namespace must be 2-20 chars, lowercase alphanumeric + underscore Namespace must be 2-20 chars, start with a lowercase letter, and contain only lowercase letters, digits and underscores
same key, TSDoc Rules: line 2-20 characters, lowercase letters, digits, and underscores only. 2-20 characters, starting with a lowercase letter; lowercase letters, digits, and underscores only (1leave and _leave are refused).
PackageSchema.namespace refusal (packages/spec/src/marketplace/package.zod.ts). Through it, CreatePackageRequestSchema.namespace and the scaffold-only TemplateManifestSchema.namespace too byte-identical copy of the old sentence the new sentence, byte-identical to the manifest's

The package.zod.ts copy is the second author-facing restatement. The step-1 sweep below found it in packages/spec, triage's grading named it, and the dispatch authorised fixing it here. If only one copy changed, the manifest and the publish payload would prescribe two different rules for one vocabulary. Its in-code comment now says that the sentence is kept identical as well as the pattern.

The new sentence has no trailing period on purpose. duplicatePackage in metadata-protocol appends . after the declaration's message (protocol.ts, the explicit-targetNamespace and derived-namespace refusals).

Measured, before and after

Each value was parsed through ManifestSchema.shape.namespace from source: origin/main 0e90a8d1c5 before, this branch 27704f4cc2 after.

value before after
1leave refused, old sentence refused, new sentence
_leave refused, old sentence refused, new sentence
a (1 char) refused, old sentence refused, new sentence
21-char name refused, old sentence refused, new sentence
Leave refused, old sentence refused, new sentence
leave, ab, 20-char name accepted accepted

All refusals are one issue with code invalid_format. The verdicts are identical on both sides. Only the text changed.

Restatement census (step 1)

This is git grep over the whole tree at 0e90a8d1c5, for the regex literal, the sentence, 2-20 chars, 2-20 characters and alphanumeric + underscore. CHANGELOGs and release pages are excluded.

site states the rule completely? action
packages/spec/src/kernel/manifest.zod.ts refusal + TSDoc no (the leading letter is missing) fixed here
packages/spec/src/marketplace/package.zod.ts refusal no (same sentence) fixed here
packages/spec/src/api/endpoint-publish-gate.ts refusal (apis: without a legal namespace) yes, it quotes the regex none
packages/spec/src/kernel/namespace-prefix.ts code comment (2-20 chars) partial, but it is an internal comment directly above the regex literal and not author-facing none
packages/cli/src/commands/package/publish.ts refusal + docblock yes ("a lowercase letter followed by lowercase letters, digits or underscores") outside packages/spec, none
packages/cli/src/commands/init.ts docblock yes, it quotes the regex outside packages/spec, none
packages/create-objectstack/src/index.ts docblock yes, it quotes the regex outside packages/spec, none
content/docs/api/declarative-endpoints.mdx yes, it quotes the regex outside packages/spec, none
docs/adr/0048-…, docs/adr/0121-… yes, they quote the regex outside packages/spec, none
.changeset/19577-duplicate-package-explicit-namespace.md (unreleased) it quotes the OLD sentence verbatim as duplicatePackage's refusal text outside packages/spec, not edited. See Acceptance notes
skills/** no restatement of the charset rule none
content/docs/references/** (generated) renders the .describe() text only, which states no rule none

Pins of the old sentence (step 4)

This is git grep over all of packages/ (and examples/, apps/, scripts/) for the sentence and its fragments.

  • packages/spec/src/marketplace/package-namespace.test.ts pinned it verbatim twice (PackageSchema and TemplateManifestSchema refusals). Both now pin the new text.
  • packages/metadata-protocol/src/protocol.duplicate-package-target-namespace.test.ts reads the sentence from ManifestSchema.shape.namespace at run time and never retypes it. No edit was needed, and it passes against the rebuilt spec.
  • Zero other hits. The sibling objectui (origin/main 544ecba) has zero hits too, with the control word namespace hitting.

Generated artifacts (step 5)

pnpm --filter @objectstack/spec build then check:generated: all 15 generated artifacts are up to date, and nothing was regenerated or committed. The .describe() text is unchanged, so content/docs/references/kernel/manifest.mdx does not move. The built dist/ carries the new sentence in 18 files and the old one in 0.

Changeset (step 6)

.changeset/manifest-namespace-leading-letter-refusal.md is "@objectstack/spec": patch. The reading:

  • AGENTS.md Post-Task Checklist step 3 says a bug fix in a released package takes a patch.
  • The shipped text of @objectstack/spec changes: the built dist/ carries the new sentence, so skip-changeset does not apply.
  • Clause-②: no: no authorable key is added, removed, widened or narrowed, and the regex and accept set are byte-identical.
  • @objectstack/metadata-protocol ships no changed bytes, because it reads the message at run time. So it has no changeset entry.

Tests

All of these ran at 27704f4cc2 unless another commit is noted.

  • New pins in packages/spec/src/kernel/manifest.test.ts: 1leave and _leave are refused as exactly one invalid_format issue, and the message matches start with a lowercase letter. The same sentence still names 2-20 chars and the charset. As a control, leave, crm, my_app_2, a1 and a 20-char name still parse, both on the field and in a whole manifest.
  • New pin in package-namespace.test.ts ("two gates, one vocabulary"): all four namespace fields refuse 1leave with the manifest's exact sentence. The existing verdict table could not see the prose, and this pin closes that class of drift.
  • pnpm --filter @objectstack/spec test: 525 files passed, 15503 tests passed, 1 todo.
  • pnpm --filter @objectstack/spec typecheck (tsc + scripts + check:test-typecheck): exit 0, and the debt ledger is unchanged.
  • @objectstack/metadata-protocol: built its dependency closure, then pnpm --filter @objectstack/metadata-protocol test ran 188 files passed and 3 skipped, and 2673 tests passed and 19 skipped. The verbose run of protocol.duplicate-package-target-namespace.test.ts passed 13/13.
  • Firing control, at 48ea3d9960 (same packages/spec tree): scripts/ablation-replace.mjs put today's sentence back through an anchor that must hit, with a shell trap restoring from HEAD.
    • Leg 1 changed manifest.zod.ts only. It went red, 4 failed / 85 passed: both leading-letter pins, the charset pin, and the four-field sentence pin.
    • Leg 2 changed package.zod.ts only (drift between the two declarations). It went red, 3 failed / 86 passed: the four-field sentence pin and both verbatim pins.
    • Restored, it went back to green, 89/89. The restore was proven by blob hash equal to HEAD and an empty git diff HEAD for both files. Nothing was left in the tree.
  • Lint was narrowed to the 4 touched .ts files: eslint --no-inline-config --format json, 4 files reported, 0 errors, 0 warnings. The population comes from eslint's own isPathIgnored (false for all 4). The config never enables type-aware linting (no parserOptions.project), so this diff cannot change a verdict on an untouched file.

Gates

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands at 27704f4cc2 derived 83 commands. All 83 ran, and --ran reconciles them as 83 run, 0 NOT-MEASURED, 0 UNRUN. Three gates first exited 3 (PREREQUISITE NOT MET, workspace dist/ absent): check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt. After turbo run build --filter='./packages/*' --filter='./packages/*/*' all three exit 0. Six roster gates in directories this diff touches also exit 0: check-changeset-fixed, check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:error-code-casing and check:filter-alias-parity. The spec repo vitest project and the CI-only jobs are left to CI.

This branch is based on 0e90a8d1c5. origin/main is 4 commits ahead (2bbb462335). None of them touches a file in this diff, and their diff has zero hits for the sentence.

Acceptance notes

  • Sibling key, same class, not fixed here. The dispatch rules out every other ManifestSchema key. manifest.id / PackageSchema.manifestId (manifestIdRefusal, same file) say "lowercase dot-separated segments; hyphens allowed inside a segment, underscores are not.", but the pattern also requires each segment to open with a letter. Measured at 0e90a8d1c5: com.example.2app and com.2example.app are refused with exactly that sentence and no suggestion. They satisfy every clause it states. This is reported for the seat to file.
  • The unreleased changeset .changeset/19577-duplicate-package-explicit-namespace.md (line 15) quotes the old sentence as the text duplicatePackage returns. After this PR that quote describes text the runtime no longer produces. It is outside packages/spec, so it is not edited here. This PR's own changeset states the new sentence and names duplicatePackage, so the same release carries the correction. The replacement for the quoted fragment is Namespace must be 2-20 chars, start with a lowercase letter, and contain only lowercase letters, digits and underscores.
  • PR feat(spec)!: the canon for a package version is SemVer 2.0.0 — nine carriers, one grammar #19637 edits the version key and the imports of manifest.zod.ts, and PR feat(spec): doc navigation item targeting a book and/or a doc #19789 regenerates manifest.mdx. This PR touches neither region and moves no generated file.

Generated by Claude Code

…er rule

The regex `^[a-z][a-z0-9_]{1,19}$` requires a lowercase letter first, but
the refusal sentence and the TSDoc `Rules:` line only stated length and
charset, so `1leave` / `_leave` were refused by a sentence they satisfy.
The publish-payload copy in marketplace/package.zod.ts carried the same
sentence and is updated in step; a new pin holds all four namespace
fields to one sentence.

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx (via PackageSchema (symbol, a top-level const))
  • content/docs/getting-started/quick-reference.mdx (via ManifestSchema (symbol, a top-level const object))
  • content/docs/plugins/development.mdx (via ManifestSchema (symbol, a top-level const object))
  • content/docs/protocol/kernel/plugin-spec.mdx (via ManifestSchema (symbol, a top-level const object))

⛔ 1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx (via ManifestSchema (symbol, a top-level const object))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 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; 100 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 — 136 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 2bbb462335ad617f51ba7fc1a0c872f932f47513 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 75eb534af0878f97da34b6d195b9db7a0946788a — the merge of head 27704f4cc2d7b6b06b17fcd053d330270345bf7d into base 2bbb462335ad617f51ba7fc1a0c872f932f47513, 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 75eb534af0878f97da34b6d195b9db7a0946788a && git checkout 75eb534af0878f97da34b6d195b9db7a0946788a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2bbb462335ad617f51ba7fc1a0c872f932f47513 27704f4cc2d7b6b06b17fcd053d330270345bf7d && git checkout -B drift-repro 2bbb462335ad617f51ba7fc1a0c872f932f47513 && git merge --no-ff 27704f4cc2d7b6b06b17fcd053d330270345bf7d

node scripts/docs-audit/affected-docs.mjs --json 2bbb462335ad617f51ba7fc1a0c872f932f47513

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2bbb462335ad617f51ba7fc1a0c872f932f47513 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: 45/45 CONTRACT_REVIEW_TIER
Head-sha: 27704f4cc2d7b6b06b17fcd053d330270345bf7d

Isolated at-tier reviewer subagent, run by the domain:spec seat-4 session on the maintainer's instruction in that session (「帮我处理」, with the landing route chosen there); every one of its 45 transcript turns served at the tier the constant names. Adopted by the seat 2026-09-24T05:35Z. The record below is the reviewer's, unedited except the two header lines.

① Derived judgments

  1. Accept set: unchanged — right. git show origin/main:packages/spec/src/kernel/manifest.zod.ts | grep -n 'a-z0-9_\]{1,19}' prints 390: .regex(/^[a-z][a-z0-9_]{1,19}$/, ...); the same command on refs/review/pr-19869 prints 391: with the byte-identical regex. packages/spec/src/marketplace/package.zod.ts likewise: origin/main:202 and refs/review/pr-19869:203, same regex. The diff (pulls/19869, Accept diff, 162 lines) touches only message strings, comments, TSDoc, tests and one changeset. Direct probe of the regex (node probe.mjs in scratch): 1leave, _leave, a, 21 chars, Leave, le-ave, le.ave, non-ascii, trailing space → REFUSE; leave, ab, a1, a_, my_app_2, crm, 20 chars → ACCEPT. The card asks for no accept-set change and none is made.

  2. Refusal sentence is TRUE — right. refs/review/pr-19869:packages/spec/src/kernel/manifest.zod.ts:391: Namespace must be 2-20 chars, start with a lowercase letter, and contain only lowercase letters, digits and underscores. Clause by clause against ^[a-z][a-z0-9_]{1,19}$: [a-z] first = start with a lowercase letter (leading digit and leading underscore refused, probe above); [a-z0-9_]{1,19} = 1..19 more from exactly lowercase letters, digits, underscore (hyphen, dot, uppercase, non-ascii, whitespace refused); 1 + 1..19 = 2-20 chars. No clause admits a value the regex refuses and the regex refuses nothing the sentence admits. This is the shape the card suggested.

  3. TSDoc Rules: line — right. refs/review/pr-19869:packages/spec/src/kernel/manifest.zod.ts:382-383: 2-20 characters, starting with a lowercase letter; lowercase letters, digits, and underscores only (1leaveand_leave are refused). States the same rule as the refusal; the two examples are exactly the card's.

  4. PackageSchema.namespace sentence and its two derived fields — right, and inside the amended claim. refs/review/pr-19869:packages/spec/src/marketplace/package.zod.ts:203 carries the byte-identical new sentence; lines 198-202 now say the SENTENCE is kept identical, not only the pattern. package.zod.ts:296 namespace: PackageSchema.shape.namespace (CreatePackageRequestSchema) and template-manifest.zod.ts:106 namespace: CreatePackageRequestSchema.shape.namespace.describe(...) (TemplateManifestSchema) inherit it, so all four fields read one refusal. Triage comment 5793132438 required both copies to move together; amendment comment 5796198185 puts this file and its test in the claim surface.

  5. Generated docs and .describe() — right. Neither .describe() text changed; the generated refs/review/pr-19869:content/docs/references/kernel/manifest.mdx:31 renders the describe text only and states no charset rule, so there is nothing to regenerate. git grep -l -i -E 'Namespace must be|alphanumeric \+ underscore' refs/review/pr-19869 -- 'content/docs/references/**' '**/*.json' '**/*.mdx' → zero hits. Lint & Repo Gates and Spec property liveness check-runs at head: success.

  6. Every copy of the rule now says the same thing — right. git grep -F 'lowercase alphanumeric + underscore' refs/review/pr-19869 → only .changeset/19577-duplicate-package-explicit-namespace.md:15 and the PR's own changeset line 11 (as the "was" quote). Remaining restatements all name the leading letter or quote the regex: packages/cli/src/commands/package/publish.ts:86-88 docblock and :473-474 refusal (a lowercase letter followed by lowercase letters, digits or underscores); packages/spec/src/api/endpoint-publish-gate.ts:181, packages/cli/src/commands/init.ts:58, packages/create-objectstack/src/index.ts:98, content/docs/api/declarative-endpoints.mdx:124-125, docs/adr/0048:426, docs/adr/0121:170 quote the regex; package-namespace.test.ts:55-56 docblock states the leading letter. packages/spec/src/kernel/namespace-prefix.ts:17 says (2-20 chars) in an internal comment above the regex, and its emitted messages (:37, :40) state no charset rule, so no author-facing copy is left incomplete. skills/objectstack-platform/SKILL.md:155 states no charset rule. The four docs flagged by the drift-check comment (5796149365) contain no charset statement (git grep -i namespace on each, filtered for char/lower/letter/digit/underscore/regex/must: only quick-reference.mdx:311, which is about explicit declaration, not charset).

  7. Doors that surface the sentence — right. refs/review/pr-19869:packages/metadata-protocol/src/protocol.ts:19399-19405: ManifestSchema.shape.namespace.safeParse(...), rule = declaredTargetNs.error?.issues[0]?.message, then ${rule}. — the no-trailing-period sentence composes correctly and duplicatePackage now carries the leading-letter rule with no change of its own. Its test reads the sentence off the schema (protocol.duplicate-package-target-namespace.test.ts:102); git grep -F 'Namespace must be' refs/review/pr-19869 -- packages/metadata-protocol → zero literal pins.

  8. Pins are weight-bearing — right. refs/review/pr-19869:packages/spec/src/kernel/manifest.test.ts:678-718: 1leave / _leave must be one invalid_format issue whose message matches /start with a lowercase letter/, plus /2-20 chars/ and /lowercase letters, digits and underscores/; the old sentence matches none of the three, so a revert fails. Lit control parses leave, crm, my_app_2, a1, a 20-char name on the field and inside a whole manifest. package-namespace.test.ts:100 and :228 retype the new sentence verbatim; :160-175 reads the sentence off all four fields for 1leave and holds them toBe the manifest's, which fails on any drift of package.zod.ts. The PR's firing-control runs were not re-run here (gate family); Test Core (1/6..6/6) and TypeScript Type Check at head: success.

  9. Drift on main since the PR base — right, nothing collides. git rev-list --count 0e90a8d1c5f3cd3312730a0c9d7f206b3e887314..origin/main = 32 (origin/main c1641868a3da71537c9c6c572d2bd2044103236b); git log 0e90a8d1c5..origin/main -- packages/spec/src/kernel/manifest.zod.ts packages/spec/src/kernel/manifest.test.ts packages/spec/src/marketplace/package.zod.ts packages/spec/src/marketplace/package-namespace.test.ts → empty; git diff 0e90a8d1c5 origin/main | grep -E 'lowercase alphanumeric \+ underscore|start with a lowercase letter|2-20 chars' → zero. git grep -F 'Namespace must be' origin/main → only the four files this PR edits plus the 19577 changeset, so no new pin of the old sentence landed on main. pulls/19869 mergeable_state: clean.

② Semver level

refs/review/pr-19869:.changeset/manifest-namespace-leading-letter-refusal.md:2 "@objectstack/spec": patch, :7 Clause-②: no, no arm. AGENTS.md at origin/main :1081-1085: a bug fix in a released package takes patch, never none and never skip-changeset; the declaration is Clause-②: yes|no plus at most one arm, and yes takes at least minor. The accept set is byte-identical (①.1), so no with no arm is the correct declaration; the built dist/ carries a changed runtime string, so skip-changeset does not apply; nothing is removed or renamed, so no migration text and no ADR-0087 marker is owed (:1086-1096). @objectstack/metadata-protocol ships no changed bytes (①.7) and rides the fixed group plus updateInternalDependencies: patch in origin/main:.changeset/config.json. The PR body's Clause-②: no matches the changeset. Check Changeset check-run at head: success. Level and declaration agree: patch, prose-only.

③ Boundary flags

  • Non-blocking — escalate to the domain:spec seat, and the stated mitigation does not hold. .changeset/19577-duplicate-package-explicit-namespace.md:15 (identical at origin/main and refs/review/pr-19869) quotes Namespace must be 2-20 chars, lowercase alphanumeric + underscore as the text duplicatePackage returns; after this PR the runtime never produces it. It is outside the amended claim (comment 5796198185 routes it through ruling D, [finding] the skip-changeset label suppresses the DELIBERATE-CORRECTION refusal whose own text says 「no label and no diff shape makes that safe」 — declared contract against enforced behaviour #18375), so it is not a defect of this diff. But the amendment's and PR body's reasoning for option B — "PR 19869's own changeset ... so the CHANGELOG carries the correction next to that quote" — is false: that changeset is '@objectstack/metadata-protocol': minor (its line 2) and this PR's is "@objectstack/spec": patch; changeset version writes per-package files (packages/metadata-protocol/CHANGELOG.md and packages/spec/CHANGELOG.md both exist at origin/main), and the fixed group aligns versions, not text. At release packages/metadata-protocol/CHANGELOG.md would publish a refusal text that version never emits, with the correction in a different package's file, and AGENTS.md :697 then makes it a released-entry amendment. The seat should amend that one line (dev's option A route, via the ruling-D path) before the release that consumes it. scripts/check-empty-changeset.mjs:605-610 names this exact "deliberate correction" class as the human path: say so on the PR and get it confirmed, which the PR's Acceptance notes do.
  • Non-blocking. Changeset line 13 quotes the TSDoc Rules: line without its parenthetical (1leaveand_leave are refused) present at manifest.zod.ts:383; a prefix of the real line, not a contradiction.
  • Non-blocking. PR body says origin/main is 4 commits ahead at 2bbb462335; at review it is 32 ahead at c1641868a3. ①.9 shows none of them touches this diff.
  • Non-blocking. The changeset file name has no issue prefix; scripts/check-empty-changeset.mjs:598-599 recommends an issue-scoped name only as the collision remedy, no gate enforces it, and the slug is distinctive.
  • Non-blocking, acknowledged, out of scope of the claim. Dev report 5796170355 out_of_scope_findings: the sibling manifestIdRefusal defect (same class on manifest.id, for the seat to file); the partial internal comment at namespace-prefix.ts:17; the stale path cloud/package.zod.ts at packages/cli/src/commands/package/publish.ts:86 (verified: the file lives at marketplace/package.zod.ts). None is this card's landing site.
  • Files vs amended claim: all five inside. pulls/19869/files: .changeset/manifest-namespace-leading-letter-refusal.md (+16), packages/spec/src/kernel/manifest.test.ts (+41, appended block only), packages/spec/src/kernel/manifest.zod.ts (+3 -2, hunks at 379-393, the namespace key only; the version key and imports that PR feat(spec)!: the canon for a package version is SemVer 2.0.0 — nine carriers, one grammar #19637 edits are untouched), packages/spec/src/marketplace/package-namespace.test.ts (+19 -2) and packages/spec/src/marketplace/package.zod.ts (+6 -5), the last two per amendment 5796198185. No generated file moved; no file outside packages/spec or .changeset/.
  • Trailers. Both commits (48ea3d9960ad95ac1e90900455530b7c62aee8ac, 27704f4cc2d7b6b06b17fcd053d330270345bf7d) end with the model-free pair Claude-Session: and Co-authored-by: Claude required by AGENTS.md :451-452; the PR body and changeset carry no model identifier.
  • Checks. commits/27704f4cc2d7b6b06b17fcd053d330270345bf7d/check-runs: total_count: 35, all completed, 32 success, 3 skipped (Console Pin Gate, Build Docs, Packed-tarball smoke opt-in), 0 failures. No gate family was re-run locally. The PR is still a draft with no needs:contract-review label; posting this record is the seat's act, not a defect.

Implemented-by: claude/issue-19831-namespace-leading-letter-prescription
Reviewed-by: session_019c3Hi6ZMU1p6m6aA6Bz45d

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 24, 2026 05:41
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 96451ec Sep 24, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-19831-namespace-leading-letter-prescription branch September 24, 2026 06:03
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/s tests tooling

Projects

None yet

1 participant