Repository navigation
feat(spec): a package-id segment may open with a digit, and the refusal states the rule the pattern enforces - #20172
Conversation
…tates the rule MANIFEST_ID_PATTERN widens to admit a digit-led segment (com.163.crm, com.example.2app); a segment still may not open with a hyphen and underscores stay refused. manifestIdRefusal and the id TSDoc now state the rule the pattern enforces. Consumer pins that asserted a digit-led segment is refused flip to accepted rows (metadata-protocol, cloud-connection, cli publish), and texts quoting the old rule or the old sentence follow (migration entry, cli docs, pending changesets). Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV Co-authored-by: Claude <noreply@anthropic.com>
…trol names the widened pattern Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 142 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ee96faa5dd5b9aeea7610b55a592e57964dbf68f && git checkout ee96faa5dd5b9aeea7610b55a592e57964dbf68f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 369bcbeda7bb6c2cbc8c3c3892435351506c960c a97a38db05143feadc46fe4d661b6db870cc2301 && git checkout -B drift-repro 369bcbeda7bb6c2cbc8c3c3892435351506c960c && git merge --no-ff a97a38db05143feadc46fe4d661b6db870cc2301
node scripts/docs-audit/affected-docs.mjs --json 369bcbeda7bb6c2cbc8c3c3892435351506c960c
|
|
The failure is |
Contract reviewServed-tier: 66/66 ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #19870
Clause-②: yes
Implements ruling
5807946372on this card (maintainer, verbatim: 「19870 去掉」; re-graded p2 in5808347937), items 1 to 5, in the package-ID region ofmanifest.zod.ts/manifest.test.tsonly. The VERSION-grammar hunks that draft PR #19637 carries in the same two files are untouched; a no-driver merge-tree probe of this head againstorigin/main369bcbeis clean.What changes
MANIFEST_ID_PATTERN(packages/spec/src/kernel/manifest.zod.ts) becomes/^[a-z0-9][a-z0-9-]*(\.[a-z0-9][a-z0-9-]*)+$/(item 1). Additive widening: every id legal before stays legal;com.163.crm,com.example.2appandlocal.2024-appbecome legal. Still refused: a hyphen-led segment, an underscore, upper case, a single segment, an empty segment.manifestIdRefusal) now reads... Expected reverse-domain notation ('com.steedos.crm', 'org.apache.superset') — lowercase dot-separated segments of letters, digits and inner hyphens; a segment may not open with a hyphen; underscores are not admitted.The pattern docblock loses 「Each segment starts with a letter」 and says why a digit may open a segment; theidTSDoc states the rule (item 2).MANIFEST_ID_EXAMPLESunchanged. A digit-led bare word now gets the prefixed repair (2fagetsDid you mean 'com.example.2fa'?), where it used to get none.manifest.test.ts: oneACCEPTED/REFUSEDtable.com.example.2appmoved to accepted withcom.163.crmbeside it; each accepted row asserts the id parses to itself.com.example.-app,com.example.my_appandCom.Example.Appstay refused, each assertinginvalid_formatand the declaration's own sentence. ThePackageSchema.manifestIddoor is judged once on the same table, the expected verdict read from the table and never from the pattern. One more pin: the sentence names digits and the leading-hyphen rule and states no leading-letter clause.manifest.namespaceis untouched (item 4). Its leading-letter rule stays for the SQL-identifier reason.@objectstack/specminor (item 5),.changeset/19870-manifest-id-digit-led-segment.md.Repo-wide pin sweep (card-class clauses ① and ②)
Swept by RULE, not by literal: every string literal in
git ls-files(ts/mts/mjs/js/json/md/mdx/yml, release-owned trees excluded) that the OLD pattern refuses and the NEW one accepts. That gave 586 raw hits, triaged by hand to the package-id ones. Every same-semantic pin is flipped in this PR, and each flipped pin asserts the new behaviour rather than just dropping the old assertion:packages/metadata-protocol/src/protocol.install-manifest-id.test.tscom.4example.crma REFUSED rowcom.-example.crm(hyphen-led) at the install and duplicate doorspackages/cloud-connection/src/marketplace-install-local-id-gate.test.tscom.1acme.crma REFUSED row200,manifestIdechoed, registered and filed ascom.1acme.crm.json. The refused reason is kept bycom.-acme.crmpackages/cli/test/package-publish-manifest-id.test.ts9foo.barin the relaxation table;2024 Appderivedlocal.2024-appand was refused9foo.bar,com.163.crm,local.2024-appare ids.2024 Apppublishes: exit 0, both POSTs, wiremanifest_idlocal.2024-app, not rewritten. Every slug the derivation can produce, from the name or the filename, parsesProse that stated the retired rule, made false by this change:
packages/spec/src/migrations/entries/semantic/18.manifest-id-reverse-domain-required.ts: the unreleased v18 prescription said "each opening with a letter". Reworded, andregistry.tsregenerated withgen:migration-registry(not hand-edited).content/docs/deployment/cli.mdxand thepublish.tsdocblocks: they saidlocal.2024-appis rejected, and listed9foo.baras a shape the control plane refuses. These are comment and docs changes only.⚠ Three PENDING release notes corrected (confirmation requested)
check-empty-changesetis red on this PR by design. This is its DELIBERATE CORRECTION class. Three pending changesets onmainquote the refusal sentence verbatim in atextblock, and this PR changes that sentence. Each block now quotes what the door will actually print. Nothing else in those notes moved: their "If you are refused" prose was already true under the widened rule..changeset/19417-install-door-parses-manifest-id.md: thepkg-arefusal quote..changeset/19417-protocol-install-primitive-parses-manifest-id.md: thecom.example.my_erprefusal quote..changeset/19576-install-local-id-gate.md: thelate-apprefusal quote.Restoring them from base would ship a sentence no door prints.
skip-changesetis deliberately not applied. Please confirm these three edits in writing on this PR.Check Changesetis not a required context.PM mechanism hypotheses — measured
MANIFEST_ID_PATTERN,manifestIdRefusalorManifestSchema, or names them in a comment. Pins that refused a digit-led segment under another spelling: the three consumer rows above. Two producers still assume a letter-led last segment and prefix a digit-led name (2fabecomesapp-2fa):manifestIdSlug(packages/cli/src/commands/init.ts) andderiveManifestId(packages/create-objectstack/src/rewrite-identity.ts). Their output stays legal, so they are left as they are (Acceptance notes).deriveNamespaceFromPackageIdfrom the built spec gives:com.example.2app→app,com.163.crm→crm,com.4example.crm→crm,com.example.123→null.namespace-prefix.test.tsis green, and so is the metadata-protocol duplicate-door namespace test.PACKAGE_ID_REinpackages/app-shell/src/views/studio-design/packages-io.ts:244, the same at the pinf8a9d0fb05and atorigin/mainc3a26cc. That copy requires a letter first, lets a later segment open with a digit, and admits underscores. The one new drift this PR adds: a digit-led FIRST segment (9foo.bar) is now legal in spec, and the Studio duplicate form's client check still refuses it. objectui does not import the spec constant, and nothing is removed or renamed, so the Console Pin Gate is unaffected.manifest_id, cloudb524051) is carried as a lead.Verification, at head
a97a38db0@objectstack/spec: full suitevitest run --project local: 540 files, 15800 passed, 2 todo.typecheck(tsc, scripts, test layer): exit 0. Focused (manifest,namespace-prefix,package-namespace,template-manifest-id,package-api): 5 files, 188 passed.protocol.install-manifest-id,protocol.duplicate-package-target-namespace): 32 passed,typecheck0 errors.packages-install-manifest-id,artifact-granted-permissions,domain-handler-registry): 101 passed.init-manifest-id,nav-contribution-groups.package-id,package-publish-manifest-id): 43 passed,typecheck0 errors.rewrite-identity): 22 passed.marketplace-install-local-id-gate): 23 passed. It has notypecheckscript.scripts/ablation-replace.mjs. Both legs landed on disk, and each restore was proven: blob == HEAD blobf0913fa,git diff HEADempty.manifest.test.tswent 5 red. That is the two accepted digit rows, the shared-table door test, the2farepair, and the every-suggestion-parses test.pnpm --filter @objectstack/spec check:generated --fixreports all 15 up to date against a dist it built. The only regenerated file isregistry.ts.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --rangives 115 derived, 110 run, 5 NOT MEASURED, 0 unrun. Of the 110 run, 109 exit 0 andcheck-empty-changesetexits 1 by design (above).check:dual-build-cjs-loads,check:i18n,check:i18n-coverage,check:i18n-walk-parity.check:type-check-debt. Its whole-workspace re-measure was cut off by the batch timeout.Acceptance notes
None of these is filed. Each is an observation with no carrier (承接者:无).
2fabecomesapp-2fainos init;123becomescom.example.app-123in create-objectstack) is no longer required by the rule. Their comment "A segment must OPEN with a letter" now states a retired clause. Their output pins stay true as pins of the output.os package publish: the refusal remedy arms for DERIVED sources (manifestIdRemedy,artifact-manifest-name/artifact-filename) are now unreachable. A slug is always one legal segment, so a derived id always parses. The arm for a declaredmanifest.idstays live.PACKAGE_ID_RE(H3): a second transcription of the rule. It was already looser (it admits underscores, which the server refuses loudly) and is now stricter on a digit-led first segment. Not exercised.deriveNamespaceFromPackageIddrops a leading digit run, even when that run is part of a word (com.example.2fa-leavegivesfa_leave). This is pre-existing, only a default, and the author can declarenamespace.studio/plugin.zod.ts, andcontent/docs/plugins/development.mdx) keeps its own leading-letter pattern. It is a different key under a different rule, not a package id.Generated by Claude Code