Skip to content

fix(0.2.1): surface npm install failures via marker file#133

Open
pmclSF wants to merge 1 commit intomainfrom
fix/0.2.1-postinstall-surfacing
Open

fix(0.2.1): surface npm install failures via marker file#133
pmclSF wants to merge 1 commit intomainfrom
fix/0.2.1-postinstall-surfacing

Conversation

@pmclSF
Copy link
Copy Markdown
Owner

@pmclSF pmclSF commented May 2, 2026

Summary

Closes the silent-install path flagged in the 0.2.0 launch-readiness review (Item 5: postinstall.js swallows install failure). Pre-fix, npm install -g mapterrain could exit 0 with the binary missing; the user only discovered it minutes later with a confusing retry loop.

Approach

Option B (lazy with loud signal) per the implementation plan. Hard-failing every cosign-missing host would be more disruptive than the failure mode itself.

  • bin/postinstall.js writes ~/.terrain/install-failure.log with the captured error and prints a multi-line framed warning instead of a single line.
  • bin/terrain-installer.js exports writeInstallFailureMarker / clearInstallFailureMarker. runTerrainCli checks the marker before retrying the fetch and throws a structured remediation block if a failed install was recorded.
  • Marker auto-clears on a successful install or successful first run.

User-visible flow after this PR

$ npm install -g mapterrain
... (cosign-missing failure) ...

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! mapterrain: binary install FAILED                              !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

cosign is required to verify the Sigstore signature
[full error message...]

npm install reports success, but the `terrain` binary is NOT
installed. Running `terrain` will fail with the same error
until the underlying issue is resolved.

Marker written to ~/.terrain/install-failure.log

$ terrain analyze
Terrain binary is not installed.

Recorded install failure (2026-05-02T..., darwin/arm64, v0.2.0):
  cosign is required to verify the Sigstore signature

Resolve the underlying issue, then either:
  - Re-run `npm install -g mapterrain` after installing cosign
  - Set TERRAIN_INSTALLER_ALLOW_MISSING_COSIGN=1 to fall back to
    checksum-only verification, or
  - Set TERRAIN_INSTALLER_SKIP_VERIFY=1 to skip verification entirely.

Marker file: ~/.terrain/install-failure.log

Test plan

  • New scripts/test-installer-marker.mjs (Node node:test) — write/clear/idempotency
  • Wired into npm test via new test:unit step
  • npm run release:verify green (format + lint + tests + verify-pack)

Plan link

/Users/pzachary/.claude/plans/kind-mapping-turing.md (Phase 3.5).

🤖 Generated with Claude Code

Closes the silent-install path flagged in the launch-readiness
review. Pre-fix:

  $ npm install -g mapterrain
  > postinstall fails (cosign missing)
  > [warn] one-line stderr message
  > exit 0
  $ terrain analyze
  > silently retries the same fetch
  > fails with the same error
  > user is confused about why "install" reported success

Two acceptable resolutions were on the table; the plan chose Option
B (lazy-with-loud-signal) over Option A (hard-fail npm install).
Hard-failing every cosign-missing host would be more disruptive than
the failure mode itself; CI pipelines that wrap `npm install` would
break for legitimate reasons. The right user experience is: install
"succeeds" with a loud, framed warning, and the *first* `terrain`
invocation refuses to retry silently — printing the original error
verbatim with concrete remediation.

Implementation:

  * `bin/postinstall.js` writes ~/.terrain/install-failure.log with
    the captured error (timestamp, platform, version, message,
    stack) when ensureTerrainBinary throws. The stderr warning is
    upgraded from one line to a multi-line framed banner so it's
    hard to miss in a CI log.
  * `bin/terrain-installer.js` exports `writeInstallFailureMarker`
    and `clearInstallFailureMarker`. `runTerrainCli` (the trampoline
    for `terrain ...`) consults the marker before retrying the
    fetch; if a marker exists AND no installed binary is present,
    it throws the recorded error with a structured remediation
    block instead of attempting another silent retry.
  * On a successful install or successful first run, the marker is
    cleared so future invocations don't see stale state.

Tests added (`scripts/test-installer-marker.mjs`, run via
`node --test`):

  * writeInstallFailureMarker captures the error fields
  * clearInstallFailureMarker removes the marker
  * clearInstallFailureMarker is idempotent

Wired into `npm test` as a `test:unit` step so it runs ahead of
`scripts/verify-pack.js` in the existing release-verify chain.

CHANGELOG note in PR #131 already calls this out as 0.2.1 work; a
follow-up PR can promote the entry from "known issue" to "fixed".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

[RISK] Terrain — Merge blocked

Significant protection gaps in changed code require attention.

Metric Value
Changed files 4 (3 source · 0 test)
Impacted units 6
Protection gaps 6

Coverage gaps in changed code

  • bin/postinstall.js [LOW] — postinstall.js has no observed test coverage.
    → Add unit tests for postinstall.js.
  • bin/terrain-installer.js [MED] — Exported function clearInstallFailureMarker has no observed test coverage.
    → Add unit tests for exported function clearInstallFailureMarker — this is public API surface.
  • bin/terrain-installer.js [MED] — Exported function ensureTerrainBinary has no observed test coverage.
    → Add unit tests for exported function ensureTerrainBinary — this is public API surface.
  • bin/terrain-installer.js [MED] — Exported function runTerrainCli has no observed test coverage.
    → Add unit tests for exported function runTerrainCli — this is public API surface.
  • bin/terrain-installer.js [MED] — Exported function writeInstallFailureMarker has no observed test coverage.
    → Add unit tests for exported function writeInstallFailureMarker — this is public API surface.
  • scripts/test-installer-marker.mjs [LOW] — test-installer-marker.mjs has no observed test coverage.
    → Add unit tests for test-installer-marker.mjs.

Owners: PMCLSF

Limitations
  • No coverage artifacts provided; protection gaps reflect missing data, not measured absence. Provide --coverage to improve accuracy.
  • Mixed test cultures reduce cross-framework optimization confidence. Consider standardizing on fewer frameworks.

Generated by Terrain · terrain pr --json for machine-readable output

Targeted Test Results

No tests selected — change affects only non-code files.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

Terrain AI Risk Review

Metric Value
AI surfaces 13
Eval scenarios 16
Impacted scenarios 0
Uncovered surfaces 13

Decision: PASS — AI surfaces are covered.

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.

1 participant