Skip to content

Release: v7.9.0 — obs dispatcher removed + binary-precedence guard#461

Merged
Data-Wise merged 16 commits into
mainfrom
dev
Jun 5, 2026
Merged

Release: v7.9.0 — obs dispatcher removed + binary-precedence guard#461
Data-Wise merged 16 commits into
mainfrom
dev

Conversation

@Data-Wise

Copy link
Copy Markdown
Owner

v7.9.0 — obs dispatcher removed + binary-precedence guard

Removed

  • `obs` dispatcher — it shadowed the real Homebrew `obs` binary (obsidian-cli-ops) but needed a `python/obs_cli.py` flow-cli never shipped, so a function-beats-binary lookup made the broken dispatcher win in every shell. Deleted dispatcher + `man/man1/obs.1` + its test; scrubbed all inventories. 15 → 14 dispatchers (+ `at` bridge). Canonical `obs` man page now lives in obsidian-cli-ops.

Added

  • Binary-precedence guard (`flow_load_dispatcher`) — drops any newly-defined dispatcher command that shadows an external $PATH binary, so a broken dispatcher can't mask a working tool. Allowlist via `FLOW_INTENTIONAL_SHADOWS` (default `r mcp cc`) or `FLOW_FORCE_DISPATCHER=1`. New regression test (18 checks).

Fixed

Changed

  • Dependency bumps (prettier, actions/checkout v6, lint-staged 17, app-token v3); dropped unused eslint

Test plan

  • Full suite: 59 passed, 0 failed, 1 expected timeout (`e2e-em-dispatcher`, IMAP/tmux)
  • New guard test `test-dispatcher-binary-precedence.zsh`: 18/18
  • `mkdocs build --strict`: clean
  • man-page version-sync guard: 12/12
  • `type obs` resolves to the real binary

🤖 Generated with Claude Code

Test User and others added 16 commits June 4, 2026 11:46
Pre-Homebrew-migration backup (referenced obsolete ~/.zsh/plugins/flow-cli
path). The other ad-hoc .zshrc backups in zsh/ are gitignored; this was the
only tracked one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spec to remove the redundant/broken flow-cli obs dispatcher + add a general
binary-precedence guard in the dispatcher loader (no dispatcher should shadow
an installed binary). Cross-refs obsidian-cli-ops dependency-bootstrapping spec
and the man-page refresh spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brainstorm pass found Option B's sketch keyed the binary-precedence guard
on the dispatcher *filename*, which equals the command name only for the
lone bare-named obs.zsh; every other file is X-dispatcher.zsh defining X.
The naive guard therefore protected only obs and left the general
shadowing hazard open for any future dispatcher.

Corrected to strip the -dispatcher suffix so the guard keys on the real
command name (genuinely general after Option A deletes obs.zsh). Added
convention test, stub-binary regression test, and symlink-deletion notes.
Includes the brainstorm artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
flow-cli drops obs.1 (doesn't own the binary); the man page moves to
obsidian-cli-ops, which owns /opt/homebrew/bin/obs and ships zero man
pages today. Records the cross-repo contract + the full v3.2.1 command
surface to document.

Audit finding: obs ai merge-suggest / tag-suggest / quality are handled
in the obs.zsh dispatch case but absent from obs help --all — a man page
built from help would inherit the gap. Authored-from-dispatch-table noted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…es 1+2) (#460)

* docs(orchestrate): plan for obs dispatcher shadowing fix

Phase 1 (Option A): delete dead obs dispatcher + symlink + obs.1 + obs
test + inventory refs (fully fixes the live shadowing bug).
Phase 2: general binary-precedence guard, elevated to a decision -
audit found B1 suffix-strip invariant already false (em<->email-dispatcher,
4 helper files), so B3 post-source self-check is recommended.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(obs): remove dead obs dispatcher so the real obs binary wins

The flow-cli obs() dispatcher shadowed /opt/homebrew/bin/obs
(obsidian-cli-ops) but required a python/obs_cli.py flow-cli never
ships, so typing `obs` always errored "Python CLI not found". A shell
function beats a PATH binary in lookup, so the broken dispatcher won in
every interactive shell. The zsh/functions/obs.zsh symlink (sourced
after the dispatcher loop) compounded this when obsidian-cli-ops was
present.

Phase 1 (Option A): delete the dispatcher and scrub every obs
reference, dropping flow-cli from 15 to 14 dispatchers.

- Delete lib/dispatchers/obs.zsh, zsh/functions/obs.zsh, man/man1/obs.1,
  and tests/test-obs-dispatcher.zsh.
- Scrub obs from inventories: flow.plugin.zsh, lib/help-compliance.zsh
  (15->14 + map), lib/help-browser.zsh, and
  commands/{flow,alias,tutorial,doctor}.zsh.
- Remove dangling SEE ALSO obs(1) refs and the flow.1 obs subcommand
  block (flow.1, g.1, mcp.1, qu.1, r.1); vendored scribe.1 left as-is.
- Update test suites for 14 dispatchers (help-compliance, dogfood,
  atlas-bridge, browser-preview, cli) and remove obs-specific blocks
  (legacy obs_help alias, _obs_help direct test, obs src-file case).

After: `type obs` -> /opt/homebrew/bin/obs (no obs() function). Affected
guards green; the man-page coverage guard now derives 14 dispatchers and
requires obs.1 gone.

Deferred: headline "15 dispatchers" docs and Phase 2 (general
binary-precedence guard, form TBD).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(dispatchers): guard against dispatchers shadowing PATH binaries

Phase 2 (Option B3) of the obs shadowing fix: a general binary-precedence
guard in the dispatcher loader so no future dispatcher can silently mask
an installed binary the way the broken obs() did.

After sourcing each lib/dispatchers/*.zsh, the loader diffs the function
table and unfunctions any newly-defined, non-`_` command whose name
resolves to an external PATH binary (whence -p) — UNLESS:
  - it is an intentional shadow: FLOW_INTENTIONAL_SHADOWS=(r mcp cc),
    overridable by pre-setting the array (cc launches Claude Code, not
    the C compiler; r/mcp are flow's dispatchers), or
  - it is forced: FLOW_FORCE_DISPATCHER_<NAME>=1.
The skip is logged under FLOW_DEBUG. Keying on the functions a file
actually defines means no filename convention is needed and `_`-helpers
are ignored automatically — unlike the spec's B1, whose filename->command
guess was already false (email-dispatcher.zsh defines `em`; several
helper files define no command at all).

Adds tests/test-dispatcher-binary-precedence.zsh (16 cases:
drop-on-collision, allowlist/force keep, helper preserved, real r/mcp/cc
survive a live load, obs is not a function) and registers it in
run-all.sh.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: drop obs from dispatcher inventories (15 -> 14)

Follow-up to the obs dispatcher removal (fix(obs)) and the binary-
precedence guard (feat(dispatchers)). Scrubs the now-removed obs
dispatcher from active documentation and repairs the mkdocs nav left
dangling after tutorials/41-obs-dispatcher.md was deleted.

- Dispatcher count "15" -> "14" across active docs: CLAUDE.md, README,
  MASTER-DISPATCHER-GUIDE/API-REFERENCE/ARCHITECTURE, reference/index,
  DOC-DASHBOARD, commands/at, REFCARD-TEACH/EMAIL, EMAIL-DISPATCHER-GUIDE,
  and 8 tutorial footers (35,37,38,39,40,42,43,44).
- Remove obs from inline dispatcher lists/tables/grammar examples in
  CLAUDE.md, MASTER-* guides, PHILOSOPHY, commands/{flow,alias,config},
  CONTRIBUTING, getting-started/{quick-start,00-welcome}, index,
  QUICK-REFERENCE, ENHANCED-HELP-QUICK-START.
- Remove the deleted obs tutorial's nav entry (mkdocs.yml) and its
  mermaid node + table row (docs/tutorials/index.md).

Historical records left frozen per convention: CHANGELOG(.md),
docs/CHANGELOG.md, RELEASES.md, docs/specs/*, and .archive/*.

Verified: mkdocs build --strict passes (exit 0); no dangling links to
41-obs-dispatcher; "obs" as a naming-convention example (CONVENTIONS,
PHILOSOPHY) and the separate zsh/ obs() smart-function are left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(status): log obs dispatcher shadowing fix (Phases 1+2 + docs)

Record the obs removal, the B3 binary-precedence guard, and the 15->14
docs sweep in the session log + Active Worktrees table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: remove ORCHESTRATE working artifact before PR

ORCHESTRATE-*.md is a feature-branch working artifact; it should not land
on dev (per CLAUDE.md merge-cleanup rule).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(obs): address PR #460 review — guard perf + doc scrub + env-var docs

- Guard: snapshot the function table once around the whole batch instead of
  per-file, and use the fork-free ${commands} hash instead of $(whence -p).
  Eliminates the ~10ms startup overhead (59ms -> ~46ms); test still 16/16.
- Docs: scrub stray 'obs' dispatcher refs missed by the sweep
  (getting-started/00-welcome 8->14 list, CONVENTIONS, PHILOSOPHY).
- CLAUDE.md: document FLOW_INTENTIONAL_SHADOWS + FLOW_FORCE_DISPATCHER_<NAME>
  with the empty-array override caveat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(obs): add FLOW_INTENTIONAL_SHADOWS empty-array regression cases

Enforces the documented footgun: an explicitly-emptied allowlist (set, not
unset — zsh ${+arr} is 1 for empty arrays) skips the (r mcp cc) default, so a
default-protected shadow like cc is dropped; unset keeps it. Both run in a
fresh `zsh -f` because the guard only acts on functions new to the source
pass — re-sourcing an already-loaded shell would be a no-op. 16 -> 18 cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ck (#459)

Check [34] grepped for the literal two-word strings `teach solution`,
`teach sync`, `teach validate-r`, but a03916b ("docs(claude): optimize —
move teach/dispatcher detail to pointers") condensed CLAUDE.md's teach docs
into a single subcommand list (`..., solution, sync, validate-r, ...`). The
subcommands are still documented, so the doc is correct and the assertion
was stale — failing 1/41 on dev independent of any feature work.

Accept either form via an alternation: `teach <sub>` OR `[(,] ?<sub>[,)]`.
The [(,]/[,)] boundaries keep it non-vacuous and stop it matching the
`--sync` deploy flag on the same line (verified: removing the `sync`
subcommand while keeping `--sync` still fails the check).

Fixes the test, not the doc — re-adding per-command lines would undo the
deliberate CLAUDE.md optimization.

Co-authored-by: Test User <test@example.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
obs dispatcher removed + binary-precedence guard (15→14 dispatchers).
- flow.plugin.zsh FLOW_VERSION, package.json, CLAUDE.md, man-page .TH set
- CHANGELOG (root + docs mirror): 7.9.0 entry
- docs/index.md What's-New + footer, ~47 doc-footer version stamps
@Data-Wise Data-Wise merged commit 981fe1a into main Jun 5, 2026
2 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