chore(release): Bump version to 0.16.0 - #439
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… release material)
Review:
|
CLAUDE.md (this PR) |
AGENTS.md (untouched) |
|
|---|---|---|
| L103 | 4,836 |
4,818 |
| L399 | 4,836 + per-module |
4,818 + per-module |
| L404 | 4,836 |
4,818 |
Same three-line edit applies. AGENTS.md is also missing from the release-prep file list — exactly the omission that let plugin/.claude-plugin/plugin.json drift to 0.7.0 in the past (the checklist itself calls that out).
2. CHANGELOG.md:41 points at a doc that doesn't have the note. The #431 entry says detection stays "ISO-date-only (m/d/yyyy remains text; documented in LIMITATIONS)" — but m/d/yyyy appears nowhere in docs/ or plugin/, and docs/LIMITATIONS.md has no positional-put detection section. The real documentation is docs/reference/cli.md:408-415 ("Type Inference" + --no-detect), which lists ISO dates as detected but never states that US-style dates stay text. Either add the caveat to docs/LIMITATIONS.md or repoint the CHANGELOG at docs/reference/cli.md. This matters because the bullet is a promise to the user hunting for why their 3/31/2026 landed as text.
3. The breaking change is buried in a ### Fixed bullet. 0.16.0 has only ### Fixed and ### Added, yet it carries:
- a source-incompatible API change —
SourceContext.sourcePath: Path→content: SourceContent(CHANGELOG.md:78-86, parenthetical at the end of the ooxml: bytes-based reads have no SourceContext — preserved workbook children lost on read-bytes→write #412 bullet); - a behavior change — positional
putnow types values that previously stored as text, so existing scripts produce different bytes (escape hatch:--no-detect); - explicit batch
format:"date"on unparseable input now errors where it previously wrote a cell.
The file claims Keep a Changelog + SemVer, and the repo has used ### Changed 22× and ### Breaking Changes twice. Since the annotated tag message is extracted verbatim from this heading, a Maven consumer upgrading 0.15.0 → 0.16.0 currently gets a compile error whose only warning was a parenthetical inside a "Fixed" item. Hoisting these three into a ### Changed (or ### Breaking) block above ### Fixed is a two-minute edit with real downstream value. docs/STATUS.md:24 does flag it as "breaking" — the CHANGELOG should match.
Nits (pre-existing drift the PR walks past)
4. docs/STATUS.md:168-177 per-module table is stale. The headline directly above it is now 4,836, but the table rows sum to 3,996 (evaluator 1571, core 1104, ooxml 684, cli 406, cats-effect 110, agent 102, prelude 19). Since the PR edits line 166, refreshing the seven rows underneath with the numbers already in CLAUDE.md:399 closes the inconsistency in the same commit.
5. docs/reference/testing-guide.md:3,225 still says 4,085 "as of 0.12.6". The roadmap's identical 4,085 got fixed here (docs/plan/roadmap.md:13), and CLAUDE.md points readers at the testing guide — worth the same one-line refresh.
Suggestion: automate the pin sweep
35 hand-maintained pins with automated coverage for only two of them (test-examples.sh covers project.scala↔build.mill; release.yml covers the scripting skill). WorkbookMetadata.appVersion, plugin.json, and the README/QUICK-START/scripting-docs pins are protected by nothing but the checklist — and the checklist just missed AGENTS.md. A ~15-line scripts/check-version-pins.sh in CI (extract BuildConfig.version, assert every com.tjclp::xl:<v> occurrence plus plugin.json's version plus WorkbookMetadata.appVersion matches; fail listing offenders) would have caught the plugin.json 0.7.0 drift then and AGENTS.md today. xl-cli already models the better pattern — generate, don't copy — so appVersion could alternatively read a generated resource like BuildInfo does.
Nothing here blocks the release once (1) is applied; (2) and (3) are cheap and both affect what users read at upgrade time.
Review:
|
| Module | STATUS.md table | CLAUDE.md (this PR) |
|---|---|---|
| xl-evaluator | 1571 | 1855 |
| xl-core | 1104 | 1191 |
| xl-ooxml | 684 | 923 |
| xl-cli | 406 | 585 |
| xl-cats-effect | 110 | 135 |
| xl-agent | 102 | 122 |
| xl (prelude) | 19 | 25 |
| Total | 3,996 | 4,836 |
The drift is pre-existing, but the header line right above the table is one of the lines this PR edited, and it's stamped "verified via ./mill __.test, 2026-07-29" — which reads as a claim that the table below was verified too. Since the CLAUDE.md numbers are already in the diff, this is a copy-paste fix. Worth doing before the tag, because STATUS.md is the doc CLAUDE.md points readers at for "current capabilities."
2. docs/reference/testing-guide.md still says 4,085 "as of 0.12.6"
testing-guide.md:3 and its total row (:225) both report 4,085, four releases behind — and it is the file CLAUDE.md sends readers to for suite structure. That leaves three different per-module breakdowns across three docs (CLAUDE.md 4,836 / STATUS.md 3,996 / testing-guide 4,085). Neither file is on the release-prep checklist, which is arguably the root cause; if you fix them here, consider adding both to the checklist's "Files to Update" list so the next bump cannot reintroduce the split.
3. The one source-breaking change is buried in a ### Fixed bullet
SourceContext.sourcePath: Path → content: SourceContent appears only as a parenthetical at CHANGELOG.md:80-81, inside the #412 entry under ### Fixed. Two reasons to hoist it:
- The tag message is extracted verbatim from this section, so the GitHub release notes for 0.16.0 will bury the only change that breaks compilation for downstream callers under a heading that promises the opposite.
- The CHANGELOG already has precedent for this —
### Breaking Changessections at:1476and:1538.
Suggest a ### Breaking Changes (or ### Changed) subsection at the top of the 0.16.0 entry, with the SourceContent.OnDisk(path) | InMemory(bytes) migration line and the "fromFile unchanged" note pulled up into it. The PR body says the notes flag this change — they do, just not where a consumer scanning release notes will see it. (Semver-wise, a source-breaking minor on 0.x is conventional and the roadmap pre-planned 0.16.0 as this slot, so no objection there.)
4. WorkbookMetadata.appVersion is the last hand-maintained version literal
xl-core/src/com/tjclp/xl/workbooks/WorkbookMetadata.scala:30 hardcodes Some("0.16.0"), bumped by hand every release. The CLI already avoids this — Main.scala:45-50 reads a generated /version.properties. Since plugin.json demonstrably drifted (stale at 0.7.0 until the checklist called it out), a generated constant would remove the remaining drift site.
The purity charter rules out the CLI's resource-loading approach for xl-core (a class-init side effect in a 100%-pure module), but Mill generatedSources emitting a private[xl] val version compile-time constant from BuildConfig.version keeps it pure and total. Out of scope for this PR — worth an issue.
Relatedly: scripts/test-examples.sh:14-29 only guards examples/project.scala against build.mill. Extending that guard to the other version-bearing files (README, QUICK-START, plugin.json, WorkbookMetadata) would turn the whole checklist into something CI enforces rather than something a human re-greps.
5. Minor: CLAUDE.md still frames smart detection as batch-only
CLAUDE.md:246-251 heads the section "Batch JSON Syntax (typed values + smart detection)" and gives the opt-out as "detect":false, while :192's example is a bare put B5 1000. After #431 that framing is stale — positional put detects identically, with --no-detect as the opt-out. The user-facing docs are already correct (docs/reference/cli.md:107,414, xl-cli/SKILL.md:306,311,670), so this is only the agent-facing file — but that is precisely the file an agent reads before choosing between put and batch. One line under the CLI Usage block covers it.
Not a concern: no security surface (version strings and prose only), no performance implications, no new tests needed. The ### Fixed/### Added structure, date stamps, and the roadmap "Current Version" line are all internally consistent, and the roadmap TL;DR's stale "4,085 tests passing" is correctly refreshed to 4,836.
Recommendation: fix #1 (and ideally #2 and #3) before tagging — a release commit is the one commit whose doc numbers get read as authoritative. #4 and #5 are follow-up issues. Happy to push the STATUS.md table, testing-guide, and CHANGELOG restructure as a commit on this branch if useful.
🤖 Generated with Claude Code
Release 0.16.0 "Bedrock" — wave 19 (#436) + structural recalc-before-write (#437) + positional put detection (#438).
Mechanical bump across the 11 version-bearing files (35 pins), CHANGELOG heading cut with the #431 entry folded in, STATUS/roadmap release records, test counts refreshed (4,836).
Verified: compile 810/810 (0 non-exhaustive), full suite 1028/1028 (4,836 cases), test-examples (drift guard), verify-skill-snippets --local, no SNAPSHOT refs. Release notes flag the SourceContext.sourcePath → content API change.
🤖 Generated with Claude Code