Skip to content

Harden swarm design-lens integration (0.5.1)#41

Merged
gering merged 7 commits into
mainfrom
task/harden-swarm-design-lens-integration
Jul 18, 2026
Merged

Harden swarm design-lens integration (0.5.1)#41
gering merged 7 commits into
mainfrom
task/harden-swarm-design-lens-integration

Conversation

@gering

@gering gering commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Closes the residual gaps left open when swarm 0.5.0 made kind:"design" findings first-class: the --fix/--loop/fan-out/rendering paths were written for defects and never fully generalized to suggestion-shaped findings.
  • Two real UX bugs (P1) plus four correctness/UX polish items (P2/P3) surfaced by an independent /code-review high on PR Extend swarm lens set to 11 lenses in 4 clusters #35.
  • Patch bump (0.5.0 → 0.5.1) — correctness/UX polish, no new user surface.

Changes

  • P1 — --fix re-confirm is kind-aware. A kind:"design" finding has no line-local defect to re-find, so an agreed (✅) design fix was silently reported skipped-stale. Step 1 now re-confirms the suggestion still applies for design findings (reuse target / duplication / simpler form / waste still present).
  • P1 — --loop converges on design churn. loop-closeout.py step gains --defects D and a new design-only reason (fixed order: after no-change, before cap); --pending is now defect-scoped. Design suggestions are advisory and no longer run the loop to the cap. Omitting --defects disables the reason (legacy-safe).
  • P2 — untagged cluster findings no longer mis-route to defect. A Claude finder reviews through one kind-homogeneous cluster, so its kind is inferred (kindTrusted) even when the [lens] prefix is dropped; externals (kind-mixed 11-lens unit) stay unspecified/defect and keep not voting — the consensus/auto-accept invariant is untouched, only design/defect routing is corrected.
  • P3 — pr-post [lens] double-prefix guard (DESIGN_LENS_TAGS, sync-checked); in-session Design table gains a [lens] prefix (matches the PR path); per-lens failure-isolation loss documented as an accepted tradeoff of the cluster default.
  • Knowledge (swarm-review-pipeline.md), CHANGELOG, version bump; tests extended (test_loop_closeout.py, test_pr_post.py, test_lens_sync.py).

Readiness

  • ✅ Tests: test_loop_closeout / test_pr_post / test_lens_sync all pass
  • check-structure.py: 0 errors (2 pre-existing description-length warnings, unrelated)
  • ✅ Version bumped 0.5.0 → 0.5.1 (plugin.json + marketplace.json, in sync)
  • ✅ CHANGELOG + knowledge entry updated
  • ➖ Build: N/A (declarative markdown plugin repo)

Test plan

  • --loop on a diff whose only remaining findings are design suggestions terminates with design-only, not at the cap
  • An agreed design finding under --fix is applied (not reported skipped-stale)
  • A design-cluster finding with a dropped [lens] prefix renders in the Design table, not the defect table
  • A design row whose befund already carries [reuse] posts once, not [reuse] [reuse]

🤖 Generated with Claude Code

gering and others added 7 commits July 18, 2026 12:57
Two UX bugs where kind:"design" findings interact badly with the
--fix/--loop paths, which were written for defects:

- --fix re-confirm was defect-shaped: a design suggestion has no
  line-local defect to re-find, so an agreed (✅) design fix got
  silently reported skipped-stale and never applied. Step 1 now
  branches on kind — for kind:"design" it re-confirms the suggestion
  still applies (reuse target/duplication/simpler form/waste still
  present), only skipping when that target is genuinely gone.

- --loop never converged on design churn: the tally made no
  defect/design distinction, so once only design suggestions remained
  (F>0 ∧ A>0 ∧ C>0 every round, each simplification spawning a fresh
  one) it ran to the cap. loop-closeout.py step gains --defects D and a
  new design-only reason (fixed order: after no-change, before cap);
  --pending is now defect-scoped (design never holds the loop open).
  Omitting --defects disables the reason (legacy callers unaffected).

test_loop_closeout.py extended for the design-only ordering,
pending-suppression, and range-check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
In default per-cluster mode a design-cluster finder that dropped its
[lens] prefix fell back to 'unspecified' → kind:"defect", so a real
design suggestion rendered in the defect table, skipped applicability
verify, and (since P1b) inflated the --loop defect tally that drives
convergence — reintroducing the churn P1b closes.

The old guard rejected inference because "guessing lenses[0] could
stamp a design kind on an off-lens defect". That collapsed a real
distinction: a Claude finder reviews through ONE kind-homogeneous
cluster, so its kind is recoverable even when the exact lens isn't;
externals carry the full 11-lens (kind-mixed) set or none, so they
stay 'unspecified'/defect and keep NOT voting.

- pool: untagged finding from a homogeneous Claude unit inherits that
  unit's kind and is marked kindTrusted; lens stays 'unspecified'
  (we recover the kind, not a lens we can't know).
- cluster kind vote uses kindTrusted members; untaggedOnly stays
  lens-tagged-based, so the consensus/auto-accept invariant is
  untouched — only design/defect routing is corrected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
render_body unconditionally prepended "[lens] " to design rows. The
workflow doesn't strip a finder's own "[lens] " self-tag from the
summary, and a merge can leave the representative summary tagged with a
different design lens than the cluster's resolved lens — so a row could
post as "[reuse] [reuse] …" or "[reuse] [simplification] …".

Add an idempotency guard keyed on a DESIGN_LENS_TAGS tuple (mirrored
from LENS_CLUSTERS.design, sync-checked by test_lens_sync.py): if the
cell already opens with a known design-lens tag, keep it and don't add a
second. The tuple is NOT a kind fallback (the retired DESIGN_LENSES was)
— it runs only inside the already-decided design branch and can never
move a row between tables. A non-lens bracket ([TODO] …) is not mistaken
for a self-tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
- P3: the in-session Design table gains a [lens] Befund prefix, matching
  the PR-comment path so lens attribution reads identically on both.
- P3: document the cluster-default's loss of per-lens failure isolation
  as an accepted tradeoff (--max restores it; a crash is a visible
  backendError).
- Update the swarm-review-pipeline knowledge entry for the 0.5.1
  design-lens hardening (P1 --fix/--loop, P2 kind inference, P3 guard +
  attribution + isolation tradeoff).
- CHANGELOG 0.5.1 entry; bump plugin.json + marketplace.json.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
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
The branch's own external-only self-review flagged that inferring a
design kind from cluster homogeneity is unsafe: a design finder is
invited to report defects too, so an untagged finding from a design
cluster may be a real off-lens bug. Inferring 'design' routed that bug
to applicability verify (wrong rubric → can silently REFUTE/drop a real
defect) and excluded it from the --loop defect tally (loop could
converge design-only with a real defect still open).

Dropping a real bug is the cardinal sin for a review tool and outweighs
the benefit (keeping a rarer-but-lower-severity untagged design
suggestion out of the defect table). Revert to the pre-0.5.1 safe
default: untagged multi-lens findings fall to 'unspecified' → defect.

Restores the original pool-level fallback and lens-tagged cluster-kind
vote; drops kindTrusted/voters. The P3 double-prefix guard, in-session
lens prefix, and P1 --fix/--loop changes are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
The branch's second external-only self-review (CONFIRMED codex+grok)
flagged that `--loop` design-only convergence terminates right after
applying that round's design fixes, before any re-review — so a
simplification that introduces a real defect this round is never caught.

Forcing a re-review would re-open the churn design-only exists to close
(design findings diverge), so the fix is explicit disclosure, not a
behavior change: the SKILL close-out, loop-closeout.py's REASONS label +
docstring, and the knowledge entry now state the last design edits were
applied but NOT re-reviewed and recommend a fresh /swarm:review to
confirm — same honesty as the cap caveat.

(Round-2 finding B — the double-prefix guard keeping a self-tag that
differs from the resolved cluster lens — was declined: the shown tag
matches the shown text, so rewriting to the resolved lens would mislabel
it; it's the deliberate anti-double-prefix tradeoff.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jo5yGBLmefV64HN26hxV8n
@gering
gering merged commit 68a261f into main Jul 18, 2026
1 check passed
@gering
gering deleted the task/harden-swarm-design-lens-integration branch July 18, 2026 17:04
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