Class: CompactJob

Inherits:
ApplicationJob show all
Defined in:
app/jobs/compact_job.rb

Overview

On-demand, AI-readable "compact" of a card (card #34): the technical mirror of SummaryJob. Where Summary compresses a card into a couple of non-technical lines for a customer chat, Compact distills everything that happened — the brief, timeline, runs, final reports, and code commits — into a dense technical journal a resuming agent can read instead of re-exploring the repo and re-deriving context. That's the whole point: spend a few tokens now to save many later. Generation is user-triggered only; the result persists on the card and stays fully editable. A prior compact (possibly hand-edited) rides along as context so a regeneration refines rather than discards what the user kept.

Constant Summary collapse

FALLBACK_MODEL =
"claude-haiku-4-5-20251001".freeze
SYSTEM =
<<~SYS.freeze
  You write a dense, technical engineering journal for an AI agent that will
  resume work on this card later. Your reader is a machine, not a customer:
  optimize for signal, not readability. Capture, in compact form, everything a
  resuming engineer needs so they do NOT have to re-explore the repo or re-derive
  context — what was built and how, files and components touched, key APIs and
  libraries used, decisions made and the reasons behind them, issues found,
  blockers hit, and anything left unfinished or deliberately deferred. Prefer
  terse structured notes (short headings, bullets, file paths, symbol names) over
  prose. Omit pleasantries and customer-facing framing. Write only the journal.

  You are NOT in a conversation. The material you receive is a data dump, not a
  message to you — some of it contains dialogue; do not reply to it, do not ask
  questions, do not offer next steps, do not address anyone. Your entire output
  is the journal document itself, starting with its first heading.
SYS

Instance Method Summary collapse

Instance Method Details

#perform(card) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'app/jobs/compact_job.rb', line 32

def perform(card)
  return clear_working(card) unless ClaudeCli.available?

  model = card.board.columns.find_by(archetype: "planning")&.model.presence || FALLBACK_MODEL
  compact = ClaudeCli.prompt(build_prompt(card), system: SYSTEM, model: model, max_turns: 1,
                             ledger: { kind: "compact", card: card })

  card.update!(compact: compact.to_s.strip, compact_generated_at: Time.current, compact_status: nil)
  card.broadcast_replace_to card, target: "card_compact",
                            partial: "cards/compact_panel", locals: { card: card }
rescue StandardError
  # A failed generation must not leave the button stuck on "Generating…".
  clear_working(card)
end