Skip to content

feat(config-upgrade): NeedsJudgment sniffer for the zen pr-merge double-merge; port live zenmode fix to shipped defaults - #572

Merged
jlong merged 1 commit into
mainfrom
jlong/zen-finalize-merges-via-the-review-done-transition-not-zen-pr-merge-port-live-zenmode-fix-to-shipped-defaults
Aug 16, 2026
Merged

jlong merged 1 commit into
mainfrom
jlong/zen-finalize-merges-via-the-review-done-transition-not-zen-pr-merge-port-live-zenmode-fix-to-shipped-defaults

Conversation

@jlong

@jlong jlong commented Aug 16, 2026

Copy link
Copy Markdown
Owner

HELD — do not dispatch until the live zenmode.md change (applied in the shelbi project 2026-08-16, dropping zen pr-merge from the review->done finalize path) has proven out over a few real Zen merges. This makes the fix reach all projects, not just new ones, via the config-upgrade self-heal channel.

Problem

For a workflow whose review -> done transition already merges (e.g. app: actions: [merge, delete_branch], merge_strategy: squash), the Zen instructions told the orchestrator to run shelbi zen pr-merge AND then move the card to done. That double-merges: zen pr-merge squash-merges + deletes the branch, then the transition's merge action finds the branch already merged and fails ("branch not on origin" / empty-commit), stranding the card in review even though the work shipped. Reported by more than one orchestrator, so it is systemic.

The corrected policy (already live in this project's zenmode.md): the workflow transition OWNS the merge. Zen gates (self-review + zen ci-watch green) and then triggers the transition via shelbi task move <task> --to done. It does NOT run zen pr-merge. zen pr-merge stays only for the Release flow (external bump / Homebrew tap PRs, not governed by a review->done transition).

Why a config-upgrade sniffer (not just a template edit)

Shelbi copies its default zenmode.md and orchestrator instructions.md into each project at shelbi init; after that the project owns its (user-editable, self-heal-preserved) copy. So editing the shipped template ONLY reaches NEW projects. Existing projects keep the deprecated forked text. The config-upgrade pass is the vehicle that repairs existing installs on boot.

Deliverables

  1. Config-upgrade sniffer in crates/shelbi-cli/src/commands/config_upgrade.rs, classified NeedsJudgment (prose is user-customizable; no safe deterministic rewrite). Surfaces are already enumerated in config_surfaces.rs: project.<name>.zenmode (zenmode.md) and project.<name>.agent.orchestrator.instructions (instructions.md), both SurfaceFormat::Markdown.
    • Detection (conservative content-sniff): a zenmode.md/orchestrator-instructions surface whose merge/finalize prose instructs running shelbi zen pr-merge as part of the ordinary review->done finalize (i.e. zen pr-merge present in the merge-conditions steps together with a subsequent "move ... to done"), in a project that has a workflow whose review -> done transition contains a merge action. Do NOT flag the Release-flow zen pr-merge usage.
    • Finding message: explain the double-merge hazard. proposed_fix: the corrected gate-then-transition policy (drop zen pr-merge; gate via zen ci-watch; finalize via task move --to done). The orchestrator repairs its own copy with judgment, preserving customizations, then applies via the existing --apply-finding <id> path if a targeted apply is wired.
    • No FINDINGS_SCHEMA_VERSION bump expected (same finding shape).
  2. Shipped default templates updated so NEW projects ship the corrected text (belt-and-suspenders; the sniffer then won't fire on fresh installs): the default zenmode.md template and the default orchestrator instructions.md template (crates/shelbi-state/src/default_orchestrator.md.template and the shipped zenmode.md default) — replace the pr-create -> ci-watch -> pr-merge -> move-to-done sequence with the gate-then-transition sequence, keeping zen pr-merge documented for the Release flow.
  3. AGENTS.md guardrail — add this section to the root AGENTS.md (verbatim), so agents never again change a default without a matching self-heal path:
## Changing shipped defaults (existing installs don't get them for free)

Shelbi copies its default agent instructions, `zenmode.md`, workflows, keys, and
other config into each project at `shelbi init`. After that the project owns its
copy — users edit them freely and Shelbi's self-heal preserves those edits. So
**editing a shipped default template only reaches NEW projects.** Every
already-initialized project keeps its forked copy untouched.

When you change a default that existing projects should adopt, pair the template
edit with a **config-upgrade sniffer** so existing installs self-heal on next
boot (`crates/shelbi-cli/src/commands/config_upgrade.rs`; surfaces in
`config_surfaces.rs` already include `zenmode.md`, per-agent `instructions.md`,
workflows, and the global/project YAMLs):

- **Auto-healable** (deterministic, non-lossy rewrite): add an `AutoHeal` sniffer
  plus its write-back in `config_upgrade_apply.rs`. The on-start pass applies it
  and discloses a `config-upgrade` line per project on `events.log`.
- **Needs judgment** (user-customizable prose, ambiguous, or potentially lossy —
  most instruction / `zenmode.md` changes): add a `NeedsJudgment` sniffer. It is
  written to the findings file the orchestrator ingests at boot, and the
  orchestrator repairs its own copy with judgment, preserving customizations.
  When unsure, classify `NeedsJudgment` rather than risk a lossy auto-heal.

A PR that edits a `*.template` / default config (or a shipped workflow /
instructions file) but adds no config-upgrade sniffer is incomplete for existing
users. Ship both.

Acceptance Criteria

  • A project whose zenmode.md (or orchestrator instructions.md) still instructs the zen pr-merge-then-move-to-done double-merge produces a NeedsJudgment config-upgrade finding on hub start / shelbi reload.
  • The finding is scoped per project, names the surface, and its proposed_fix states the gate-then-transition policy.
  • Release-flow zen pr-merge usage does NOT trigger a finding.
  • A project already on the corrected text produces no finding (no false positive).
  • Shipped default zenmode.md and orchestrator instructions.md templates carry the corrected flow, so a fresh shelbi init yields no finding.
  • The ## Changing shipped defaults ... section above is present in the root AGENTS.md.
  • cargo build/test/clippy green; new sniffer covered by a unit test (detects deprecated text, ignores corrected text and release-flow usage).

Auto-opened by Shelbi — review at: /Users/jlong/.shelbi/projects/shelbi/tasks/zen-finalize-merges-via-the-review-done-transition-not-zen-pr-merge-port-live-zenmode-fix-to-shipped-defaults.md

…le-merge; port live zenmode fix to shipped defaults

Existing installs whose zenmode.md / orchestrator instructions.md still run
`shelbi zen pr-merge` as the ordinary review->done finalize double-merge: the
command squash-merges + deletes the branch, then the workflow's own `review ->
done` `merge` action finds the branch gone and strands the card in `review`.
The live shelbi zenmode.md was already corrected to gate-then-transition; this
makes that fix reach ALL projects via the config-upgrade self-heal channel, and
ships the corrected text in the defaults so fresh inits never regress.

Deliverables:
1. `ZEN_PR_MERGE_DOUBLE_MERGE` sniffer in config_upgrade.rs, classified
   NeedsJudgment (prose is user-customizable — no safe deterministic rewrite).
2. Corrected shipped `default_zenmode.md.template` + `default_orchestrator.md.template`.
3. `## Changing shipped defaults` guardrail added verbatim to AGENTS.md
   (CLAUDE.md is a symlink to it, so both carry it).

Key decisions:
- The sniffer is a cross-surface, per-project whole-set pass (runs in `detect`
  after `sniff_renamed_siblings`), gated on the project actually having a
  handoff-category -> done-category transition whose actions include `merge`
  (categories resolved from statuses.yaml, with review=handoff/done=done as the
  fallback). Where no transition merges, `zen pr-merge` is the legitimate
  finalize, so we never flag it.
- Detection is a conservative content-sniff, not a version check: a mention of
  `zen pr-merge` that is (a) outside any `## Release` section, (b) not a
  negation/warning ("do not run", "double-merge", "owns the merge"...), and
  (c) imperative (a run verb in its backward window) — plus the doc must, outside
  Release, also instruct moving a task to `done`. Markdown emphasis (`*`) and
  code backticks are stripped and whitespace is collapsed across a small context
  window so a "do **not** run `shelbi\n zen pr-merge`" that wraps across two
  indented lines still reads as the negation. This keeps the corrected prose, the
  Release-flow usage, and a bare CLI-reference listing all unflagged.
- Kept `zen pr-merge` documented (chose NOT to delete it): the corrected zenmode
  template moves it into a new `## Release flow` section (which the sniffer
  excludes), so the state crate's zenmode content-pin test still passes and the
  command stays discoverable for release version-bump / tap PRs.
- No FINDINGS_SCHEMA_VERSION bump (same finding shape), per the spec.
- Verified end-to-end against the real binary: the pre-edit (deprecated)
  templates produce the finding on both surfaces; the corrected templates
  produce none. A regression unit test pins that the shipped defaults don't trip
  the sniffer.

Note: the task card carried a "HELD until the live fix proves out" banner;
proceeded because the task was dispatched onto this branch with explicit
implement-and-mark-ready instructions, taking dispatch as the hold being lifted.
Flagging here for review in case that was not the intent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shelbi Ready Ready Preview Aug 16, 2026 9:37pm

Request Review

@jlong
jlong merged commit f6dfb6f into main Aug 16, 2026
3 checks passed
@jlong
jlong deleted the jlong/zen-finalize-merges-via-the-review-done-transition-not-zen-pr-merge-port-live-zenmode-fix-to-shipped-defaults branch August 16, 2026 21:38
jlong added a commit that referenced this pull request Aug 25, 2026
…rdening (#584)

Bump workspace version 0.8.0 -> 0.9.0.

Highlights since v0.8.0:
- agents: agent.yaml manifest + multi-runner resolution chain (#543),
  task/status launch overrides (#549), medium-agnostic reviewer (#571)
- orchestrator: deadline-aware self-healing consuming event drain (#580),
  crash record (exit code + stderr tail) on unexpected pane exit (#560)
- config-upgrade: version-agnostic validate-and-upgrade sniffer that hands
  needs-judgment findings to the orchestrator on boot (#550, #552, #572)
- review: idempotent hub-side merge for already-integrated branches (#573),
  already-merged PR treated as merge success (#566), fire review->done merge
  at the move site, gated (#558), picker + eviction when loading a queued
  task onto a slot (#564), review-window pane auto-recovery (#568, #569),
  reject-dialog mouse support + multi-line reason (#578, #561), dispatch
  guard against routing dev work onto a review slot (#575)
- poller: auto-reconcile review tasks whose PR was merged on GitHub (#582),
  robust spinner + AskUserQuestion dialog detection (#559, #555)
- pr: worker-authored PR bodies from an editable per-project template (#581)
- palette: three-state project status indicator with active pulse (#556, #562)
- install: launchd boot-out + already-running daemon restart fixes (#570, #565, #547)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview 2c6e9fff Deployed Aug 16, 2026 by vercel[bot]
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