Skip to content

fix(vibe): ship 1.0.81 fleet lessons - #343

Merged
shafty023 merged 4 commits into
mainfrom
fix/vibe-1081-lessons
Oct 24, 2026
Merged

shafty023 merged 4 commits into
mainfrom
fix/vibe-1081-lessons

Conversation

@shafty023

@shafty023 shafty023 commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Purpose

Ships vibe 1.0.81. It covers the 2026-10-23 and 2026-10-24 lessons in the orchestrator's lessons ledger that 1.0.79 (#341) and 1.0.80 (#342) did not already cover. Each rule sits at the highest rung it could reach: a hook or an evidence gate where one fits, launcher behavior for the writer queue, and prose only where nothing mechanical applies.

Already covered by #341 and #342, so not repeated here: credential improvisation, green-watch messaging, force pushing scratch refs, direct vibe worker launches, hyphenated ClosedLoop MCP names and parallel prep while the writer runs.

Lessons

Lesson Rung Where it landed
Targeted tests skipped a lane pnpm test:lanes named; #9238 broke main gate handoff/scripts/pr-facts.mjs requires a passing testRuns entry with lane for every lane match, by its printed command (a mention-only lane needs notRunReason); vibe-verify-worker.md pre-pr mode; fleet SKILL.md and both worker templates no longer say "exactly the tests code_tests_for maps"
New prop on a shared component missed a second capability ledger (#9238) prose vibe-change-worker.md
Layout plays passed vacuously in the jsdom story sweep; three plays left stale on main (#9238, #9127) prose vibe-verify-worker.md: a story file with a play on a component whose layout, position or scrolling the diff changes also runs in the real-browser story test; handoff SKILL.md keeps it a PR opening gate
New gate inside a batch-only CI job never exercised before merge (#9230, fixed in #9237) gate + tool new handoff/scripts/ci-job-shape.mjs (tier, fetch depth, env, if per job); pr-facts.mjs ciCheckProblems requires ciCheckRepros when the diff touches a check, CI script or workflow; vibe-verify-worker.md
Bot review comments treated as human gate handoff/scripts/review-threads.mjs resolves a source: bot thread answered reason with evidence; a human's reasoned answer stays open. vibe-environment-worker.md marks bot threads (Bot author, self-described automated review, or git config vibe.reviewBots); handoff SKILL.md step 3 (bots contradict themselves across PRs); fleet SKILL.md
Watcher started with & inside a compound command, twice hook hooks/shell-safety-guard.mjs refuses watch.sh unless it is its own run_in_background call; watch.sh's second-copy refusal now names the kill-guard own step and the sleep tick
HOLD sent twice as a message; only TaskStop stopped the session hook (reminder) new hooks/pause-guard.mjs on SendMessage adds a TaskStop reminder to context and never refuses (patterns and tests below); fleet SKILL.md
Merge watcher never fired: set -- $st does not word-split in zsh hook shell-safety-guard.mjs refuses set -- $var and points to read -r a b <<< "$var"
Remote reruns tested a stale commit (ISS-13043) hook + remote script shell-safety-guard.mjs refuses e2e-slot.sh without --head <sha>; the remote e2e-slot.sh takes --head (see "Live change on the second laptop"); vibe-verify-worker.md Tier C
Stale-image reruns: a rerun reused images built from another worktree or commit (ISS-13067, #9241, 2026-10-24 03:10Z and 16:47Z) gate new skills/vibe/scripts/image-head.mjs records, per compose project, the commit and worktree that built the images; e2e-lock.mjs run refuses a --no-build run whose images do not match --head and that worktree, and records a passing build; the staged remote e2e-slot.sh.next makes the same check; vibe-verify-worker.md Tier C says to build fresh after a worktree switch
Writer queue wedged on a stopped or length-rejected turn (ISS-13043, ISS-13051) launcher tools/vibe-workers/src/ledger.ts: a new request supersedes a FAILED turn, and a Claude turn whose launcher process is gone is closed on the next claim. claude-worker.ts caps an over-long result instead of rejecting it
Writer turn hit the 30-minute cap mid-merge with no report (vibe-13007) launcher claude-worker.ts reports CAP-HIT with the changed-file count, mid-merge flag and a patch saved in the git dir; nothing is committed or reset
No push path for a session without a Vercel env (ISS-13051) prose vibe-environment-worker.md redeploy step 7: a session with no lastRequestId stops after the normal push
Human QA env started with the wrong command (ISS-13043) data + test handoff/scripts/parallel-prep.mjs local QA lane names pnpm vibe up and a readiness check past the org picker
Orchestrator flooded one writer with about ten asks prose fleet SKILL.md Claude workers

Not included: the fleet watcher's STALLED-WRITER flag for a dirty or mid-merge worktree with no file change. The cap lesson suggested it as a second layer; only the launcher's CAP-HIT report ships here.

pause-guard trigger patterns

It never refuses: a match adds a TaskStop reminder to the sender's context and the message is sent. A message that already mentions TaskStop, or one that is not a string, gets nothing.

Pattern Matches
^\s*(?:HOLD|PAUSE)\b (case-sensitive) "HOLD: main is being reverted", "PAUSE until the revert lands"
\b(?:pause|hold|freeze)\s+(?:all\s+)?(?:of\s+)?(?:your\s+)?(?:work|writers?|sessions?|everything|agents?|subagents?|turns?)\b (any case) "Please pause your writer now.", "hold all work on #9230", "freeze everything"
\bstop\s+(?:all\s+)?(?:of\s+)?(?:your\s+)?(?:writers?|sessions?|everything|agents?|subagents?|all\s+work)\b (any case) "Stop your subagents and wait"
\bstand\s+down\b (any case) "Stand down until I say go"

hooks/pause-guard.test.mjs pins the matches above, and checks that each of these gets nothing: "Push nothing more to the branch.", "Stop the investigation and report what you found.", "Hold off on pushing until CI is green", "Holding steady on #9230, ready for review", "Stop at the first failure and report it", "Fix the stop button label", "hold the PR open for review", and "HOLD: stopped with TaskStop; wait for the revert". It also checks that the hook output carries additionalContext and no permissionDecision. That follows the code plugin's PreToolUse hook, which adds context the same way.

Live change on the second laptop

~/vibe-remote/e2e-slot.sh is not in this repo. On 2026-10-24 at 12:02 local I replaced it with a version that takes an optional --head <sha> and refuses to run unless HEAD is that commit, both when the run joins the queue and after it waits. Without --head it behaves as before. It was swapped in with an atomic mv (a run already in flight keeps the old file open), and the previous copy is ~/vibe-remote/e2e-slot.sh.bak-20261024. To roll back: cd ~/vibe-remote && cp -p e2e-slot.sh.bak-20261024 e2e-slot.sh.new && mv e2e-slot.sh.new e2e-slot.sh.

The image check and a warning when --head is missing are staged, not deployed, as ~/vibe-remote/e2e-slot.sh.next, because a slot run was in flight. It calls this PR's image-head.mjs from the remote's ~/Source/claude-plugins checkout, so deploy it once #343 is merged and that checkout is on main. With no slot run holding /tmp/cl-e2e.lock, run cd ~/vibe-remote && cp -p e2e-slot.sh e2e-slot.sh.bak-$(date +%Y%m%d%H%M) && mv e2e-slot.sh.next e2e-slot.sh. Roll back the same way from that backup.

Release metadata

  • Both vibe manifests and the README runtime line move to 1.0.81; the version pin moves from the 1.0.80 contract test to test_vibe_1081_lessons_contract.py.
  • Instruction text under plugins/vibe is 2 words shorter than 1.0.80, measured at the final head with instruction-words.mjs --changelog CHANGELOG.md --version 1.0.81. Prose that the new hooks and gates now enforce was removed to pay for the new rules.

Commands run

I ran the suites on the second laptop, because the first laptop was at load 185 and vitest timed out there. Each failure below was rerun on its own.

  • Repository node suite (node --test over every plugins/**/*.test.mjs) at the final head: 787 of 788 passed. The one failure was cl-sweep/scripts/core-client-process.test.mjs, a sendInput timeout at remote load 128 in code this PR does not touch. Alone it passes 4 of 4. Earlier, the evidence comment fixture failed because it had no lane run for the new gate to accept; the fixture was fixed.
  • uv run pytest plugins/ at the final head: 2,490 passed and 3 skipped. Earlier runs caught three prose contracts pinning lines I had trimmed: the verify worker's no-pattern stop line, handoff's resolve-after-check wording, and handoff's WebKit iPhone and Chromium Pixel names. All three were restored.
  • uv run ruff check . and uv run pyright: clean.
  • tools/vibe-workers: typecheck clean; npm run build leaves the committed bundles unchanged. Full vitest: 762 of 763 passed. The one failure was a 30-second main-sync-report-admission case under remote load 131, in code this PR does not touch; it passes on rerun. An earlier full run had six similar load timeouts, and both affected files pass alone on this branch and on main. The last commit changes no vibe-workers source.
  • tools/plugin-manifests: passed.
  • instruction-words.mjs --base origin/main --changelog CHANGELOG.md --version 1.0.81: added 695, removed 697, net 2 shorter; the changelog claim matches.
  • Live remote e2e-slot.sh, tried in a scratch repo: a --head naming an older commit is refused, the current commit runs, no --head behaves as before, and --head HEAD is rejected. Staged e2e-slot.sh.next, tried in scratch repos against this branch's image-head.mjs: --no-build with no recorded build is refused, a build records, reuse at the same head and worktree runs, and reuse from another worktree is refused.

Risks

  • vibe-pr-evidence.json files written before this release lack lane runs and, for check or CI changes, ciCheckRepros, so the PR evidence gate refuses them until they are rerun. That is intended.
  • A --no-build run through vibe's e2e lock with no recorded build for its compose project is refused until a build runs. The first run after this release builds.
  • A new writer request now closes a FAILED turn instead of waiting for its continuation. The persistent session still resumes, so its context survives.

- Gate every lane pnpm test:lanes names and CI job shape repros
- Refuse detached watchers, zsh set -- splitting, unpinned e2e-slot
- Refuse hold messages until TaskStop; resolve evidenced bot threads
- Close stopped or rejected writer turns; report CAP-HIT with a patch
- Push env-less sessions; name pnpm vibe up for human QA

Testing: node, vitest, pytest, ruff and pyright suites
Risks: new evidence fields block older vibe-pr-evidence files
- Restore the verify worker's no-pattern stop line for Codex runs
- Keep the resolve-after-check wording handoff tests pin
- Give the evidence comment fixture its lane run
- Drop a duplicated review step from the fleet skill

Testing: pytest plugins/vibe, evidence comment node test
Risks: None identified
- Drop the argument separator from the lane fixture command

Testing: node --test pr-facts.test.mjs
Risks: None identified
- Record e2e image build commits and refuse stale --no-build reuse
- Run real-browser story tests for layout changes with plays
- Make the SendMessage hold hook a TaskStop reminder, not a refusal

Testing: node hooks, image-head, e2e-lock, handoff suites; pytest
Risks: a --no-build run without a recorded build now builds first
@shafty023
shafty023 merged commit a610ad0 into main Oct 24, 2026
10 checks passed
@shafty023
shafty023 deleted the fix/vibe-1081-lessons branch October 24, 2026 18:20
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