Skip to content

fix: --version reports the installed package's version, not the core crate's literal - #970

Closed
thekevinbot wants to merge 6 commits into
mainfrom
claude/issue-958-q2loh3
Closed

thekevinbot wants to merge 6 commits into
mainfrom
claude/issue-958-q2loh3

Conversation

@thekevinbot

@thekevinbot thekevinbot commented Aug 20, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #958

Root cause

--version renders CARGO_PKG_VERSION of the dirsql core crate
(packages/rust/Cargo.toml, literal 0.2.7). putitoutthere rewrites that literal
in the crates.io lane only — the PyPI wheel and the npm addon are built from a
checkout where it is untouched, while their own manifests are rewritten to the real
release version. So every published wheel and npm package since 0.2.7 has printed
dirsql 0.2.7, whatever version it actually was.

There is no single literal to fix: the version has three correct sources, one per
publish lane.

Fix

lane version source
crates.io binary the core crate's CARGO_PKG_VERSION — unchanged
PyPI wheel dirsql-py-ext's CARGO_PKG_VERSION, which maturin writes into the wheel and the module already exports as __version__ — now one constant, so the CLI and SDK cannot disagree
npm packages/ts/package.json, read by the launcher and passed to the addon

The core gains cli::run_cli_with_version(argv, version); run_cli keeps its
signature and delegates with its own version. ~35 lines of code across five files;
the rest is the tests and the fragments the gates require.

packages/python/Cargo.toml's placeholder moves 0.2.7 → 0.0.1. It is a
placeholder either way (the release tooling rewrites it), but while it equalled the
core crate's, the python distcheck assertion below passed whether or not the CLI read
the right source — the coincidence that hid this.

Regression guard

dirsql-distcheck installs the published artifact and runs it; it asserted only that
the output contained the word "dirsql". Both flows now compare the exact string
against the version the package manager installed — the wheel filename for pip, the
installed package.json for npm.

RED first, on CI, both flows for the same reason
(python,
ts):

`dirsql --version` printed 'dirsql 0.2.7', expected 'dirsql 0.0.1'

E2E Verification

  • Ran e2e suites locally for every affected SDK
  • Python SDK e2e: pass (29 passed)
  • TypeScript SDK e2e: pass (13 passed)
  • Rust core e2e: pass (cargo test --workspace --features cli --no-fail-fast)
  • packages/python/e2e-attestation.json refreshed
  • packages/ts/e2e-attestation.json refreshed
  • Command(s) run:
    • uv run python -m pytest tests/e2e/ -x -q (packages/python)
    • pnpm test:e2e (packages/ts)
    • cargo test --workspace --features cli --no-fail-fast
    • dirsql-distcheck node / dirsql-distcheck python — both OK
  • Result summary: all green. Two sandbox-only failures in the Rust suite, neither
    related to this change: vtab.rs::unreadable_file_yields_null_content_… (the
    sandbox runs as root, so a chmod 000 file is still readable) and one
    sdk.rs::it_streams_watch_events watcher timing flake that passed on re-run.

Manual exercise (the point of the fix, not just the tests):

$ packages/python/.venv/bin/dirsql --version        dirsql 0.0.1   # == dirsql.__version__
$ node packages/ts/dist/cli/dirsql.js --version     dirsql 0.0.1   # == package.json
$ ./target/debug/dirsql --version                   dirsql 0.2.7   # the crate, unchanged
$ node packages/ts/dist/cli/dirsql.js query "SELECT COUNT(*) AS n FROM './'"
[{"n":557}]
$ node packages/ts/dist/cli/dirsql.js --nope        error: unexpected argument '--nope' found  (exit 2)

Changelog / Migrations

  • Changelog fragment added under packages/<pkg>/changelog.d/ for each changed package (rust, python, ts)
  • Migration fragment — judged not required: this is a bug fix that makes a wrong
    output correct, and no API breaks. The one visible shift is that a source
    checkout now reports 0.0.1 where the CLI used to say 0.2.7; published
    artifacts only gain the right number. Say the word and I'll add fragments.

Parity

PARITY.md updated. This restores parity rather than introducing drift: the
crates.io binary was already correct and both bindings now match it. The plumbing is
asymmetric on purpose (pyo3 bakes its crate version in, napi takes an optional
argument) because the manifest a publisher rewrites differs per lane; both surfaces
are launcher-facing, not SDK API.

Follow-up spotted, not fixed here

persist.rs / parsed_cache.rs stamp the same core-crate literal into the cache as
an invalidation key, so a wheel or addon writes 0.2.7 for every release — a core
change that alters parsing will not invalidate an existing cache. Same root cause,
different blast radius; worth its own issue rather than widening this PR.

claude added 4 commits August 20, 2026 18:15
…alled

The distcheck gates -- the tier whose whole job is to install the published
artifact and run it -- asserted only that `dirsql --version` printed the word
"dirsql". That blind spot let #958 ship: wheels and npm packages published at
0.4.x print `dirsql 0.2.7`, the on-disk literal of the Rust core crate
compiled into them, because only the crates.io release lane rewrites it.

Both gates now compare the exact string against the version the package
manager installed -- the wheel filename for pip, the installed package.json
for npm. The python e2e suite makes the same assertion against a dev build
(and drops the binary staging that #738 made dead).

`packages/python/Cargo.toml`'s placeholder moves 0.2.7 -> 0.0.1 so it stops
coinciding with the core crate's. With the two equal, the python assertion
passes even when the CLI is reading the core crate's version -- exactly the
coincidence that hid the bug; the npm lane's placeholder already differed,
which is why its gate goes red on today's code.

RED on CI, both for the same reason (run 32398805851 / 32398805744):

    `dirsql --version` printed 'dirsql 0.2.7', expected 'dirsql 0.0.1'

Refs #958

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGHtvJMekPAB9qweTsTNK9
`--version` rendered the `dirsql` core crate's `CARGO_PKG_VERSION`. Only the
crates.io release lane rewrites that literal, so the binary was right and both
bindings -- which embed the same crate but publish on their own version lines
-- printed `dirsql 0.2.7` on every release since 0.2.7 (#958).

Each artifact now reports the version of the manifest its own publisher
rewrites:

  crates.io binary  the core crate's CARGO_PKG_VERSION  (unchanged)
  PyPI wheel        dirsql-py-ext's CARGO_PKG_VERSION, which maturin writes
                    into the wheel and the module already exports as
                    `__version__` -- now one constant, so the CLI and the SDK
                    cannot disagree
  npm package       packages/ts/package.json, read by the launcher and passed
                    to the addon

The core gains `cli::run_cli_with_version(argv, version)`; `run_cli` keeps its
signature and delegates with its own version, so `cargo install dirsql
--features cli` is untouched. Parsing moves from the derive's `try_parse_from`
to building the command and overriding `.version()`, which needs clap's
`string` feature (an owned version string).

The plumbing is deliberately asymmetric across the bindings, because the
manifest a publisher rewrites differs: pyo3's `run_cli(argv)` keeps its
signature and bakes its crate version in, while napi's `runCli(argv, version?)`
takes one, since the addon crate's version is a workspace placeholder no npm
release touches. Omitted, the core's version still stands.

Verified by running the artifacts, not only the tests:

    packages/python/.venv/bin/dirsql --version    -> dirsql 0.0.1
    node packages/ts/dist/cli/dirsql.js --version -> dirsql 0.0.1
    ./target/debug/dirsql --version               -> dirsql 0.2.7  (the crate)

and both distcheck flows, which install the built wheel / packed tarball and
compare against what the package manager recorded, now pass.

Fixes #958

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGHtvJMekPAB9qweTsTNK9
@thekevinbot
thekevinbot force-pushed the claude/issue-958-q2loh3 branch from 5206c15 to b45d84f Compare August 20, 2026 18:17
claude added 2 commits August 20, 2026 18:23
The TS mutation gate surfaced `main.ts:32 BlockStatement (-> {})` as a
surviving mutant: with `try { return … } catch { return undefined }`, emptying
the catch body still yields `undefined` implicitly, so no assertion can tell
the two apart -- an equivalent mutant, and an exemption is not the fix here.

Assigning inside the `try` and returning after it makes the arm observable:
emptied, execution falls through and destructures `undefined`, which the
"falls back to undefined rather than failing the CLI" test now catches
(verified by applying the mutant by hand: TypeError, 1 failed | 10 passed).
Behavior is unchanged.

Refs #958

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGHtvJMekPAB9qweTsTNK9

Copy link
Copy Markdown
Collaborator Author

Closing unfixed — this belongs upstream, not here.

The stale --version string comes from putitoutthere bumping only the crate it builds. On the pypi and npm lanes that's packages/python and packages/ts/napi; the CLI's #[command(version)] lives in packages/rust, which ships inside both artifacts as a path-dep and never gets bumped. Filed as thekevinscott/putitoutthere#621 with the per-lane breakdown.

This PR worked around that by resolving the version from the host package's manifest at runtime and threading it into run_cli. It works, but it's a per-binding API change in every consumer to patch a build-time gap — and the same fix would have to be repeated in every other repo that hits this. The upstream fix also covers the part this PR didn't: persist.rs / parsed_cache.rs stamp that same stale literal as a cache-invalidation key, so published caches never invalidate across releases.

dirsql#958 stays open until upstream lands and dirsql re-releases. Branch claude/issue-958-q2loh3 is left in place if any of the distcheck assertions are worth salvaging separately.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--version prints a stale version string

2 participants