Skip to content

feat: quest autopsy — failure memory across sessions#75

Merged
justinjdev merged 7 commits intomainfrom
feat/quest-autopsy-67
Mar 12, 2026
Merged

feat: quest autopsy — failure memory across sessions#75
justinjdev merged 7 commits intomainfrom
feat/quest-autopsy-67

Conversation

@justinjdev
Copy link
Copy Markdown
Owner

@justinjdev justinjdev commented Mar 11, 2026

Summary

  • Adds structured failure records (autopsies) that persist in .fellowship/autopsies/ so future quests learn from past mistakes
  • Three CLI commands: autopsy create (JSON stdin), autopsy scan (match by files/modules/tags), autopsy infer (reconstruct from worktree signals)
  • Simplifies gate guard to allow all fellowship CLI commands through the gate, not just gate approve/reject/init
  • Integrates autopsy scan into quest Research phase and autopsy write into Implement recovery
  • Adds autopsy infer to Gandalf's dead-quest handling and rekindle recovery flow
  • Adds autopsy aggregation to /retro retrospective analysis
  • Configurable expiry (default 90 days) via autopsy.expiryDays in ~/.claude/fellowship.json

Closes #67

Test plan

  • 22 unit tests covering create, scan, infer, expiry pruning, matching, config reading
  • Updated guard tests verify all fellowship commands pass through gate
  • Full test suite passes (go test ./...)
  • Binary compiles cleanly (go build ./cmd/fellowship/)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added an autopsy system to record, scan, and infer quest failures with CLI commands: autopsy create, autopsy scan, autopsy infer. Added default expiry (90 days) and user-configurable expiry.
  • Behavior Changes

    • Gate-pending now allows a broader set of safe fellowship subcommands; CLI help updated to include autopsy commands.
  • Documentation

    • Integrated autopsy steps into recovery, skills, and retrospective workflows.
  • Tests

    • Added comprehensive tests for autopsy flows, expiry config, inference, and gate behavior.

#67)

When quests fail, lessons now persist as structured autopsy records in
.fellowship/autopsies/. Future quests scan autopsies during Research and
incorporate relevant warnings before repeating the same mistakes.

CLI commands:
- fellowship autopsy create: write autopsy from JSON stdin
- fellowship autopsy scan: find autopsies by files, modules, or tags
- fellowship autopsy infer: reconstruct autopsy from worktree signals

Also simplifies gate guard to allow all fellowship CLI commands through
the gate (not just gate approve/reject/init), since fellowship commands
operate on state files, not source code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

📝 Walkthrough

Walkthrough

Adds a new autopsy subsystem with CLI commands (create, scan, infer), on-disk JSON persistence under .fellowship/autopsies, expiry/pruning, inference from worktree/tome/herald data, datadir expiry config, guard allowlist updates, tests, and docs/skill integration.

Changes

Cohort / File(s) Summary
Core Autopsy Module
cli/internal/autopsy/autopsy.go, cli/internal/autopsy/autopsy_test.go
New types (Autopsy, CreateInput, ScanOptions), exported funcs Create, Scan, Infer, DefaultExpiryDays; JSON persistence, expiry/pruning, inference helpers, filter matching, and comprehensive unit tests.
CLI Command Integration
cli/cmd/fellowship/main.go
Adds top-level autopsy command with create, scan, infer subcommands, handlers parsing flags/stdin, repo-root resolution, calls into internal/autopsy, and CLI help/dispatch updates.
Datadir config
cli/internal/datadir/datadir.go, cli/internal/datadir/datadir_test.go
New AutopsyExpiryDays(defaultDays int) int reading autopsy.expiryDays from user config; tests cover default and custom values.
Hook/Guard Logic & Tests
cli/internal/hooks/guard.go, cli/internal/hooks/guard_test.go
Relaxed isFellowshipEscapeCommand to use an allowlist during gate_pending (adds autopsy and other subcommands); tests renamed/expanded and a new blocking test added.
Docs / Plugin SKILLs
plugin/commands/rekindle.md, plugin/skills/fellowship/SKILL.md, plugin/skills/quest/SKILL.md, plugin/skills/retro/SKILL.md
Inserts autopsy infer/write into respawn/recovery and Research flows, documents autopsy scan usage, and adds autopsy collection/pattern analysis to retro output.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as "fellowship CLI"
    participant Autopsy as "internal/autopsy"
    participant Datadir as "datadir / .fellowship"
    participant Worktree as "worktree (tome/herald/eagles)"
    CLI->>Autopsy: autopsy infer --dir <worktree> --repo <repo>
    Autopsy->>Worktree: read quest-tome.json, herald, eagles (infer helpers)
    Autopsy-->>Autopsy: build CreateInput (quest, trigger, files, modules, what_failed)
    Autopsy->>Datadir: write .fellowship/autopsies/<ts>-<sanitized>.json
    Datadir-->>Autopsy: persist confirmation
    Autopsy-->>CLI: return created file path / success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.20% 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 title clearly and concisely summarizes the main feature: adding quest autopsy functionality for persistent failure memory across sessions.
Linked Issues check ✅ Passed PR implements all core requirements: autopsy create/scan/infer commands, JSON persistence, integration into quest phases, expiry/pruning logic, and retro aggregation per issue #67.
Out of Scope Changes check ✅ Passed All changes align with issue #67 scope: autopsy subsystem, CLI integration, quest SKILL updates, guard relaxation for fellowship commands, and datadir config.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/quest-autopsy-67

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
cli/internal/autopsy/autopsy_test.go (2)

112-126: Consider checking errors in test assertions.

Lines 113-115 ignore the error from os.ReadFile and json.Unmarshal. While this is unlikely to cause issues in a controlled test, silently ignoring errors can mask test failures.

🔧 Suggested fix
-	data, _ := os.ReadFile(path)
-	var a Autopsy
-	json.Unmarshal(data, &a)
+	data, err := os.ReadFile(path)
+	if err != nil {
+		t.Fatalf("reading autopsy file: %v", err)
+	}
+	var a Autopsy
+	if err := json.Unmarshal(data, &a); err != nil {
+		t.Fatalf("parsing autopsy: %v", err)
+	}

This pattern appears in several other tests (lines 278-280, 326-328, 361-363). Consider applying the same fix consistently.


412-427: Test assertion may not validate the expected behavior.

The test at lines 412-427 has unclear assertions:

  • Line 414-417: The first assertion checks len(modules) != 1 with a comment // Both start with "src", but only logs instead of failing
  • The actual validation happens in the second case (lines 419-426)

The first case seems to be testing that files with a common prefix (src/) produce a single module, but the assertion logic is inverted and uses t.Logf instead of t.Errorf.

🔧 Suggested fix
 func TestInferModules(t *testing.T) {
 	modules := inferModules([]string{"src/auth/jwt.go", "src/auth/session.go", "src/billing/charge.go"})
-	if len(modules) != 1 {
-		// Both start with "src"
-		t.Logf("modules = %v", modules)
+	// All files start with "src", so we expect "src" as the common module
+	if len(modules) != 1 || modules[0] != "src" {
+		t.Errorf("expected [src], got %v", modules)
 	}
cli/internal/autopsy/autopsy.go (1)

224-240: Sort inferred modules before persisting them.

seen is a map, so the module order in the returned slice is nondeterministic. Since these JSON files may be committed, sorting here avoids needless diff churn for identical failures.

♻️ Proposed fix
 import (
 	"encoding/json"
 	"fmt"
 	"os"
 	"path/filepath"
+	"sort"
 	"strings"
 	"time"
 )
@@
 	for m := range seen {
 		modules = append(modules, m)
 	}
+	sort.Strings(modules)
 	return modules

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5001bd97-9406-4c3b-83f5-d3178bbf3ee4

📥 Commits

Reviewing files that changed from the base of the PR and between 9f1de07 and 9ae392d.

📒 Files selected for processing (9)
  • cli/cmd/fellowship/main.go
  • cli/internal/autopsy/autopsy.go
  • cli/internal/autopsy/autopsy_test.go
  • cli/internal/hooks/guard.go
  • cli/internal/hooks/guard_test.go
  • plugin/commands/rekindle.md
  • plugin/skills/fellowship/SKILL.md
  • plugin/skills/quest/SKILL.md
  • plugin/skills/retro/SKILL.md

Comment thread cli/internal/autopsy/autopsy.go Outdated
Comment thread cli/internal/autopsy/autopsy.go Outdated
Comment thread cli/internal/autopsy/autopsy.go
Comment thread plugin/commands/rekindle.md Outdated
justinjdev and others added 4 commits March 10, 2026 21:26
- Log corrupt autopsy files to stderr instead of silently skipping
- Skip autopsies with unparseable timestamps instead of treating as non-expired

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move AutopsyExpiryDays config reading from autopsy to datadir package
- Narrow gate escape from all fellowship commands to explicit allowlist
- Add tests for non-allowlisted commands blocked during gate_pending

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pin HOME in autopsy tests to prevent custom config interference
- Use existing readUserConfig pattern for AutopsyExpiryDays
- Extend cfg struct with autopsy config instead of duplicate file reading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents false positives when both query and autopsy files have no
directory component (filepath.Dir returns ".").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
cli/internal/autopsy/autopsy.go (1)

286-308: Consider sanitizing additional characters in filenames.

The sanitize function only handles spaces and slashes. Characters like :, *, ?, ", <, >, | are invalid in Windows filenames and could cause issues if quest names contain them. This is a minor concern since quest names are typically controlled, but worth noting.

♻️ Optional: Broader sanitization
 func sanitize(s string) string {
 	s = strings.ReplaceAll(s, " ", "-")
 	s = strings.ReplaceAll(s, "/", "-")
+	// Additional characters problematic on Windows
+	for _, c := range []string{":", "*", "?", "\"", "<", ">", "|", "\\"} {
+		s = strings.ReplaceAll(s, c, "-")
+	}
 	if len(s) > 40 {
 		s = s[:40]
 	}
 	return s
 }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c2dd261e-509b-48b2-9cfb-028504801ebe

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae392d and 20c818e.

📒 Files selected for processing (7)
  • cli/cmd/fellowship/main.go
  • cli/internal/autopsy/autopsy.go
  • cli/internal/autopsy/autopsy_test.go
  • cli/internal/datadir/datadir.go
  • cli/internal/datadir/datadir_test.go
  • cli/internal/hooks/guard.go
  • cli/internal/hooks/guard_test.go

- Add random bytes to autopsy filenames for collision resistance
- Return error on failed herald read instead of silently skipping
- Tighten file matching to require directory boundaries (no false positives
  like foo.go matching foobar.go)
- Sanitize additional characters in filenames (colons, asterisks, etc.)
- Check errors in test assertions instead of silently ignoring
- Fix undefined zombie classification in rekindle.md (use stale)
- Use pinned CLI path in rekindle.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6e846a1-ea46-4771-9a51-a471bddb919b

📥 Commits

Reviewing files that changed from the base of the PR and between 20c818e and 4c6bf94.

📒 Files selected for processing (3)
  • cli/internal/autopsy/autopsy.go
  • cli/internal/autopsy/autopsy_test.go
  • plugin/commands/rekindle.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugin/commands/rekindle.md

Comment thread cli/internal/autopsy/autopsy_test.go
Comment thread cli/internal/autopsy/autopsy.go
Comment thread cli/internal/autopsy/autopsy.go
Comment thread cli/internal/autopsy/autopsy.go
- Guard against nil CreateInput with early return
- Check rand.Read() error for collision-resistant filenames
- Return errors from Scan instead of silently skipping bad autopsies
- Sort inferred modules for deterministic JSON output
- Fix test assertions: use t.Errorf/t.Fatalf instead of t.Logf,
  check errors from ReadFile/Unmarshal in Infer tests
- Add TestCreate_NilInput test case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
cli/internal/autopsy/autopsy_test.go (3)

144-149: Consider checking Create return error in test setup.

While the test would eventually fail if Create fails, checking the error provides clearer diagnostics.

♻️ Proposed fix
-	Create(repo, &CreateInput{
+	_, err := Create(repo, &CreateInput{
 		Quest:      "quest-1",
 		Trigger:    "recovery",
 		Files:      []string{"src/auth/jwt.go"},
 		WhatFailed: "auth issue",
 	})
+	if err != nil {
+		t.Fatalf("setup Create failed: %v", err)
+	}

This pattern applies to other Scan tests as well (lines 162, 180, 198).


254-263: Minor: Test doesn't set HOME environment variable.

Unlike other tests that use setupTestRepo or explicitly set HOME, this test uses a raw t.TempDir(). While it works because the autopsies directory doesn't exist, consider using t.Setenv("HOME", t.TempDir()) for consistency with other tests in this file.

♻️ Proposed fix
 func TestScan_EmptyDirectory(t *testing.T) {
+	t.Setenv("HOME", t.TempDir())
 	repo := t.TempDir() // no autopsies dir

286-286: Consider checking tome.Save error in test setup.

The tome.Save call at line 286 (and similar calls at lines 331, 381, 418) ignores the error return value. While unlikely to fail in test environments, checking errors would provide clearer diagnostics if something goes wrong.

♻️ Proposed fix
-	tome.Save(filepath.Join(tomeDir, "quest-tome.json"), qt)
+	if err := tome.Save(filepath.Join(tomeDir, "quest-tome.json"), qt); err != nil {
+		t.Fatalf("setup tome.Save failed: %v", err)
+	}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2f4d49a-de13-4adc-a369-12c08f8a691c

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6bf94 and 30d9f49.

📒 Files selected for processing (2)
  • cli/internal/autopsy/autopsy.go
  • cli/internal/autopsy/autopsy_test.go

@justinjdev justinjdev merged commit 00b7783 into main Mar 12, 2026
2 checks passed
@justinjdev justinjdev deleted the feat/quest-autopsy-67 branch March 12, 2026 00:20
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.

Quest Autopsy — failure memory that persists across sessions

1 participant