Skip to content

knowledge-system v1.4.0: /backfill-knowledge + origin metadata - #2

Merged
gering merged 5 commits into
mainfrom
feat/knowledge-system-backfill
Apr 18, 2026
Merged

knowledge-system v1.4.0: /backfill-knowledge + origin metadata#2
gering merged 5 commits into
mainfrom
feat/knowledge-system-backfill

Conversation

@gering

@gering gering commented Apr 18, 2026

Copy link
Copy Markdown
Owner

Summary

Minor bump of knowledge-system (v1.3.0 → v1.4.0). Backwards-compatible — existing knowledge files without the new origin metadata remain valid and are backfilled on the next /reindex run.

Highlights

  • New skill /backfill-knowledge — retroactively mines merged PR history for significant learnings that are missing from the knowledge base. Strict quality bar: only new user-facing features, architecture changes, and major insights qualify. Small bug fixes, refactors, test additions, dependency bumps, and style/chore PRs are explicitly excluded even if informative. A Sonnet background agent reads each PR (title, body, commit messages, full diff) and judges significance. Survivors return in a single batch report with one-line learning summaries and target-file recommendations. User approves by number range (1,3,5, all, 1-4) and then /curate runs on each approved candidate. Flags: --last N, --pr N, --since YYYY-MM-DD, --dry-run.
  • Origin metadata — frontmatter gains two fields:
    • createdFrom: "PR #42" (or "branch: feature/xyz", or "session: YYYY-MM-DD")
    • updatedFrom: "<origin>"
      Extensible string format with a source prefix so future origin types can be added without a schema change.
  • /curate — detects current origin (branch → PR lookup → session fallback) and stamps createdFrom on new files / updatedFrom on every edit. Gains a --origin "<value>" flag for programmatic callers like /backfill-knowledge (humans rarely need it).
  • /reindex — backfills createdFrom / updatedFrom via a cascade: gh pr list --search <sha> (robust across merge, squash, and rebase-merge modes), then squash-commit (#N) suffix, then classic merge-commit subject parsing, then branch fallback. Verified empirically against this repo (which uses rebase/FF merge and has no merge commits) — the gh lookup is the only reliable path in that mode. /reindex also upgrades stale "branch: <name>" values to "PR #<N>" once the branch is merged.
  • Idempotency for /backfill-knowledge — before dispatching, scans createdFrom / updatedFrom frontmatter lines (not prose body) for PR numbers already represented, plus the persistent log at .claude/logs/backfill-knowledge.md (including a user-driven never-bucket).
  • /init auto-prime rule — updated to mention /backfill-knowledge so Claude suggests it at the right moments in new sessions.

Commits

  • 45823e7 Add createdFrom/updatedFrom origin metadata to knowledge schema
  • 27111f7 Add /backfill-knowledge skill and --origin override for /curate
  • 00c0408 Bump knowledge-system to v1.4.0 and list /backfill-knowledge

Test plan

  • /curate "<test insight>" on a feature branch: verify createdFrom / updatedFrom are written as "branch: <branch-name>" when no PR exists
  • /curate "<test insight>" on a branch with an open PR: verify both fields become "PR #<N>"
  • /curate "<update>" to an existing file: verify createdFrom unchanged, updatedFrom updated to current origin
  • /curate "<insight>" --origin "PR #99": verify the override wins over auto-detection
  • /reindex on an existing knowledge base: verify createdFrom / updatedFrom get backfilled via gh pr list --search and no PR numbers leak from prose mentions
  • /backfill-knowledge --dry-run --last 5: verify report is produced, no files written, no log entry
  • /backfill-knowledge --pr 42 on a PR already referenced in a knowledge file's createdFrom: verify it is detected as already-curated and the user is prompted before re-processing
  • /backfill-knowledge --last 20: verify the batch approval flow, the never-bucket persistence across runs, and that curated files carry createdFrom: "PR #N" with the correct number

🤖 Generated with Claude Code

gering and others added 5 commits April 18, 2026 12:46
Extends the frontmatter with two string fields that record where an
entry originated and where its last edit came from. Values use a source
prefix so additional origin types can be added without a schema change:

- "PR #42"              — preferred form when a merged PR exists
- "branch: feature/xyz" — on a branch without a PR yet; /reindex
                           upgrades to "PR #N" once merged
- "session: 2026-04-18" — direct edit on main or outside a branch
                           workflow

/curate now resolves the current origin once at skill start and writes
createdFrom on new files, updatedFrom on every edit. /reindex backfills
both from git by parsing merge-commit subjects (both `Merge pull request
#N` and squash `(#N)` forms) with a clean "leave empty if ambiguous"
fallback — no guessing. /reindex also upgrades stale "branch:" values to
"PR #N" once the branch has landed.

README updates: schema + field semantics tables, extended
git-aware-metadata feature section, and a new section describing the
retroactive workflow (run /reindex first to seed metadata, then
/backfill-knowledge).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New /backfill-knowledge skill mines merged PR history for significant
learnings missing from the knowledge base. Strict quality bar:
only new user-facing features, architecture changes, and major insights
qualify — small bug fixes, refactors, dependency bumps, test-only PRs,
style/chore cleanups are explicitly rejected even if informative.

Flow: a Sonnet background agent reads each PR (title, body, commit
messages, full diff), judges against the bar, and returns a JSON
report with `accepted`, `rejected`, and `errors` buckets. The skill
presents a batch-approval prompt (single selection, not ten
interruptions) so the user picks by number range. Each approved
candidate is curated via /curate with the PR number stamped into
createdFrom/updatedFrom via a new --origin flag.

Idempotency: skips PRs already represented in knowledge (grep for `PR
#N` across .claude/knowledge/) and PRs already handled in prior
backfill runs (parse .claude/logs/backfill-knowledge.md). Supports
a persistent "never re-propose" bucket driven by user selection.

Flags:
- /backfill-knowledge            — all unprocessed merged PRs on main
- /backfill-knowledge --last N   — last N merged PRs
- /backfill-knowledge --pr N     — single PR
- /backfill-knowledge --since D  — merged since date
- /backfill-knowledge --dry-run  — preview, no writes

/curate gains a --origin "<value>" flag (human usage unchanged; the
flag is reserved for programmatic callers like /backfill-knowledge to
override the auto-detected current-branch origin).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Minor bump: adds /backfill-knowledge skill for retroactive curation
from PR history, extends frontmatter with createdFrom/updatedFrom
origin metadata, and adds a --origin flag to /curate. Backwards
compatible — existing knowledge files without origin metadata remain
valid and are backfilled by /reindex on the next QA run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- /backfill-knowledge step 2: explicit flag precedence (--pr wins over
  --last/--since; --last and --since are mutually exclusive; --dry-run
  combines freely).
- /backfill-knowledge step 3: idempotency parse now includes "Skipped —
  not significant" — without it every run re-judges every rejected PR
  and generates the same noise. Grep anchor tightened so pathological
  values like `createdFrom: "session: ... see PR #99"` cannot leak into
  the processed set.
- /backfill-knowledge step 4: document that the agent never writes and
  therefore does not receive --dry-run; the flag only gates steps 7+8
  in the outer skill. Dispatch text no longer implies contiguous PR
  range.
- /backfill-knowledge step 6: supported approval inputs are now
  disjoint; combined forms like `1,3 never 2,4` are explicitly
  unsupported (user runs twice). Empty/`n` still writes a log entry so
  already-judged PRs are not re-judged next time.
- /backfill-knowledge step 7: show exact /curate shell-argument shape
  (including reference-files placement) so the invocation is
  unambiguous.
- /backfill-knowledge report format: surface the reference_files per
  candidate so the user can see what gets attached to each knowledge
  entry before approving.
- /backfill-knowledge agent input #3: fix broken `gh pr diff
  --name-only` (that flag does not exist); use `gh pr view --json
  files` for the file list instead.
- /curate step 1: unambiguous --origin placement rule with concrete
  examples covering flag-before-files, flag-after-files, and no-flag
  invocations.
- /curate frontmatter-less backfill: remove duplicated cascade
  description; point to /reindex SKILL.md step B as the canonical
  source so the logic cannot drift across two skills.
- /reindex cascade: annotate that step 1 (`gh pr list --search`) covers
  virtually all online cases and steps 2–4 are fallbacks. Upgrade-path
  clarified: re-run the cascade with the same SHAs used for the
  initial lookup, not `git log <branch-name>`.
- README: bump v1.3.0 → v1.4.0 in the log and reindex-report examples.
  Reword the `session:` origin description — it is always written on
  main, not "rare".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- /backfill-knowledge Step 6: mixed list+range approval forms
  (1-3,7 / 1,4-6,9) now explicitly accepted and documented for both
  `approve` and `never` shapes. Parser expands ranges and unions with
  individual numbers.
- /backfill-knowledge Step 3: two-stage grep pipeline. Stage 1 uses
  `-o` to restrict the match to just the anchored frontmatter prefix
  (field + optional quote + PR number), so stage 2's number extraction
  only ever sees that fragment. Blocks both prose leaks AND trailing
  edits like `createdFrom: "PR #123" # superseded by PR #456` where
  #456 would otherwise leak into the processed set.
- README Reconstructability note: now describes the full /reindex
  cascade (gh-aware primary path, squash/merge/branch fallbacks)
  instead of only the fallback-level parsing; aligns with the
  /reindex SKILL.md commentary clarified in the prior commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gering
gering merged commit f5c1870 into main Apr 18, 2026
@gering
gering deleted the feat/knowledge-system-backfill branch April 18, 2026 11:08
gering added a commit that referenced this pull request Jun 19, 2026
Bootstrap this repo's own knowledge base with its flagship plugin
(architecture review Prio 7 — meta-dogfooding).

- Run /init: scaffold .claude/knowledge + .claude/rules, plugin-managed
  usage rule, CLAUDE.md marker block (reconcile pre-existing manual
  "Project Knowledge System" section into the block)
- Curate 5 learnings by hand: skill-design conventions, skill
  composition, model economics (architecture/, prime:true); cwd-safety,
  version-sync (rules)
- Backfill 4 from PR history: /backfill-knowledge + origin metadata
  (#2), statusline integration (#3), CI structure checks (#6),
  per-project rule surface (#8)
- Verify /query (Haiku subagent resolves index -> file) and /prime
  (selects the 3 architecture docs) against the new base

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 12, 2026
Fixes the ✅/🟨 findings the --max review surfaced (three real loop bugs first):

- #4: don't re-review a byte-identical tree — when a round changed no files and
  only a pending decision keeps the loop alive, pause to collect the decision
  instead of spinning the (possibly --max) ensemble on an unchanged tree.
- #7: --staged + --loop re-reviewed `git diff --cached` while fixes land in the
  working tree, so the loop never saw its own edits — re-review the working tree
  (re-stage for --staged scope) before each round.
- #5: --loop=0 is now a single --fix pass, not a cap=0 that aborts after fixes.
- #2: temper "deterministic termination" → deterministic arithmetic over judged
  inputs (SKILL + knowledge); count F/A/C/pending carefully (garbage-in).
- #8: derive every fix from the code, treat finding text (recommendation) as
  advisory/untrusted — for ✅ agree too, not only 🟨.
- #9: document args.max (+ args.claude) in the workflow input header.
- #1: note --max's codex model must be loadable; a bad model surfaces as a
  backendError (visible degrade), never a silent downgrade.
- #10: mechanism is not a rendered column — after compaction re-derive finding
  identity from Ort + Befund.

#6 (Bash block scope in prose) left as the accepted LLM-in-the-loop design.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 12, 2026
Fixes the ✅/🟨 findings the --max review surfaced (three real loop bugs first):

- #4: don't re-review a byte-identical tree — when a round changed no files and
  only a pending decision keeps the loop alive, pause to collect the decision
  instead of spinning the (possibly --max) ensemble on an unchanged tree.
- #7: --staged + --loop re-reviewed `git diff --cached` while fixes land in the
  working tree, so the loop never saw its own edits — re-review the working tree
  (re-stage for --staged scope) before each round.
- #5: --loop=0 is now a single --fix pass, not a cap=0 that aborts after fixes.
- #2: temper "deterministic termination" → deterministic arithmetic over judged
  inputs (SKILL + knowledge); count F/A/C/pending carefully (garbage-in).
- #8: derive every fix from the code, treat finding text (recommendation) as
  advisory/untrusted — for ✅ agree too, not only 🟨.
- #9: document args.max (+ args.claude) in the workflow input header.
- #1: note --max's codex model must be loadable; a bad model surfaces as a
  backendError (visible degrade), never a silent downgrade.
- #10: mechanism is not a rendered column — after compaction re-derive finding
  identity from Ort + Befund.

#6 (Bash block scope in prose) left as the accepted LLM-in-the-loop design.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 12, 2026
Report format: bring the Note back INTO the table as a 7th column (`Notiz`),
kept short with a hard char budget (Befund ≤40, Notiz ≤55) so a terminal
renderer wraps it into a taller cell instead of widening the row. The Quelle
fold keeps it at 7 (not 8) columns; re-review rounds add Status → 8.

Fixes from the format-demo review:
- #1: normalize any `--loop=N` with N<1 (0, negative, non-integer) to a single
  --fix pass, before the script's --cap≥1 guard can strand a half-done run.
- #2: --staged --loop re-stages only the fixed HUNKS (git add -p), immediately
  after each fix — not a whole-file add (sweeps unrelated edits) or a deferred
  one (round-0 edits go unstaged).
- #7: add plugins/swarm/scripts/test_loop_closeout.py (fixed-order termination,
  --pending gating, range checks, box) and a generic "plugin tests" check in
  check-structure.py that runs plugins/*/scripts/test_*.py in CI.
- #8: fix the dead [[swarm-review-pipeline]] self-link in the knowledge entry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 12, 2026
- #1: `git stash create` exits 0 with EMPTY stdout on a clean tree, so the
  `|| git rev-parse HEAD` fallback never fired and SNAP was empty → `git diff
  --name-only ""` errored and C=0 false-terminated the loop. Split into
  `SNAP=$(git stash create); [ -n "$SNAP" ] || SNAP=$(git rev-parse HEAD)`.
- #2: `git diff` never lists untracked files, so a fix that CREATES a file
  counted as 0 changes → bogus no-change. Add the untracked before/after set
  diff to C. Verified across clean / modified / new-file / dirty-before cases.
- #3: document check_plugin_tests's arbitrary-code-execution surface — safe
  only because CI withholds secrets/write-token from fork PRs (GitHub default,
  confirmed: structure-checks.yml declares no secrets/permissions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 12, 2026
- #2: check_plugin_tests now passes stdin=DEVNULL + timeout=120 to subprocess
  and treats a timeout as a failure, so a hanging/stdin-blocking test can't
  wedge the structure check (and CI) indefinitely.
- #5: the loop's C= snippet counted new untracked files with `grep -c .`, which
  exits 1 on zero matches and aborts the arithmetic under `set -euo pipefail`
  (the review block's shell). Use `wc -l` (exit 0), symmetric with the first
  term. Verified under strict shell across clean/modified/new-file cases.
- #7: knowledge/ci-structure-checks.md now documents the fifth check (plugin
  tests) the last commit added.

Left as accepted residuals: #1 (C misses edits to pre-existing untracked files
— rare, documented), #3 (CI arbitrary-code surface — safe under GH fork-PR
defaults), #4/#6 (LLM-in-the-loop scope + in-session loop state, by design).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gering added a commit that referenced this pull request Jul 16, 2026
First dogfooding run: /swarm:review --fix over its own diff (4 cluster
finders + codex + grok-4.5 + composer; 13 findings, 5 cross-family
consensus). Fixes the agreed findings:

- Keep validly tagged off-cluster lens prefixes: validate against the
  global lens set, not the finder's subset — coercion could flip kind
  and route a real defect through the applicability verifier (#1, consensus critical)
- Verify design clusters even with cross-family consensus: agreement
  attests agreement, not repo-grounded applicability (externals cannot
  open repo files); defect consensus stays auto-accepted (#2)
- Untagged external findings ('unspecified' lens) no longer vote in the
  cluster-kind derivation (#3)
- Derive CANDIDATE_LENSES from LENS_CLUSTERS — one list, no unchecked
  mirror; DRIFT WARNING on the SKILL.md external-prompt copy (#4, #9)
- Finder prompt: "issue (defect or substantive improvement)" + all lens
  prefixes; external prompt lead covers design improvements too (#5, #6)
- pr-post.py owns design-row ordering + [lens] prefixing via optional
  kind/lens row fields, unit-tested; SKILL.md step 5 passes rows through
  verbatim (#13)
- Doc sync: balance-spec finder count, README canonical cluster names +
  preset teaser wording, knowledge-index line trimmed (#8, #10, #11, #12)

Declined: #7 (per-cluster dilutes per-lens depth) — deliberate,
documented cost/coverage trade-off; --max is the depth profile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 16, 2026
Second dogfooding round at the deepest profile (/swarm:review --max --fix:
per-lens split live — gate pruned style, 10 xhigh finders + codex
gpt-5.6-sol@xhigh + grok-4.5 + composer; 24 findings, 10 consensus).
Fixes the agreed findings:

- Never auto-accept an all-untagged consensus cluster: no tagged lens
  backs it, so it is verified like a solo. Verify/auto-accept now derive
  from ONE needsVerify predicate (structural exactly-once partition);
  kind vote in clearer every-form (#1, consensus critical; #21, #22)
- Design verifier sees the finding's recommendation — the proposal the
  applicability rubric actually tests — and carries an escape hatch:
  a genuine defect mis-filed under a design lens is not refuted away
  (#12, #3); "solo" dropped from verifier prompts (#4)
- Untagged findings from multi-lens cluster finders fall back to
  'unspecified' (safe defect bucket), not lenses[0] (#7); merge-agent
  free-text lens validated, majority-member fallback (#9)
- Improvement invitation scoped to design finder units — defect-lens
  finders stay defect-only (#8); merge prompt clusters by issue, not
  only defect (#13); schema descriptions generalized for design
  findings (#14)
- LENS_BRIEF startup assertion (#6); gate prompt interpolates
  LENS_CLUSTERS.design (#19); new test_lens_sync.py guards all lens
  mirrors: SKILL HDR prompt, LENS_BRIEF, pr-post DESIGN_LENSES (#5)
- Workflow assigns stable finding num (defects first, shared sequence);
  presenter/pr-post render it verbatim (#20)
- pr-post.py: design lens is the backup kind signal when the handoff
  drops kind (explicit defect still wins); single-pass partition (#17, #24)
- Balance: REFUTED is its own segment (refuted ⊄ solo since design
  consensus can be refuted) (#2); LOCKED design-table column precedence
  in --loop rounds clarified (#11); "verifies solos" doc sweep across
  manifests/README/knowledge (#4); cluster failure-isolation trade-off
  documented (#10); knowledge index line trimmed (#15)

Declined: #16 (JS test harness for sandbox code; lens-sync test covers
the drift class), #18 (gate-fail under --max runs all lenses — the
documented never-silently-narrower degrade), #23 (micro-opt vs readability).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 17, 2026
Address the agreed findings from the local swarm review:

- agent-registry grok probe: add a `gtimeout` fallback so `grok models` is
  time-bounded on stock macOS (only gtimeout ships there), not just where GNU
  `timeout` exists (#1).
- grok availability: a failed/unreachable `grok models` fetch is now inconclusive
  (trust auth, soft note) rather than "unavailable" — a network hiccup no longer
  wrongly blocks launch. Fetch status rides the function's exit code, since a
  command-substitution subshell can't carry a global flag back (#6).
- agent-registry resolve: reject control chars in `--session`, closing the
  newline→forged-`argv=`-line injection through the launch protocol (#2).
- kickoff SKILL manual (non-herdr) block: shell-quote each argv word (the
  codex/grok bootstrap prompt is one word with spaces) instead of space-joining
  (#3); and persist a picker "save as default" on the manual path too, not only
  the herdr path (#4).
- plugin.json: refresh the stale description (dropped the wrong lifecycle verbs,
  mention worker-agent choice) (#8).

Not changed (reviewed, disagreed): /continue's claude-only resume is a
documented degradation; README model-id duplication is accepted human-facing
docs; the CHANGELOG paragraph matches the repo's entry style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- default get now VALIDATES the committed value against the registry: a stale/
  removed/attacker-supplied name (from a cloned repo) reads as "no default" →
  picker, instead of routing or bricking every no-flag kickoff (#1). kickoff also
  announces a non-claude project default before launch — visibility, not a prompt,
  so a committed default can't silently route your code off-Claude (#1 security).
- grok probe: when neither `timeout` nor `gtimeout` exists, skip `grok models`
  and return inconclusive (trust auth) rather than risk an unbounded call that
  hangs the picker (#2).
- kickoff argument grammar: `--agent` consumes the next token as its value, so it
  isn't mistaken for the task name (#4).
- agent-registry.sh committed executable (100755), matching herdr-launch.sh, so
  the documented direct invocation works (#5).
- kickoff "Critical" note: step 12 → step 13 cross-ref (launch was renumbered) (#6).
- `supports=` comment marked RESERVED/not-yet-consumed (a seed for the
  orchestration design), not "already driving" degradation (#7).
- herdr-launch bad-mode usage string shows the launch arity incl.
  [agent-selector] (#8).
- continue reopen: note reworded to match behavior (`claude -c` IS always sent)
  and the codex/grok caveat surfaced inline in the success report (#3).

Not changed (reviewed): README model-id duplication (accepted human-facing docs),
CHANGELOG paragraph (matches repo style); per-task worker persistence for a true
per-CLI resume stays a later idea.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
First dogfooding run: /swarm:review --fix over its own diff (4 cluster
finders + codex + grok-4.5 + composer; 13 findings, 5 cross-family
consensus). Fixes the agreed findings:

- Keep validly tagged off-cluster lens prefixes: validate against the
  global lens set, not the finder's subset — coercion could flip kind
  and route a real defect through the applicability verifier (#1, consensus critical)
- Verify design clusters even with cross-family consensus: agreement
  attests agreement, not repo-grounded applicability (externals cannot
  open repo files); defect consensus stays auto-accepted (#2)
- Untagged external findings ('unspecified' lens) no longer vote in the
  cluster-kind derivation (#3)
- Derive CANDIDATE_LENSES from LENS_CLUSTERS — one list, no unchecked
  mirror; DRIFT WARNING on the SKILL.md external-prompt copy (#4, #9)
- Finder prompt: "issue (defect or substantive improvement)" + all lens
  prefixes; external prompt lead covers design improvements too (#5, #6)
- pr-post.py owns design-row ordering + [lens] prefixing via optional
  kind/lens row fields, unit-tested; SKILL.md step 5 passes rows through
  verbatim (#13)
- Doc sync: balance-spec finder count, README canonical cluster names +
  preset teaser wording, knowledge-index line trimmed (#8, #10, #11, #12)

Declined: #7 (per-cluster dilutes per-lens depth) — deliberate,
documented cost/coverage trade-off; --max is the depth profile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 17, 2026
Second dogfooding round at the deepest profile (/swarm:review --max --fix:
per-lens split live — gate pruned style, 10 xhigh finders + codex
gpt-5.6-sol@xhigh + grok-4.5 + composer; 24 findings, 10 consensus).
Fixes the agreed findings:

- Never auto-accept an all-untagged consensus cluster: no tagged lens
  backs it, so it is verified like a solo. Verify/auto-accept now derive
  from ONE needsVerify predicate (structural exactly-once partition);
  kind vote in clearer every-form (#1, consensus critical; #21, #22)
- Design verifier sees the finding's recommendation — the proposal the
  applicability rubric actually tests — and carries an escape hatch:
  a genuine defect mis-filed under a design lens is not refuted away
  (#12, #3); "solo" dropped from verifier prompts (#4)
- Untagged findings from multi-lens cluster finders fall back to
  'unspecified' (safe defect bucket), not lenses[0] (#7); merge-agent
  free-text lens validated, majority-member fallback (#9)
- Improvement invitation scoped to design finder units — defect-lens
  finders stay defect-only (#8); merge prompt clusters by issue, not
  only defect (#13); schema descriptions generalized for design
  findings (#14)
- LENS_BRIEF startup assertion (#6); gate prompt interpolates
  LENS_CLUSTERS.design (#19); new test_lens_sync.py guards all lens
  mirrors: SKILL HDR prompt, LENS_BRIEF, pr-post DESIGN_LENSES (#5)
- Workflow assigns stable finding num (defects first, shared sequence);
  presenter/pr-post render it verbatim (#20)
- pr-post.py: design lens is the backup kind signal when the handoff
  drops kind (explicit defect still wins); single-pass partition (#17, #24)
- Balance: REFUTED is its own segment (refuted ⊄ solo since design
  consensus can be refuted) (#2); LOCKED design-table column precedence
  in --loop rounds clarified (#11); "verifies solos" doc sweep across
  manifests/README/knowledge (#4); cluster failure-isolation trade-off
  documented (#10); knowledge index line trimmed (#15)

Declined: #16 (JS test harness for sandbox code; lens-sync test covers
the drift class), #18 (gate-fail under --max runs all lenses — the
documented never-silently-narrower degrade), #23 (micro-opt vs readability).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 17, 2026
- grok probe now always runs BOUNDED: when neither `timeout` nor `gtimeout`
  exists, self-bound with a background killer (fds detached so the command
  substitution doesn't block on it) instead of skipping the check — so a dropped
  model is still caught on hosts without a timeout binary, and the probe still
  can't hang the picker (#1).
- a successful `grok models` that parses to nothing (a reformatted listing that
  dropped the `*` bullet) is treated as inconclusive → availability assumed,
  rather than marking every grok entry unavailable and disabling the backend (#3).
- herdr-launch surfaces resolve's real stderr on exit 2 instead of labelling
  every cause "unknown agent selector" (#5).
- README: `/continue` reopen wording corrected — it always sends `claude -c` and
  the user resumes a codex/grok worker themselves; no automatic per-CLI resume is
  claimed (#2, doc half; per-task persistence stays a later idea).
- marketplace.json work-system description refreshed to match plugin.json (#6).

Not changed: committed-external-default consent gate (#4) — an explicit product
decision to announce, not prompt (a cloned repo can already run hooks/CLAUDE.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
Address the agreed findings from the local swarm review:

- agent-registry grok probe: add a `gtimeout` fallback so `grok models` is
  time-bounded on stock macOS (only gtimeout ships there), not just where GNU
  `timeout` exists (#1).
- grok availability: a failed/unreachable `grok models` fetch is now inconclusive
  (trust auth, soft note) rather than "unavailable" — a network hiccup no longer
  wrongly blocks launch. Fetch status rides the function's exit code, since a
  command-substitution subshell can't carry a global flag back (#6).
- agent-registry resolve: reject control chars in `--session`, closing the
  newline→forged-`argv=`-line injection through the launch protocol (#2).
- kickoff SKILL manual (non-herdr) block: shell-quote each argv word (the
  codex/grok bootstrap prompt is one word with spaces) instead of space-joining
  (#3); and persist a picker "save as default" on the manual path too, not only
  the herdr path (#4).
- plugin.json: refresh the stale description (dropped the wrong lifecycle verbs,
  mention worker-agent choice) (#8).

Not changed (reviewed, disagreed): /continue's claude-only resume is a
documented degradation; README model-id duplication is accepted human-facing
docs; the CHANGELOG paragraph matches the repo's entry style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- default get now VALIDATES the committed value against the registry: a stale/
  removed/attacker-supplied name (from a cloned repo) reads as "no default" →
  picker, instead of routing or bricking every no-flag kickoff (#1). kickoff also
  announces a non-claude project default before launch — visibility, not a prompt,
  so a committed default can't silently route your code off-Claude (#1 security).
- grok probe: when neither `timeout` nor `gtimeout` exists, skip `grok models`
  and return inconclusive (trust auth) rather than risk an unbounded call that
  hangs the picker (#2).
- kickoff argument grammar: `--agent` consumes the next token as its value, so it
  isn't mistaken for the task name (#4).
- agent-registry.sh committed executable (100755), matching herdr-launch.sh, so
  the documented direct invocation works (#5).
- kickoff "Critical" note: step 12 → step 13 cross-ref (launch was renumbered) (#6).
- `supports=` comment marked RESERVED/not-yet-consumed (a seed for the
  orchestration design), not "already driving" degradation (#7).
- herdr-launch bad-mode usage string shows the launch arity incl.
  [agent-selector] (#8).
- continue reopen: note reworded to match behavior (`claude -c` IS always sent)
  and the codex/grok caveat surfaced inline in the success report (#3).

Not changed (reviewed): README model-id duplication (accepted human-facing docs),
CHANGELOG paragraph (matches repo style); per-task worker persistence for a true
per-CLI resume stays a later idea.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- grok probe now always runs BOUNDED: when neither `timeout` nor `gtimeout`
  exists, self-bound with a background killer (fds detached so the command
  substitution doesn't block on it) instead of skipping the check — so a dropped
  model is still caught on hosts without a timeout binary, and the probe still
  can't hang the picker (#1).
- a successful `grok models` that parses to nothing (a reformatted listing that
  dropped the `*` bullet) is treated as inconclusive → availability assumed,
  rather than marking every grok entry unavailable and disabling the backend (#3).
- herdr-launch surfaces resolve's real stderr on exit 2 instead of labelling
  every cause "unknown agent selector" (#5).
- README: `/continue` reopen wording corrected — it always sends `claude -c` and
  the user resumes a codex/grok worker themselves; no automatic per-CLI resume is
  claimed (#2, doc half; per-task persistence stays a later idea).
- marketplace.json work-system description refreshed to match plugin.json (#6).

Not changed: committed-external-default consent gate (#4) — an explicit product
decision to announce, not prompt (a cloned repo can already run hooks/CLAUDE.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
First dogfooding run: /swarm:review --fix over its own diff (4 cluster
finders + codex + grok-4.5 + composer; 13 findings, 5 cross-family
consensus). Fixes the agreed findings:

- Keep validly tagged off-cluster lens prefixes: validate against the
  global lens set, not the finder's subset — coercion could flip kind
  and route a real defect through the applicability verifier (#1, consensus critical)
- Verify design clusters even with cross-family consensus: agreement
  attests agreement, not repo-grounded applicability (externals cannot
  open repo files); defect consensus stays auto-accepted (#2)
- Untagged external findings ('unspecified' lens) no longer vote in the
  cluster-kind derivation (#3)
- Derive CANDIDATE_LENSES from LENS_CLUSTERS — one list, no unchecked
  mirror; DRIFT WARNING on the SKILL.md external-prompt copy (#4, #9)
- Finder prompt: "issue (defect or substantive improvement)" + all lens
  prefixes; external prompt lead covers design improvements too (#5, #6)
- pr-post.py owns design-row ordering + [lens] prefixing via optional
  kind/lens row fields, unit-tested; SKILL.md step 5 passes rows through
  verbatim (#13)
- Doc sync: balance-spec finder count, README canonical cluster names +
  preset teaser wording, knowledge-index line trimmed (#8, #10, #11, #12)

Declined: #7 (per-cluster dilutes per-lens depth) — deliberate,
documented cost/coverage trade-off; --max is the depth profile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 17, 2026
Second dogfooding round at the deepest profile (/swarm:review --max --fix:
per-lens split live — gate pruned style, 10 xhigh finders + codex
gpt-5.6-sol@xhigh + grok-4.5 + composer; 24 findings, 10 consensus).
Fixes the agreed findings:

- Never auto-accept an all-untagged consensus cluster: no tagged lens
  backs it, so it is verified like a solo. Verify/auto-accept now derive
  from ONE needsVerify predicate (structural exactly-once partition);
  kind vote in clearer every-form (#1, consensus critical; #21, #22)
- Design verifier sees the finding's recommendation — the proposal the
  applicability rubric actually tests — and carries an escape hatch:
  a genuine defect mis-filed under a design lens is not refuted away
  (#12, #3); "solo" dropped from verifier prompts (#4)
- Untagged findings from multi-lens cluster finders fall back to
  'unspecified' (safe defect bucket), not lenses[0] (#7); merge-agent
  free-text lens validated, majority-member fallback (#9)
- Improvement invitation scoped to design finder units — defect-lens
  finders stay defect-only (#8); merge prompt clusters by issue, not
  only defect (#13); schema descriptions generalized for design
  findings (#14)
- LENS_BRIEF startup assertion (#6); gate prompt interpolates
  LENS_CLUSTERS.design (#19); new test_lens_sync.py guards all lens
  mirrors: SKILL HDR prompt, LENS_BRIEF, pr-post DESIGN_LENSES (#5)
- Workflow assigns stable finding num (defects first, shared sequence);
  presenter/pr-post render it verbatim (#20)
- pr-post.py: design lens is the backup kind signal when the handoff
  drops kind (explicit defect still wins); single-pass partition (#17, #24)
- Balance: REFUTED is its own segment (refuted ⊄ solo since design
  consensus can be refuted) (#2); LOCKED design-table column precedence
  in --loop rounds clarified (#11); "verifies solos" doc sweep across
  manifests/README/knowledge (#4); cluster failure-isolation trade-off
  documented (#10); knowledge index line trimmed (#15)

Declined: #16 (JS test harness for sandbox code; lens-sync test covers
the drift class), #18 (gate-fail under --max runs all lenses — the
documented never-silently-narrower degrade), #23 (micro-opt vs readability).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126cGxsBYxqgEFH4AcpriNk
gering added a commit that referenced this pull request Jul 17, 2026
- Bound EVERY external-CLI probe: factor out run_bounded (timeout/gtimeout, else
  a self-watchdog that escalates SIGTERM -> SIGKILL) and use it for codex
  `login status` (was completely unbounded) and grok `models`. Its stdout goes to
  a temp file so an orphaned grandchild can't hold the command-substitution pipe
  open — verified a SIGTERM-ignoring probe is now killed at ~12s, not left to hang
  the picker (#4).
- kickoff manual (non-herdr) block no longer auto-persists the project default:
  it only prints a command, so no launch is confirmed — tell the user to run
  `default set` once the worker is up, matching the herdr path's "persist only
  after a successful launch" rule (#2).
- kickoff picker: set OFFER_DEFAULT from the interpreted Yes/No answer, not a
  literal label match, so the save-as-default gate can't miss on case (#3).
- knowledge: add the missing `prime:` key to the new entry (#6); refresh the
  stale herdr-kickoff-automation entry (step 13, registry-resolved worker argv,
  not a hardcoded `claude … /continue`) (#7).

Not changed: the committed-external-default consent gate (#1) stays announce-not-
prompt (a settled product decision); herdr-launch's `${0%/*}` sibling lookup (#5)
is latent and matches the file's existing convention (callers always pass an
absolute path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
Mostly real regressions from the round-4 batch, caught by the re-review:

- run_bounded: add `-k 1` to the timeout/gtimeout branches. GNU timeout only
  SIGTERMs at the deadline then waits, so a SIGTERM-ignoring probe ran forever on
  the COMMON path (any host with a timeout binary — e.g. all Linux CI); --kill-after
  escalates to SIGKILL like the self-watchdog. Normalize a bounded kill to a single
  124 "timed out" code (#4).
- codex probe: a run_bounded timeout (124) is now inconclusive -> assume available
  (mirrors grok), not a genuine auth failure — a slow `codex login status` no longer
  tells a logged-in user to re-login and disables the backend (#5).
- grok probe: match the model id as a SUBSTRING of the raw `grok models` output
  (here-string, no pipe) instead of a positional awk field + exact-line grep, so a
  reformatted listing can't yield a wrong token and a false "model not offered" (#6).
- project default resolves the MAIN repo root via --git-common-dir, so a
  `default set` run from inside a linked worktree lands in the main checkout, not
  the disposable worktree copy (#3).
- kickoff manual path: the main-repo session runs `default set` after the user
  confirms the worker started — not a command for the user's terminal, where $REG
  is undefined and the cwd is the worktree (#2).
- knowledge: correct the herdr-kickoff entry's grok argv (`grok -m …`, not codex) (#7).

Not changed: committed-external-default consent gate (#1) — settled announce-not-
prompt product decision.

Verified: gtimeout -k bounds a SIGTERM-ignoring probe at ~11s; a hung codex probe
reads available; `default set` from the worktree writes the main repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
Address the agreed findings from the local swarm review:

- agent-registry grok probe: add a `gtimeout` fallback so `grok models` is
  time-bounded on stock macOS (only gtimeout ships there), not just where GNU
  `timeout` exists (#1).
- grok availability: a failed/unreachable `grok models` fetch is now inconclusive
  (trust auth, soft note) rather than "unavailable" — a network hiccup no longer
  wrongly blocks launch. Fetch status rides the function's exit code, since a
  command-substitution subshell can't carry a global flag back (#6).
- agent-registry resolve: reject control chars in `--session`, closing the
  newline→forged-`argv=`-line injection through the launch protocol (#2).
- kickoff SKILL manual (non-herdr) block: shell-quote each argv word (the
  codex/grok bootstrap prompt is one word with spaces) instead of space-joining
  (#3); and persist a picker "save as default" on the manual path too, not only
  the herdr path (#4).
- plugin.json: refresh the stale description (dropped the wrong lifecycle verbs,
  mention worker-agent choice) (#8).

Not changed (reviewed, disagreed): /continue's claude-only resume is a
documented degradation; README model-id duplication is accepted human-facing
docs; the CHANGELOG paragraph matches the repo's entry style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- default get now VALIDATES the committed value against the registry: a stale/
  removed/attacker-supplied name (from a cloned repo) reads as "no default" →
  picker, instead of routing or bricking every no-flag kickoff (#1). kickoff also
  announces a non-claude project default before launch — visibility, not a prompt,
  so a committed default can't silently route your code off-Claude (#1 security).
- grok probe: when neither `timeout` nor `gtimeout` exists, skip `grok models`
  and return inconclusive (trust auth) rather than risk an unbounded call that
  hangs the picker (#2).
- kickoff argument grammar: `--agent` consumes the next token as its value, so it
  isn't mistaken for the task name (#4).
- agent-registry.sh committed executable (100755), matching herdr-launch.sh, so
  the documented direct invocation works (#5).
- kickoff "Critical" note: step 12 → step 13 cross-ref (launch was renumbered) (#6).
- `supports=` comment marked RESERVED/not-yet-consumed (a seed for the
  orchestration design), not "already driving" degradation (#7).
- herdr-launch bad-mode usage string shows the launch arity incl.
  [agent-selector] (#8).
- continue reopen: note reworded to match behavior (`claude -c` IS always sent)
  and the codex/grok caveat surfaced inline in the success report (#3).

Not changed (reviewed): README model-id duplication (accepted human-facing docs),
CHANGELOG paragraph (matches repo style); per-task worker persistence for a true
per-CLI resume stays a later idea.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- grok probe now always runs BOUNDED: when neither `timeout` nor `gtimeout`
  exists, self-bound with a background killer (fds detached so the command
  substitution doesn't block on it) instead of skipping the check — so a dropped
  model is still caught on hosts without a timeout binary, and the probe still
  can't hang the picker (#1).
- a successful `grok models` that parses to nothing (a reformatted listing that
  dropped the `*` bullet) is treated as inconclusive → availability assumed,
  rather than marking every grok entry unavailable and disabling the backend (#3).
- herdr-launch surfaces resolve's real stderr on exit 2 instead of labelling
  every cause "unknown agent selector" (#5).
- README: `/continue` reopen wording corrected — it always sends `claude -c` and
  the user resumes a codex/grok worker themselves; no automatic per-CLI resume is
  claimed (#2, doc half; per-task persistence stays a later idea).
- marketplace.json work-system description refreshed to match plugin.json (#6).

Not changed: committed-external-default consent gate (#4) — an explicit product
decision to announce, not prompt (a cloned repo can already run hooks/CLAUDE.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
- Bound EVERY external-CLI probe: factor out run_bounded (timeout/gtimeout, else
  a self-watchdog that escalates SIGTERM -> SIGKILL) and use it for codex
  `login status` (was completely unbounded) and grok `models`. Its stdout goes to
  a temp file so an orphaned grandchild can't hold the command-substitution pipe
  open — verified a SIGTERM-ignoring probe is now killed at ~12s, not left to hang
  the picker (#4).
- kickoff manual (non-herdr) block no longer auto-persists the project default:
  it only prints a command, so no launch is confirmed — tell the user to run
  `default set` once the worker is up, matching the herdr path's "persist only
  after a successful launch" rule (#2).
- kickoff picker: set OFFER_DEFAULT from the interpreted Yes/No answer, not a
  literal label match, so the save-as-default gate can't miss on case (#3).
- knowledge: add the missing `prime:` key to the new entry (#6); refresh the
  stale herdr-kickoff-automation entry (step 13, registry-resolved worker argv,
  not a hardcoded `claude … /continue`) (#7).

Not changed: the committed-external-default consent gate (#1) stays announce-not-
prompt (a settled product decision); herdr-launch's `${0%/*}` sibling lookup (#5)
is latent and matches the file's existing convention (callers always pass an
absolute path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 17, 2026
Mostly real regressions from the round-4 batch, caught by the re-review:

- run_bounded: add `-k 1` to the timeout/gtimeout branches. GNU timeout only
  SIGTERMs at the deadline then waits, so a SIGTERM-ignoring probe ran forever on
  the COMMON path (any host with a timeout binary — e.g. all Linux CI); --kill-after
  escalates to SIGKILL like the self-watchdog. Normalize a bounded kill to a single
  124 "timed out" code (#4).
- codex probe: a run_bounded timeout (124) is now inconclusive -> assume available
  (mirrors grok), not a genuine auth failure — a slow `codex login status` no longer
  tells a logged-in user to re-login and disables the backend (#5).
- grok probe: match the model id as a SUBSTRING of the raw `grok models` output
  (here-string, no pipe) instead of a positional awk field + exact-line grep, so a
  reformatted listing can't yield a wrong token and a false "model not offered" (#6).
- project default resolves the MAIN repo root via --git-common-dir, so a
  `default set` run from inside a linked worktree lands in the main checkout, not
  the disposable worktree copy (#3).
- kickoff manual path: the main-repo session runs `default set` after the user
  confirms the worker started — not a command for the user's terminal, where $REG
  is undefined and the cwd is the worktree (#2).
- knowledge: correct the herdr-kickoff entry's grok argv (`grok -m …`, not codex) (#7).

Not changed: committed-external-default consent gate (#1) — settled announce-not-
prompt product decision.

Verified: gtimeout -k bounds a SIGTERM-ignoring probe at ~11s; a hung codex probe
reads available; `default set` from the worktree writes the main repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NjTKpmBkXxxYkn7orMfZCC
gering added a commit that referenced this pull request Jul 18, 2026
External-only (codex+grok) review of this branch's own diff:

- #1: pr-post's design double-prefix guard required trailing whitespace
  after "[lens]", so a valid but unspaced self-tag ([reuse]text, bare
  [reuse]) — which the workflow parser accepts — slipped past and got
  re-prefixed to "[reuse] [reuse]…". Align the regex to the workflow
  parser (/^\s*\[([\w-]+)\]/, no trailing-space requirement).
- #2: the SKILL in-session Design-table skip rule suppressed the prefix
  only for the row's OWN lens, while pr-post suppresses any known
  design-lens tag — so a merged row opening with a different member's
  tag rendered differently on the two surfaces, contradicting the
  "read identically" claim. Align the wording to the pr-post guard.
- #4: the "cap wins over design-only" test used defects=2, so
  design-only was never eligible and it never exercised the ordering.
  Replace with the real precedence (design-only wins over cap at the
  last round, defects=0) + a correctly-named cap-with-defects case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
gering added a commit that referenced this pull request Jul 23, 2026
External-only swarm review (codex + grok) on PR #42. Apply the agreed
findings to the decision record:

- AMQ send vs single-sequencer: workers send only to the Manager handle;
  Manager relays. `amq send --to <peer>` bypasses the sequencer (#1).
- Broadcast: reuse AMQ fan-out/presence/federation instead of hand-rolled
  multi-writer global.jsonl (the model Maildir superseded) (#2).
- Lane lifecycle: drain-on-/close + stale-mail guard so a reused path never
  reconsumes a prior occupant's undrained message (#3).
- Soften the "RESOLVES" overclaim: this ADR supersedes the herdr docs' enum;
  their refresh is pending (#4).
- Canonicalize the lane key via git rev-parse --show-toplevel, not raw cwd (#7).
- Fix ws-statusline states flag order: `states [--cached] <dir>` (#10).
- _index.md blurb: central ~/.agent-mail/ mailbox, not the superseded
  .mailbox/ protocol (always-loaded surface) (#11).
- Note the spike is decided, no open task file (#12).
- Trust-model residuals (convention-based identity, home-dir readable store)
  as accepted for a single-user local tool (#5, #6).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LTZx9DqrXPXQFoTrCvcJmD
gering added a commit that referenced this pull request Jul 25, 2026
Apply the agreed findings from a local swarm review (11 ✅ + 1 🟨; the 3 ❌ —
a feature version bump, a README inventory line, and a per-subcommand python3
guard — were deliberately left, see the PR discussion).

herdr-agent.sh:
- Bound herdr list/get/read with a wall-clock timeout (_ha_bounded: timeout →
  gtimeout → perl alarm), honouring the header's "never a hang" promise. wait
  stays governed by its own --timeout. (#6)
- ha_wait now detects the --timeout=MS form too, so a caller's explicit bound in
  either spelling is honoured and no duplicate flag is appended. (#7)
- A missing <target> returns usage code 2, not 4 (server-unreachable), so a
  programmer error is not mistaken for a transient outage. (#12)
- set -u is enabled only on the executed-CLI path, never at source time, so
  sourcing for the prelude/helpers no longer mutates the caller's shell. (#13)
- classify_cwd returns the resolved path as a third tuple element, so a caller
  keying by full path reuses it instead of a second realpath. (#14)

lanes.sh:
- Scrub tab/CR/LF from every TSV cell: agent-derived fields are untrusted, and an
  embedded tab/newline would forge columns/rows. Mirrors herdr-tab-glyph. (#1)
- Guard the agent loop against non-dict (null) elements → never crash, always
  exit 0. (#2)
- flush() now calls the shared classify_cwd instead of re-open-coding the task
  rule, so the classification can't drift between the two consumers. (#15)
- Resolve SCRIPT_DIR via BASH_SOURCE (robust to bare-name invocation). (#5)
- Header wording: exit-0 scope clarified; --json emits [] when no lanes. (#3, #8)

herdr-tab-glyph.sh: consume classify_cwd's new 3-tuple; same BASH_SOURCE fix (#5).
herdr-tab-glyphs.md: point at $HERDR_MATCH_PRELUDE as the shared match SoT. (#10)
Tests extended: null-element + TSV-injection (lanes); --timeout= + missing-target
exit 2 (herdr-agent). Regression: herdr-tab-glyph output byte-identical vs a live
snapshot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8crYp6tzRKMiwW63Zt3GG
gering added a commit that referenced this pull request Jul 27, 2026
A second local swarm review (mostly regressions surfaced by the round-1 fixes);
7 agreed findings applied, 3 declined (a misread pluginVersion, the re-raised
per-subcommand python3 guard, and a 3-file DRY extraction left as a follow-up).

herdr-agent.sh:
- ha_wait now runs under _ha_bounded too, sized ABOVE the server --timeout
  (+5s), so a wedged server can't hang it either — the "never a hang" contract
  now holds for every wrapper. _ha_bounded takes the bound as an argument. (#1)
- get/read/wait reject a leading-dash <target> (usage code 2) so an untrusted
  id can't be parsed as an option flag, matching herdr-tab-glyph's guard. (#3)

lanes.sh:
- Coerce every liveness cell to str (_s): a non-string herdr field (e.g. numeric
  agent_status) no longer crashes the TSV scrub / mistypes the JSON. (#2)
- A malformed (non-dict) list element now fails unmatched lanes closed to
  "unverified" — a partly-untrustworthy list can't assert "no worker". (#4)
- Every --json early-exit emits [] (not empty stdout), so json.loads never
  chokes; the header contract is now fully honoured. (#5)
- Drop the dead `import os` from lanes_join (the prelude imports it). (#7)

herdr-tab-glyph.sh: cmd_refresh calls the bounded ha_list instead of a raw
`herdr agent list`, so a wedged server can't hang a glyph refresh. (#6)

Tests extended: leading-dash reject + bounded wait (herdr-agent); non-string
field, malformed→unverified, and []-on-empty (lanes). check-structure green,
classification byte-identical vs the live snapshot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R8crYp6tzRKMiwW63Zt3GG
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