Skip to content

publish: read published deps from the package folder in the post-check - #112

Merged
gabe4coding merged 1 commit into
mainfrom
harness/publish-postcheck-deps-path
Oct 26, 2026
Merged

gabe4coding merged 1 commit into
mainfrom
harness/publish-postcheck-deps-path

Conversation

@gabe-bots

@gabe-bots gabe-bots Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Intent

Make the publish post-check pass after a good publish. It reads each direct dependency where npm installs it from the shrinkwrap, then compares the version with the lockfile.

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Install the published version from npm] --> B{"Dependency in the package folder?"}
  B -- yes --> D[Read its installed version]
  B -- no --> C{"Dependency in the install folder?"}
  C -- yes --> D
  C -- no --> E[Report the dependency as missing]
  D --> F{"Same version as the lockfile?"}
  F -- yes --> G[Run the CLI once]
  F -- no --> H[Fail the step with the drift list]
Loading

Drift

  • The check moves from an inline script in publish.yml to scripts/check-published.mjs. Thus npm test runs its test.
  • A dependency in neither folder now gives a missing drift line with the ::error:: annotation. Before, it gave a raw ENOENT stack.

Decisions

  • The lookup follows Node resolution: the package folder first, then the install folder. A stale hoisted copy never hides a wrong nested copy.
  • The script reads package.json and package-lock.json from the working directory, as the inline script did.
  • No docs change: the "Releases" text in docs/development.mdx does not name a folder and stays true.
  • No version bump: scripts/ and .github/ are not in the npm package.
  • Door: two-way. A revert restores the inline script, and the next publish shows the result.

Evidence

The harness runs the real "Check the published package" step from publish.yml against @gabe4coding/plain@3.1.0 from npm. It uses Node 22.23.4 and npm 11.21.1, as the CI job does.

Before (main b4aad50). This is the same failure as Publish run 39253045346 on 3fa3e12:

== repo: plain @ b4aad50 (main)
== node v22.23.4, npm 11.21.1, PACKAGE=@gabe4coding/plain@3.1.0
added 473 packages in 3s
Error: ENOENT: no such file or directory, open '/tmp/plain102-runner.YguuNK/published/node_modules/@modelcontextprotocol/sdk/package.json'
Node.js v22.23.4
== step exit code: 1

After (branch 5008d98):

== repo: plain @ 5008d98 (harness/publish-postcheck-deps-path)
== node v22.23.4, npm 11.21.1, PACKAGE=@gabe4coding/plain@3.1.0
added 478 packages in 4s
✔ examples/todo.yaml
== step exit code: 0

The real install puts the dependencies in the package folder. The install folder holds only the package:

$ ls $prefix/node_modules
@gabe4coding
$ ls $prefix/node_modules/@gabe4coding/plain/node_modules | wc -l
409

The check still fails on real drift. This run uses the same real install and a lockfile copy that pins @modelcontextprotocol/sdk to 0.0.1:

::error::npm did not honor the shrinkwrap: @modelcontextprotocol/sdk 1.32.1 (lockfile 0.0.1)
== check exit code: 1 (expected 1)

New test scripts/check-published.test.mjs, with the inline check of main moved verbatim into the script:

not ok 1 - passes when npm nests the locked dependencies in the package folder, as for a shrinkwrap
ok 2 - passes when npm hoists the locked dependencies to the prefix
not ok 3 - reads the nested copy first, as Node resolves it, and reports its version
not ok 4 - reports a dependency that is in neither folder
not ok 5 - the publish workflow runs this script in "Check the published package"
# pass 1
# fail 4

The same test on the branch:

ok 1 - passes when npm nests the locked dependencies in the package folder, as for a shrinkwrap
ok 2 - passes when npm hoists the locked dependencies to the prefix
ok 3 - reads the nested copy first, as Node resolves it, and reports its version
ok 4 - reports a dependency that is in neither folder
ok 5 - the publish workflow runs this script in "Check the published package"
# pass 5
# fail 0

Full suite: main has 577 tests, 577 pass. The branch has 582 tests, 582 pass, 0 fail. node scripts/validate.mjs on the branch:

VALIDATION PASSED: key-free gate, live e2e, claims gate. Agent evals not needed: no MCP tool, result or browser skill change. Routing evals not needed: no agent note change.
  key-free gate
    # tests 582
    # pass 582
    # fail 0
    docs ok: 18 file(s)
    agent notes ok: 8 file(s)
    All examples validate.
  live e2e
    23 passed, 15 failed, 0 flaky, 0 skipped  (188 Jev calls, 345323 tokens, 58.89s)
    E2E passed.
  claims gate
    FALSE PASS 0   false fail 0   inconclusive 26   right 207/233   error 0   flips 0/233

The 15 failed e2e specs are the 15 expect-fail specs. actionlint .github/workflows/publish.yml exits 0 with no findings.

The real proof is the next Publish run after a version bump. This PR does not bump the version, so the step does not run on its merge.

Reading map

Config (CI):

  • .github/workflows/publish.yml, step "Check the published package": the inline script becomes one call to the new script.

Error handling:

  • scripts/check-published.mjs: a dependency in neither folder becomes a missing drift line, not a thrown ENOENT.

Public API: none. Tests changed or deleted: none, one test file added.

Closes #102

@gabe-bots gabe-bots Bot added the needs-gabe Needs Gabe's decision before work continues label Oct 26, 2026
@gabe-bots

gabe-bots Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@greptile review

@gabe4coding
gabe4coding force-pushed the harness/publish-postcheck-deps-path branch from d89e4e9 to 1a2f709 Compare October 26, 2026 08:46
npm installs a shrinkwrapped package's dependencies in the package's own
node_modules. The "Check the published package" step read them from the
install prefix, so it failed with ENOENT after the good 3.1.0 publish.

Move the check to scripts/check-published.mjs. It resolves each direct
dependency as Node does: the package folder first, then the prefix. An
integration test covers both layouts, a version drift and a missing
dependency, and checks that publish.yml runs the script.

Closes #102
@gabe4coding
gabe4coding force-pushed the harness/publish-postcheck-deps-path branch from 1a2f709 to adae568 Compare October 26, 2026 09:19
@gabe-bots

gabe-bots Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai review

@gabe4coding
gabe4coding merged commit 685534d into main Oct 26, 2026
7 checks passed
@gabe4coding
gabe4coding deleted the harness/publish-postcheck-deps-path branch October 26, 2026 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-gabe Needs Gabe's decision before work continues risk:t2-hard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish post-check fails after a good publish: it reads deps from the wrong path

2 participants