{"record":{"id":"b6aff306768d618c","repo":"gastownhall/beads","slug":"dry-run-would-compact-s-original-size-d-bytes","errorCode":null,"errorMessage":"dry-run: would compact %s (original size: %d bytes)","messagePattern":"dry-run: would compact (.+?) \\(original size: (.+?) bytes\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"internal/compact/compactor.go","lineNumber":114,"sourceCode":"\t\treturn fmt.Errorf(\"failed to verify eligibility: %w\", err)\n\t}\n\tif !eligible {\n\t\tif reason != \"\" {\n\t\t\treturn fmt.Errorf(\"issue %s is not eligible for Tier 1 compaction: %s\", issueID, reason)\n\t\t}\n\t\treturn fmt.Errorf(\"issue %s is not eligible for Tier 1 compaction\", issueID)\n\t}\n\n\tissue, err := c.store.GetIssue(ctx, issueID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch issue: %w\", err)\n\t}\n\n\t// Calculate original size\n\toriginalSize := len(issue.Description) + len(issue.Design) + len(issue.Notes) + len(issue.AcceptanceCriteria)\n\n\tif c.config.DryRun {\n\t\treturn fmt.Errorf(\"dry-run: would compact %s (original size: %d bytes)\", issueID, originalSize)\n\t}\n\n\t// Get summary from AI\n\tsummary, err := c.summarizer.SummarizeTier1(ctx, issue)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to summarize: %w\", err)\n\t}\n\n\t// Check if compaction would actually reduce size\n\tcompactedSize := len(summary)\n\tif compactedSize >= originalSize {\n\t\twarningMsg := fmt.Sprintf(\"Tier 1 compaction skipped: summary (%d bytes) not shorter than original (%d bytes)\", compactedSize, originalSize)\n\t\tif err := c.store.AddComment(ctx, issueID, \"compactor\", warningMsg); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to record warning: %w\", err)\n\t\t}\n\t\treturn fmt.Errorf(\"compaction would increase size (%d → %d bytes), keeping original\", originalSize, compactedSize)\n\t}\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/compact/compactor.go#L96-L132","documentation":"When Config.DryRun is true, CompactTier1 does not perform real compaction. Instead it returns this formatted message as an error to signal what WOULD happen: the issue ID and the computed original size (description + design + notes + acceptance criteria bytes). It is an informational sentinel, not a failure.","triggerScenarios":"Calling CompactTier1 (directly or via runCompactSingle/batch) with a Compactor built with DryRun: true — including the automatic downgrade in New when no API key is present (errAPIKeyRequired path).","commonSituations":"Running `bd compact --dry-run`; forgetting to set an API key so New silently switched to dry-run; CI jobs without secrets that expect real compaction.","solutions":["Treat this return value as an expected dry-run report, not a failure, in batch aggregation logic","Set a valid API key and DryRun: false to perform real compaction","Check the log for the 'failed to create Haiku client' downgrade if dry-run was unintended","Parse the original size from the message if you need reporting"],"exampleFix":"// before\ncfg := &compact.Config{} // DryRun defaults false, but empty key downgrades silently\n// after\ncfg := &compact.Config{DryRun: false}\nc, err := compact.New(store, os.Getenv(\"ANTHROPIC_API_KEY\"), cfg)\nif err != nil { return err }\nif c.IsDryRun() { log.Println(\"warning: running in dry-run mode\") }","handlingStrategy":"type-guard","validationCode":"// detect dry-run before doing work\nc, err := compact.New(store, key, cfg)\nif err != nil { return err }\nif cfg.DryRun { log.Println(\"compactor is in dry-run mode\") }","typeGuard":"func inDryRun(cfg *compact.Config) bool { return cfg != nil && cfg.DryRun }","tryCatchPattern":"if err := c.CompactTier1(ctx, id); err != nil {\n    if strings.Contains(err.Error(), \"dry-run: would compact\") {\n        return nil // expected dry-run report\n    }\n    return err\n}","preventionTips":["Remember: empty API key in New silently flips DryRun to true","Expose/check Config.DryRun after New returns to know the effective mode","In batch aggregation, treat 'dry-run:' messages as success, not failure"],"tags":["go","dry-run","informational","sentinel"],"backgroundTag":"dry-run-mode","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}