Skip to content

fix: follow-ups to #152 — session learner on macOS, Sonnet 5 price, release npm check - #153

Merged
CodeWithJuber merged 4 commits into
masterfrom
fix/post-1.1.0-followups
Sep 22, 2026
Merged

CodeWithJuber merged 4 commits into
masterfrom
fix/post-1.1.0-followups

Conversation

@CodeWithJuber

Copy link
Copy Markdown
Owner

Summary

Follow-ups found while verifying #152, which was merged (at f64c540) before these commits arrived. One commit per fix:

  • Session learner on macOS (b78b55e). global/guards/session-learner.sh ran timeout 90 claude -p. Stock macOS has no timeout, so the opt-in learner silently never recorded a lesson on a Mac; the error only reached .learn.log.

    • A shared forge_timeout in _guardlib.sh runs timeout, else gtimeout, else a bash watchdog.
    • The watchdog keeps stdin and the exit status. Its output goes to /dev/null, so a caller's $(…) never waits on it.
    • It also keeps the 90 s cap that the learner's lock reclaim relies on.
    • learn-consolidate.sh --llm, which 1.1.0 fixed by running without a limit, now uses the same helper and keeps its 180 s cap.
  • Windows home folder (339a869). learnedDir() follows HOME, which is where the bash learner writes.

    • Node's homedir() reads USERPROFILE on Windows, so a differing Git Bash HOME sent the consolidator to another folder.
    • The hermetic test now accepts HOME/USERPROFILE while test/_setup.js points them at its sandbox, and still fails if either holds the real home.
  • Sonnet 5 price (154246e). src/model_tiers.json scheduled $2/$10 → $3/$15 on 2026-09-01. Anthropic cancelled that increase.

    • The pricing page, checked 2026-09-22, lists $2/$10 as the standard price.
    • Since 2026-09-01 forge priced Sonnet 5 50% high. The cost report reads the flat price, so it always had.
    • Now a flat $2/$10, with pricingVerified 2026-09-22 (all four tier prices re-checked). The universal router registry matches.
  • Release post-publish check (c5227db). v1.0.0 and v1.1.0 both shipped but their release jobs went red. The check gave npm 60 s:

    Release Publish finished Check gave up Packument Last-Modified
    v1.0.0 02:17:23 02:18:27 02:20:02 (+159 s)
    v1.1.0 13:12:17 13:13:23 13:16:29 (+252 s)

    The registry also sends Cache-Control: max-age=300, so a retry could re-read the copy cached by the pre-publish npm view. The check now tries 40 × 15 s (10 minutes) with --prefer-online.

Verification

Run locally on Windows (Node 24), on this branch's tree (d9cab12):

Check Result
npm test 1,389 tests: 1,381 pass, 0 fail, 8 skipped
npm run lint 0 errors, 14 warnings (same as master)
npm run typecheck 0 errors
forge docs check passes
release verify step bash -n passes; npm view … --prefer-online returns the published version

Why 8 tests skip here:

  • 6 are Windows-only guards, including the two new no-timeout tests. They build a symlinked PATH, which needs elevation on Windows, and Git Bash ships timeout anyway.
  • 2 need opt-in settings.
  • The two new tests run on the Linux and macOS jobs, where the symlinked PATH reproduces stock macOS.

Checked by hand in Git Bash, with a PATH holding no timeout/gtimeout:

  • Unfixed hook: logs timeout: command not found and never calls the stub claude.
  • Fixed hook: calls the stub once and appends its lesson.
  • forge_timeout:
    • stdin passes through;
    • exit status 3 is kept;
    • a 6 s job is killed at 1 s;
    • $(…) returns in 0 s despite a 20 s watchdog.

Not in this PR

  • Tier-table update. claude-opus-4-8 and claude-fable-5 are valid ids but listed as legacy; claude-opus-5 and claude-fable-5-1 are current, at the same prices. Moving the tier table onto them is a product decision.
  • v1.1.0's red release job. It is a false alarm: npm serves 1.1.0 and the GitHub Release exists. Re-running the job goes green, because each step is idempotent.

🤖 Generated with Claude Code

CodeWithJuber and others added 4 commits September 22, 2026 16:13
session-learner.sh piped the transcript into `timeout 90 claude -p`. Stock macOS
has no `timeout`, so the command was not found (logged only to .learn.log), the
model never ran, and the opt-in learner recorded nothing on a Mac.

A shared forge_timeout in _guardlib.sh runs `timeout`, else Homebrew's
`gtimeout`, else a bash watchdog. The watchdog keeps stdin (`<&0`: a
background job without job control otherwise reads /dev/null) and sends its
own output to /dev/null so a caller's $(...) never waits on its sleep. The
learner's forge_lock reclaim relies on the 90 s cap, which the watchdog keeps.
learn-consolidate.sh --llm now uses the same helper instead of its local one.

Tests build a PATH with no timeout/gtimeout from symlinks, which reproduces
stock macOS on the Linux runners too: forge_timeout keeps stdin and the exit
status and kills an overrun; the real session-learner hook calls a stub
claude and appends its lesson. Checked by hand in Git Bash: the unfixed hook
logs "timeout: command not found" and never calls the stub.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… them

The session learner is a bash hook and writes $HOME/.claude/skills/learned.
learnedDir() used node's homedir(), which on Windows reads USERPROFILE, so a
Git Bash HOME that differed from it sent learn-consolidate to another folder.
learnedDir() now follows HOME when set (POSIX homedir() already did).

The hermetic test required every env var src reads to be unset under test.
HOME is sandboxed by test/_setup.js, not unset, so the test now accepts
HOME/USERPROFILE while they point away from the real home, and still fails
the moment one holds it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
model_tiers.json scheduled Sonnet 5 to rise from $2/$10 to $3/$15 on
2026-09-01. Anthropic cancelled that increase: the pricing page (checked
2026-09-22) lists $2/$10 as the standard price. Since 2026-09-01 forge
priced Sonnet 5 50% high, and the cost report, which reads the flat price,
always had.

Sonnet 5 is now a flat $2/$10 and pricingVerified is 2026-09-22 (all four
tier prices re-checked). The universal router's registry entry matches.
priceOf/allPricePairs take an optional table so the date-window logic keeps a
test of its own with a synthetic schedule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v1.0.0 and v1.1.0 both shipped (npm serves them, the GitHub Releases exist)
yet their release jobs failed the post-publish check, which tried 6 times
10 s apart:
- v1.0.0: publish finished 02:17:23, check gave up 02:18:27; the packument's
  Last-Modified was 02:20:02 (159 s after publish).
- v1.1.0: publish finished 13:12:17, check gave up 13:13:23; Last-Modified
  13:16:29 (252 s after publish).
The registry also serves packuments with Cache-Control max-age=300, so a
retry could re-read the copy cached by the idempotency check's `npm view`.

The check now tries 40 times 15 s apart with --prefer-online.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@CodeWithJuber
CodeWithJuber merged commit f630515 into master Sep 22, 2026
11 checks passed
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