Skip to content

feat(setbuilder): autobuild + fill_to_duration agent tools (#491)#523

Merged
thewrz merged 11 commits into
mainfrom
feat/issue-491-autobuild-fill-duration
Jun 22, 2026
Merged

feat(setbuilder): autobuild + fill_to_duration agent tools (#491)#523
thewrz merged 11 commits into
mainfrom
feat/issue-491-autobuild-fill-duration

Conversation

@thewrz

@thewrz thewrz commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Why

The WrzDJSet chat agent could sense the set and make granular edits, but had no way to (re)build it wholesale. This closes Family 3 of epic #442 with the two destructive structural tools. The family was gated on undo UX — now resolved by the global-undo stack from #493/#494.

What

  • autobuild — regenerate the entire set order from the pool + energy curve via the deterministic pass-1 builder (already honors locked slots and saved pairings). Replaces the hand-arranged order wholesale.
  • fill_to_duration — append unused pool tracks (deterministic pool order) until the set reaches its target_duration_sec; bounded by a per-turn hard cap (MAX_FILL_INSERTS) and never moves locked slots.
  • Supporting changebuild_set gained commit: bool = True; the agent path calls it with commit=False so a multi-tool chat turn stays atomic (the turn owns commit/rollback). The one REST caller keeps the default → unchanged.
  • Undonot re-implemented. Both tools join MUTATION_TOOLS, so the existing global-undo stack (feat(setbuilder): bridge agent mutations into the document undo stack (gates #491 + Family 4) #493/feat(setbuilder): make agent chat mutations undoable #494) snapshots the whole document before the turn and makes them revertible for free (⌘Z / Undo). The frontend adds only a discoverability hint on destructive tool cards.

Design + plan: docs/superpowers/specs/2026-06-21-setbuilder-autobuild-fill-design.md, docs/superpowers/plans/2026-06-22-setbuilder-autobuild-fill.md.

Testing

  • Backend tests pass — 3137 passed, coverage 89.10% (≥ 85% gate)
  • Frontend tests pass — 1391 passed; ESLint + tsc --noEmit clean
  • ruff + bandit clean; no models/migrations touched (alembic drift N/A)
  • Regression tests: snapshot round-trip identity (autobuild → restore = prior order); turn-atomicity (autobuild + failing tool → full rollback); requests table left untouched
  • CI green
  • Manual: ask the agent to "rebuild the set" and "fill to 2 hours" — confirm changes apply and ⌘Z reverts the rebuild

🤖 Co-authored by Claude Opus 4.8 (1M context). Closes #491.

Summary by CodeRabbit

  • New Features
    • Added autobuild: regenerates the full set order from the pool/curve while preserving locked slots and saved pairings.
    • Added fill_to_duration: appends unused pool tracks until target duration is reached (with per-turn insertion limits).
    • Destructive tool cards (autobuild and fill_to_duration) now show an “undo” hint to make rollback behavior more discoverable.
  • Improvements
    • Enhanced the way these tools’ results are summarized for clearer, user-facing feedback.

thewrz and others added 9 commits June 21, 2026 22:58
…tools (#491)

Family 3 destructive structural tools. Records the key finding that #493/#494's
global undo already closes #491's undo gate, so the original Task 0 (per-tool
'Undo this rebuild' button) is replaced by: rely on global undo + a
discoverability hint + a snapshot round-trip identity test.

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

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

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

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

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
… cards (#491)

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

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

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

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fd6c3a3b-3e75-416e-aebc-7065100f0b95

📥 Commits

Reviewing files that changed from the base of the PR and between 54b0203 and 1087d97.

📒 Files selected for processing (2)
  • server/app/services/setbuilder/agent_tools_structural.py
  • server/tests/test_setbuilder_structural.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/app/services/setbuilder/agent_tools_structural.py
  • server/tests/test_setbuilder_structural.py

📝 Walkthrough

Walkthrough

Adds two destructive setbuilder agent tools, autobuild and fill_to_duration. Includes a commit: bool = True flag on build_set for agent-turn atomicity, a new agent_tools_structural module, wiring through MUTATION_TOOLS/tool specs/dispatch/display summaries, comprehensive backend tests, and a frontend undo-discoverability hint on destructive tool cards.

Changes

autobuild + fill_to_duration agent tools

Layer / File(s) Summary
build_set commit/flush control
server/app/services/setbuilder/pass1_deterministic.py, server/tests/test_setbuilder_pass1.py
Adds commit: bool = True to build_set and _persist_slots; when False, flushes instead of committing so the surrounding chat turn owns commit/rollback. New test verifies the rollback-vs-persist difference.
Structural tools module
server/app/services/setbuilder/agent_tools_structural.py
New module with _tool_autobuild (wraps build_set(commit=False)), _duration_for (fallback to AVG_TRACK_LENGTH_SEC), and _tool_fill_to_duration (inserts unused pool tracks respecting locked slots and MAX_FILL_INSERTS = 100).
Backend wiring
server/app/services/setbuilder/agent_common.py, agent_tool_specs.py, pass2_agent.py, agent_display.py
Extends MUTATION_TOOLS allowlist, registers ToolSpecs for both tools, wires handlers into apply_tool_call, and adds display-summary branches with minute conversion, pluralization, and cap notes.
Backend structural tests
server/tests/test_setbuilder_structural.py
New test module covering autobuild (locked-slot preservation, rollback-on-failing-turn, snapshot round-trip identity) and fill_to_duration (target stop, pool exhaustion, insert cap, missing-target error, locked slots), plus _duration_for fallback and all display-summary variants.
Frontend undo hint
dashboard/app/(dj)/setbuilder/components/ChatPanelBody.tsx, setbuilder.module.css, components/__tests__/ChatPanelBody.test.tsx
Adds DESTRUCTIVE_TOOL_NAMES set and renders a data-testid="agent-undo-hint" block in ToolCard for matching tools. CSS adds .toolUndoHint styling. Parameterized tests assert hint presence for autobuild/fill_to_duration and absence for swap_slots.
Design spec and implementation plan
docs/superpowers/specs/2026-06-21-setbuilder-autobuild-fill-design.md, docs/superpowers/plans/2026-06-22-setbuilder-autobuild-fill.md
Spec documents undo-UX decision, architectural constraints, tool contracts, and acceptance criteria. Plan provides step-by-step TDD checkpoints, lint/coverage gates, and CI sweep instructions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #491: This PR directly implements the two tools specified in the issue (autobuild and fill_to_duration), satisfies the undo-UX gate via the global snapshot mechanism and frontend discoverability hint, fulfills all stated acceptance criteria (locked-slot preservation, requests non-modification, MUTATION_TOOLS membership, rationale requirement, snapshot round-trip identity test), and addresses the bounded insert-count constraint.

Possibly related PRs

  • wrzonance/WrzDJ#459: Both PRs extend pass2_agent.py's apply_tool_call handler dispatch map with new mutation tool entries using the same wiring pattern.
  • wrzonance/WrzDJ#469: Both PRs extend MUTATION_TOOLS in agent_common.py and add corresponding apply_tool_call handler entries in pass2_agent.py.
  • wrzonance/WrzDJ#483: Touches the same MUTATION_TOOLS allowlist, _agent_tools() spec registry, apply_tool_call dispatch, and _tool_display_summary extension points that this PR builds on.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main feature additions: two new agent tools (autobuild and fill_to_duration) for setbuilder, directly referencing the linked issue #491.
Linked Issues check ✅ Passed The PR comprehensively implements all coding requirements from issue #491: both tools added with owner-scoping, rationale requirement, MUTATION_TOOLS registration, tool dispatch wiring, ToolCard rendering with undo hints, commit parameter threading, locked slot preservation, requests table invariant validation, and extensive regression test coverage meeting acceptance criteria.
Out of Scope Changes check ✅ Passed All changes directly support the two destructive agent tools and their undo/atomicity infrastructure. No unrelated refactoring, cleanup, or out-of-scope changes detected in the backend tools, atomicity parameter threading, test coverage, or frontend hint rendering.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-491-autobuild-fill-duration

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/app/services/setbuilder/agent_tools_structural.py (1)

38-40: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Log autobuild outcome metrics for destructive-turn observability.

The dispatcher logs invocation, but this tool doesn’t log result state (slot_count, iterations). Add one lazy-formatted outcome log here for easier postmortems/debugging.

Proposed refactor
 def _tool_autobuild(
     db: Session, set_obj: Set, payload: dict[str, Any]
 ) -> tuple[dict[str, Any], set[int]]:
@@
     result = build_set(db, set_obj, commit=False)
     affected = {slot.position for slot in result.slots}
+    logger.info(
+        "setbuilder autobuild: set %s rebuilt (%s slots, %s refinement passes)",
+        set_obj.id,
+        result.slot_count,
+        result.iterations,
+    )
     return {"slot_count": result.slot_count, "iterations": result.iterations}, affected
As per coding guidelines, agent implementation files should log agent actions/state changes, and based on learnings server logs should use lazy `%s` formatting.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/app/services/setbuilder/agent_tools_structural.py` around lines 38 -
40, Add outcome logging after the build_set function call to capture the
autobuild metrics for observability. After the result assignment (the line
calling build_set with commit=False), add a logger.info statement that logs the
slot_count and iterations values from the result object using lazy %s string
formatting. This should provide visibility into the tool's execution state for
debugging and postmortem analysis.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/app/services/setbuilder/agent_tools_structural.py`:
- Around line 57-59: The presence check for target_duration_sec in the condition
uses `if not target:` which treats the value 0 as missing and raises an
AgentToolError, but 0 might be a valid target duration value. Replace the falsy
check `if not target:` with an explicit null check `if target is None:` so that
a zero value is properly handled as a valid assigned duration rather than
triggering the error.

---

Nitpick comments:
In `@server/app/services/setbuilder/agent_tools_structural.py`:
- Around line 38-40: Add outcome logging after the build_set function call to
capture the autobuild metrics for observability. After the result assignment
(the line calling build_set with commit=False), add a logger.info statement that
logs the slot_count and iterations values from the result object using lazy %s
string formatting. This should provide visibility into the tool's execution
state for debugging and postmortem analysis.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2be846e2-c72e-497a-b52c-79ba749fa2a2

📥 Commits

Reviewing files that changed from the base of the PR and between 2ac20c4 and 54b0203.

📒 Files selected for processing (13)
  • dashboard/app/(dj)/setbuilder/components/ChatPanelBody.tsx
  • dashboard/app/(dj)/setbuilder/components/__tests__/ChatPanelBody.test.tsx
  • dashboard/app/(dj)/setbuilder/setbuilder.module.css
  • docs/superpowers/plans/2026-06-22-setbuilder-autobuild-fill.md
  • docs/superpowers/specs/2026-06-21-setbuilder-autobuild-fill-design.md
  • server/app/services/setbuilder/agent_common.py
  • server/app/services/setbuilder/agent_display.py
  • server/app/services/setbuilder/agent_tool_specs.py
  • server/app/services/setbuilder/agent_tools_structural.py
  • server/app/services/setbuilder/pass1_deterministic.py
  • server/app/services/setbuilder/pass2_agent.py
  • server/tests/test_setbuilder_pass1.py
  • server/tests/test_setbuilder_structural.py

Comment thread server/app/services/setbuilder/agent_tools_structural.py
thewrz and others added 2 commits June 22, 2026 09:14
…tion (#491)

CodeRabbit: 'if not target' rejected a legitimate 0 target as missing. Use an
explicit None check so a 0 target is a no-op (loop sees it as already met) rather
than an error. Pinned with a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeRabbit nitpick: mirror fill_to_duration by logging autobuild's result
(slot_count + iterations) on this destructive turn.

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

thewrz commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator Author

CodeRabbit body nitpick addressed (autobuild observability): _tool_autobuild now logs its outcome (slot_count + iterations) on the destructive turn, mirroring fill_to_duration. Fixed in commit 1087d97.

@thewrz thewrz merged commit acb6859 into main Jun 22, 2026
10 checks passed
@thewrz thewrz deleted the feat/issue-491-autobuild-fill-duration branch June 22, 2026 16:27
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.

feat(setbuilder): autobuild + fill_to_duration agent tools (#442 Family 3) — gated on undo UX

1 participant