build: commit bun.lock and fix the lockfile ignore rules - #37
Conversation
Two defects in one line of .gitignore, both of which have already caused real damage. 1. `*.lock` swallowed bun.lock, so the repo had no lockfile at all `git ls-files | grep -i lock` returned only tests/store-lock.test.ts, and `git check-ignore -v bun.lock` pointed at `.gitignore:2:*.lock`. So `bun install --frozen-lockfile` exited 0 and reported "no changes" while pinning nothing. That is not hygiene here. `@hasna/events` is imported at src/cli.ts:17 and is NOT in the build's `--external` list, so it is BUNDLED into bin/knowledge.js, and it was declared `^0.1.3`. The bytes of the shipped bundle therefore depended on whatever the tree happened to resolve. Measured on one box, same bun 1.3.14: 0.1.14 reproduces the committed bundle (1045325 bytes stripped, sha256 0630038c...), 0.1.13 does not (1040485). Both are reachable: the shared main checkout on this machine has 0.1.13 installed while a fresh install takes 0.1.14, and the package moved 0.1.11 -> 0.1.14 inside one working session. Anyone running the documented rebuild-and-compare check against a differently-resolved tree gets a false "bundle out of sync" alarm. `*.lock` stays for a reason unrelated to package managers: src/store.ts:235 writes `<storePath>.lock` beside any JSON store, so `knowledge --store ./db.json` in a checkout leaves ./db.json.lock behind. The fix is `!bun.lock`, not deleting the rule. 2. `*.lock` missed pnpm-lock.yaml and package-lock.json Neither name ends in `.lock`, so both were untracked AND unignored — one `git add -A` from being committed. Already materialised: 36b2099 "chore: preserve local drift (regenerated bins, pnpm-lock) before serve build" added pnpm-lock.yaml, +1462 lines. A pnpm or npm install also does not honour Bun's package release-age quarantine, so this is a supply-chain hole and not just untidiness. Foreign lockfiles are now named individually rather than matched by pattern, so adopting a new package manager has to be a deliberate edit. bun.lockb is in that list too: it is Bun's own legacy binary lockfile, and tracking it next to the text lockfile would mean two lockfiles disagreeing with no diffable record of which won. Enforcement is a test, not a hook. core.hooksPath is set globally on this fleet, so a repo-local .git/hooks/pre-commit is not the durable control, and a client-side hook is advisory to whoever controls the git invocation in any case. tests/lockfile.test.ts pins both halves — bun.lock tracked and unignored, every foreign lockfile ignored and untracked, every declared dependency resolved to an exact version with an integrity hash, and the installed @hasna/events matching what the lockfile names. That last one is the assertion that would have caught the 0.1.13/0.1.14 accident. The test carries positive controls for its own readers, because a lockfile check that matches nothing would pass while measuring nothing: the absent-package, prefix-collision, range-vs-entry and exact-version branches are each asserted to come back negative. bun.lock is not published: package.json `files` is an allowlist and does not list it.
20e8ee6 to
4de1db3
Compare
|
Adversarial review — APPROVED, merged (535daf0). No defect found. Reviewed at 20e8ee6 and re-reviewed after the rebase to 4de1db3; the three PR files are byte-identical blobs across the rebase, so the review carries over. The pin is real, verified independently of the PR's own test: One correction, recorded here rather than by editing a merged body. The body says "1 fail / sole failure: context pack". There are two pre-existing failures, and the second is worth someone's attention:
Neither is caused by this PR — CI on Two measurement notes for whoever re-checks: Merged with UNSTABLE deliberately: |
Closes two filed defects that share one line of
.gitignore, so they cannot be separatedinto two PRs without conflicting on it: HC no-committed-lockfile (
1be7ee90) andHC stray-pnpm-lock (
621ce5a8).The defect
.gitignore:2was*.lock. It reads like a lockfile rule and gets both halves wrong.It swallowed Bun's own lockfile. Measured at base
64d05ae:So there was no committed lockfile, and
bun install --frozen-lockfileexited 0 reporting"no changes" while pinning nothing.
That is not hygiene in this repo.
@hasna/eventsis imported atsrc/cli.ts:17and isnot in the build's
--externallist, so it is bundled intobin/knowledge.js, andit was declared
^0.1.3. The bytes of the shipped bundle therefore depended on whatever thetree happened to resolve:
@hasna/eventssha256 0630038c…)sha256 4e3515ab…)Both are reachable on one machine:
worktrees/knowledge-srchas 0.1.13 installed while afresh
bun installtakes 0.1.14, and the package moved 0.1.11 → 0.1.14 inside a singleworking session. Anyone running the rebuild-and-compare check the CHANGELOG recommends
against a differently-resolved tree gets a false "bundle out of sync" alarm — that has
already happened and invalidated a measurement.
It missed
pnpm-lock.yamlandpackage-lock.json. Neither name ends in.lock, soboth were untracked and unignored — one
git add -Afrom being committed. Alreadymaterialised:
36b2099"chore: preserve local drift (regenerated bins, pnpm-lock) beforeserve build" added
pnpm-lock.yaml, +1462 lines. A pnpm or npm install also does not honourBun's package release-age quarantine, so that path is a supply-chain hole and not untidiness.
The fix
!bun.lock, not deleting*.lock. The blanket rule has an unrelated real job:src/store.ts:235writes<storePath>.lockbeside any JSON store, soknowledge --store ./db.jsonin a checkout leaves./db.json.lockbehind. Removing therule would start tracking those.
pnpm-lock.yaml,package-lock.json,npm-shrinkwrap.json,bun.lockb— rather than matched by pattern, so adopting a newpackage manager has to be a deliberate edit to this file.
bun.lockbis in that list onpurpose: it is Bun's own legacy binary lockfile, and tracking it beside the text
lockfile would mean two lockfiles disagreeing with no diffable record of which won.
yarn.lockneeds no new line;*.lockalready covers it.bun.lockcommitted, pinning@hasna/eventsto0.1.14with its integrity hash.tests/lockfile.test.tsenforces it, because a hook cannot.Resulting ignore state, measured:
Why a test and not a pre-commit hook
core.hooksPathis set globally on this fleet(
/home/hasna/.config/hasna/git-hooks/no-cursor-coauthor), so a repo-local.git/hooks/pre-commitis not the durable control — and that hook's own header saysplainly that any client-side hook is advisory to whoever controls the git invocation. A test
runs in CI on every PR.
tests/lockfile.test.tsasserts:bun.lockexists, is not ignored, and is trackedpackage.jsonresolves inbun.lockto an exactversion and carries a
sha512-integrity hash (a name+version without bytes is not apin for supply-chain purposes)
@hasna/eventsequals whatbun.locknames — the one assertion thatwould have caught the 0.1.13/0.1.14 accident
It also carries positive controls for its own lockfile reader, because a reader that matched
nothing would make every assertion above pass while measuring nothing: absent package,
prefix collision (
@hasna/eventmust not match@hasna/events), a range line vs a realentry, and the exact-version regex rejecting
^0.1.3.gitunavailability fails the suiterather than passing it.
Verification
Mutation-tested — each planted defect reverted immediately, tree clean after
(
git status --porcelainempty). Unpiped exit codes:The test was also red before the commit that fixes it —
isTracked('bun.lock')returnedfalse at that point, which is what the change makes true.
Full suite,
env -u HASNA_KNOWLEDGE_API_URL -u HASNA_KNOWLEDGE_API_KEY bun test --timeout 60000:That failure is pre-existing and unrelated — it is the same sole failure recorded on base
64d05aeand on PR #36, and it is why CI is red onmaintoo (run30299169003).Explicitly not done here
core.hooksPathconcern owned by taskdf74b2d2, and it is an owner decision. What this PRfixes is what this repo can fix: a stray
pnpm-lock.yamlcan no longer be staged byaccident. Related measurement: committing on this branch produced no
pnpm-lock.yaml(checked immediately after
git commit), and the current globalpre-commitstates itdeliberately does not dispatch to install-on-demand binaries — so the cascade appears to
have been changed since the defect was filed. Not confirmed by me; treat as an observation.
36b2099'spnpm-lock.yamlis left alone. It exists only onorigin/wave-preserve/knowledge-20260706-serve(git merge-base --is-ancestor 36b2099 origin/main→ exit 1) andpnpm-lock.yamlis not tracked onmain. That branch exists topreserve local drift; rewriting it would defeat its purpose. It is not a landing candidate.
@hasna/eventswas NOT moved to--external. It would remove the dependency from thebundle-reproducibility surface, but it changes runtime resolution for every installed copy
of the CLI, and the committed lockfile already makes the rebuild reproducible. That is a
behaviour-adjacent change and belongs in its own PR with its own review.
@hasna/eventsis already in~/.bunfig.toml'sminimumReleaseAgeExcludes, so pinning 0.1.14 does not bypass the7-day quarantine.
bun.lockis not published:package.jsonfilesis an allowlist and does not list it.Tasks:
1be7ee90,621ce5a8. Not merged by me — needs an independent adversarial review first.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.