Skip to content

feat(regenerate): batch path via Anthropic Message Batches API#21

Merged
silversurfer562 merged 1 commit into
mainfrom
feat/batch-maintain
May 8, 2026
Merged

feat(regenerate): batch path via Anthropic Message Batches API#21
silversurfer562 merged 1 commit into
mainfrom
feat/batch-maintain

Conversation

@silversurfer562
Copy link
Copy Markdown
Member

Summary

Adds opt-in attune-author regenerate --batch for cost-saving bulk help regen via Anthropic's Message Batches API (~50% cost vs synchronous per-call pricing). Submit-and-detach UX with a --resume partner that polls + splices results when ready.

Sequenced as item (3) from the 2026-05-08 enhancements briefing. Closes the briefing's three-item sequence (after attune-author#20 for skill-export and attune-rag#11 for native citations).

Spec: specs/author-batch-maintain/{requirements,design,tasks}.md.

CLI surface

$ attune-author regenerate --batch
Submitted batch msgbatch_xyz (35 requests, model claude-sonnet-4-20250514).
Estimated completion: ~6 min (Anthropic 24h SLA).

Run  attune-author regenerate --resume   to splice results when ready.

# ... lunch ...

$ attune-author regenerate --resume
Batch msgbatch_xyz ended. Regenerated 32 feature(s). Failed: rag, smart-test

Mutex-enforced flag set: --batch | --resume | --status | --cancel. Modifiers: --force (with --batch: overwrite pending state file), --json (with --status: cron-friendly output).

Resume ergonomics (the user's emphasis)

  • No batch ID required--resume reads .help/.batch-state.json automatically.
  • Bare regenerate prints a hint when a state file exists; never auto-resumes silently.
  • Resume-after-timeout works — state file kept on poll-loop timeout, next --resume picks up cleanly.
  • --status is one-shot — query without committing to a wait. --json for cron parsing.
  • --cancel is one-shot — call SDK cancel + remove state file.
  • Stale-state recovery — 29-day retention check (matches Anthropic) surfaces a clean cleanup hint instead of crashing on a 404.
  • Multi-batch guard--batch refuses to overwrite an existing state file unless --force is passed.

What landed

  • attune_author.doc_gen._anthropic_batch — SDK wrapper with submit_batch / poll_batch, typed BatchPolishRequest / BatchPolishResult, adaptive timeout (min(30min, max(5min, 60·N/20))), SIGINT-cancels-and-reraises.
  • attune_author.maintenance_batchsubmit_maintenance_batch / resume_maintenance_batch / status_maintenance_batch / cancel_maintenance_batch, plus BatchState schema and state-file lifecycle.
  • attune_author.polish.build_polish_prompt — extracted prompt-building helper. Both paths build byte-identical prompts.
  • attune_author.generator.prepare_polish_phase / apply_polish_results — extracted Phase 1 (render) and Phase 3 (write) helpers. Synchronous path now calls them too. Single source of truth for rendering.
  • docs/regenerate-batch.md — when to use which path, fallback behavior, env-var overrides, cancel semantics, stale-state recovery.

Tests

  • +57 new unit tests, all passing:
    • 19 for the SDK wrapper layer (test_anthropic_batch.py) — golden-fixture parser, payload shape, full poll-loop state matrix, SIGINT cancel, adaptive timeout
    • 22 for orchestration (test_maintenance_batch.py) — state file lifecycle, submit/resume/status/cancel, per-feature failure isolation, timeout-keeps-state, parity test (sync vs batch produce identical files)
    • 16 for CLI (test_cli_batch.py) — argparse mutex, all four modes, --json shape, bare-command pending-batch hint
  • +1 opt-in live integration test at tests/integration/test_batch_live.py, gated on ANTHROPIC_API_KEY + RUN_LIVE_BATCH=1. Tagged @pytest.mark.live. Default-skipped; ~$0.02/run.
  • Full suite: 670 passed, 32 skipped (live + pre-existing skill-export integration).
  • Ruff clean on all touched files.

Verification gate

V1 (Anthropic SDK class names) verified live against SDK 0.89.0:

  • Resource path is client.messages.batches
  • MessageBatch exposes processing_status, request_counts, expires_at, cancel_initiated_at, results_url
  • MessageBatchIndividualResponse carries custom_id + result (discriminated union: Succeeded / Errored / Expired / Canceled)

Pinned in code; recorded fixture at tests/golden/batch_response.json regression-tests the parser.

Test plan

  • CI green on all matrix rows (Linux/macOS/Windows × Python 3.10–3.13)
  • (Optional, on user) Run RUN_LIVE_BATCH=1 pytest tests/integration -m live to exercise end-to-end against the real Anthropic API

🤖 Generated with Claude Code

Adds opt-in `attune-author regenerate --batch` that submits all
polish requests for stale features as a single Anthropic batch
(~50% cost vs synchronous per-call pricing). Submit-and-detach
UX with a `--resume` partner that polls + splices results when
the user is ready.

CLI surface:
  --batch     submit; print batch ID + resume hint; exit
  --resume    poll + splice + write templates
  --status    one-shot status (supports --json)
  --cancel    cancel batch + remove state file
  --force     with --batch: overwrite an existing pending state

Argparse mutex enforces "exactly one batch-mode flag at a time".
Bare `regenerate` (no batch flags) prints a one-liner hint when
a state file exists but never auto-resumes.

State file lives at .help/.batch-state.json. Schema-versioned;
29-day retention check matches Anthropic's batch retention
window. On poll-loop timeout the state file is intentionally
KEPT so the next --resume picks up cleanly. SIGINT during
polling cancels the batch and re-raises.

Refactor: the synchronous path's render+write phases are
extracted to generator.prepare_polish_phase /
generator.apply_polish_results, and polish.build_polish_prompt
is shared between paths. Both paths produce byte-identical
on-disk templates for the same inputs (parity test in
tests/test_maintenance_batch.py guards the invariant).

Per-feature failure isolation: any errored depth fails the
whole feature (no templates written for it); other features in
the same batch succeed normally.

Tests: +57 new unit tests, +1 opt-in live integration test
(gated on ANTHROPIC_API_KEY + RUN_LIVE_BATCH=1, ~$0.02/run).
Full suite 670 pass / 32 skipped (live + skill-export
integration). Ruff clean on touched files.

Spec: specs/author-batch-maintain/{requirements,design,tasks}.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@silversurfer562 silversurfer562 merged commit bfd27e5 into main May 8, 2026
12 checks passed
@silversurfer562 silversurfer562 deleted the feat/batch-maintain branch May 8, 2026 20:07
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