CANP-WP-0002 T07: semver precedence and strict packaging
Two defects from the original review of the seed. Prerelease ordering was worse than first recorded. parse_semver returned (major, minor, patch, raw_string), so 1.0.0-rc1 and 1.0.0 tied on the numeric fields and then compared as strings — "1.0.0-rc1" > "1.0.0". A release candidate therefore shadowed its own release for `newest` and for `>=`, not just for the no-version case. parse_semver now returns a SemVer section 11 precedence key: numeric fields, a release/prerelease rank, then dot-separated prerelease identifiers with numeric ones compared numerically. Build metadata is ignored. Beyond ordering, prereleases are excluded from `any`, `newest` and `>=` entirely; only an exact pin selects one, so publishing a release candidate never changes what existing consumers resolve to. A package holding only prereleases now says so rather than reporting a bare not-found. Packaging copied the whole source directory, so a stray .git, virtualenv or scratch file landed in the catalog and registry. Section 2 already required otherwise — tools MUST ignore unknown non-reserved files unless a manifest field references them — so this is conformance rather than a new rule. What is new is that omissions are reported instead of silent: not packaged (not a reserved path, not referenced by the manifest): .git/, .venv/, notes.txt LICENSE joins the reserved paths. Strict packaging would otherwise drop a package's license text while faithfully copying its `license` field, which contradicts section 14's instruction to surface licensing on publish and install. Spec: 2 (LICENSE, packaging obligation, reporting), 17.1 new, 10.3 note. Reference CLI: parse_semver rewritten with is_prerelease; select_version and pick_version updated; copy_package and report_skipped replace copy_immutable. Tests 65 -> 78. examples/pqrst-estimate carries a LICENSE and a license field, exercising the new reserved path. Also fixes a leaked loop variable in package_members that would have reported a bad `template` path as an `evals` error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM Assistant: claude-code Assistant-Model: opus Assistant-Process: 388925@bnt-lap001 Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
This commit is contained in:
parent
e885eb7b05
commit
95a8bb31d2
8 changed files with 306 additions and 34 deletions
|
|
@ -388,22 +388,57 @@ the format revision warrants it.
|
|||
|
||||
```task
|
||||
id: CANP-WP-0002-T07
|
||||
status: todo
|
||||
status: done
|
||||
priority: low
|
||||
state_hub_task_id: "f642abe6-8222-5958-88ee-7a53454f2344"
|
||||
```
|
||||
|
||||
Two defects found in the same review, independent of the format questions:
|
||||
|
||||
1. **Prerelease versions sort as newest.** `parse_semver` in
|
||||
`reference/canned_prompts.py` returns `(major, minor, patch, raw_string)`,
|
||||
so `1.0.0-rc1` and `1.0.0` tie on the numeric fields and then compare as
|
||||
strings — `"1.0.0-rc1" > "1.0.0"`. `resolve_installed` with no `--version`
|
||||
therefore selects a prerelease over its own release. Order prerelease below
|
||||
release, or state in § 17 that v0.1 ignores prerelease ordering.
|
||||
2. **`copy_immutable` copies everything.** `add`/`publish` use
|
||||
`shutil.copytree` over the whole source directory, so a stray `.git`,
|
||||
`.venv`, or scratch file lands in the catalog and registry. § 2 says tools
|
||||
MUST ignore unknown non-reserved files unless a manifest field references
|
||||
them. Decide whether packaging is reserved-paths-only or an explicit
|
||||
ignore list, then align the implementation and § 2.
|
||||
1. **Prerelease versions sorted as newest.** Confirmed worse than first
|
||||
recorded: `1.0.0-rc1` shadowed `1.0.0` for `newest` *and* `>= 1.0.0`, so a
|
||||
release candidate hid its own release from every selector.
|
||||
2. **`copy_immutable` copied everything**, so a stray `.git`, `.venv` or
|
||||
scratch file landed in the catalog and registry.
|
||||
|
||||
**Decisions (operator, 2026-09-06):**
|
||||
|
||||
- *Prereleases are excluded unless named.* They sort below their release and
|
||||
are skipped by `any`, `newest` and `>=`; only an exact pin selects one.
|
||||
Publishing a release candidate therefore never changes what existing
|
||||
consumers resolve to — the point of marking it a candidate. Matches npm and
|
||||
cargo.
|
||||
- *`LICENSE` joins the reserved paths.* Strict packaging would otherwise drop
|
||||
a package's license text while faithfully copying its `license` field, which
|
||||
contradicts § 14's instruction to surface licensing on publish and install.
|
||||
|
||||
The strict-versus-ignore-list question needed no decision: § 2 already
|
||||
required it — "Tools MUST ignore unknown non-reserved files unless a manifest
|
||||
field explicitly references them" — so packaging by reserved path is
|
||||
conformance, not a new choice. What was worth adding is that omissions are
|
||||
**reported**, never silent.
|
||||
|
||||
Delivered:
|
||||
|
||||
1. `parse_semver` now returns a SemVer § 11 precedence key: numeric fields,
|
||||
then a release/prerelease rank, then dot-separated prerelease identifiers
|
||||
with numeric ones compared numerically. Build metadata is ignored, so
|
||||
`1.0.0+build.1` and `1.0.0+build.2` tie. `1.0.0-rc.10` correctly outranks
|
||||
`1.0.0-rc.2`.
|
||||
2. `select_version` excludes prereleases from `any`, `newest` and `>=`;
|
||||
`pick_version` reports "only prerelease versions are available" rather than
|
||||
a bare not-found.
|
||||
3. `copy_package` replaces `copy_immutable`, copying reserved paths plus
|
||||
manifest-referenced files only, and returning what it skipped;
|
||||
`report_skipped` names those on stderr. `skipped_entries` reports top-level
|
||||
names without walking into an ignored directory, so a stray virtualenv
|
||||
costs nothing to skip.
|
||||
4. § 2 gains `LICENSE`, the packaging obligation, and the reporting SHOULD;
|
||||
§ 17.1 (new) specifies precedence and prerelease selection; § 10.3 notes
|
||||
the exclusion.
|
||||
5. `examples/pqrst-estimate` now carries a `LICENSE` and a `license: MIT`
|
||||
field, exercising the new reserved path. Tests 65 → 78.
|
||||
|
||||
**Fixed while implementing.** `package_members` reused a loop variable as the
|
||||
error label, so a bad `template` path would have been reported as an `evals`
|
||||
error.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue