Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions examples/sample-output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Sample outputs

Reference outputs the skill should produce given a representative day. Use these as regression anchors when iterating on SKILL.md wording.

---

## Example 1 — Full four-bucket day

**Ask:** `debrief today`

**Output:**

```
Fri, Apr 18 2026

Decided
- Went with go-yaml over mapstructure — reflection cost wasn't worth the flexibility
- Dropped the Slack webhook path for v1 — too much scope

Shipped
- Handle PR-squash chore commits (#11)
- Redesigned the cost table with per-model breakdown (#12)
- Added --project filter to standup and cost commands

Investigated
- goreleaser's default matrix skips arm64 Linux — had to add it explicitly

Watch
- The classifier regex is too aggressive on test: prefixes and might drop real work
```

Note: **Decided** and **Investigated** bullets come from Claude session notes. **Shipped** bullets are a mix of commits and session notes about completed work. **Watch** captures a risk the user flagged during a session but didn't file as an issue.

---

## Example 2 — Quiet day (chore-only)

**Ask:** `debrief today`

**Commits:** only `chore: bump deps`, `chore: format`, `test: flaky retry`.

**Session notes:** none survived the filter (all were planning language).

**Output:**

```
Quiet day — just chores and lints. Nothing shipped worth writing up.
```

This exact line signals "the tool worked, your day was just quiet" — distinct from "the tool found nothing" (which means a broken scan).

---

## Example 3 — Nothing at all

**Ask:** `debrief yesterday` on a day the user didn't work.

**Output:**

```
No activity to report.
```

---

## Example 4 — Slack format

**Ask:** `debrief today as slack`

**Output:**

````
`Fri, Apr 18 2026`

- Went with go-yaml over mapstructure — reflection cost wasn't worth the flexibility
- Handle PR-squash chore commits (#11)
- goreleaser's default matrix skips arm64 Linux — had to add it explicitly
- The classifier regex is too aggressive on test: prefixes and might drop real work
````

- Date is wrapped in backticks (Slack renders it as inline code).
- No section headers — flat list.
- Bucket order is preserved in bullet order.

---

## Example 5 — Week range

**Ask:** `debrief this week`

**Output:**

```
Week of Apr 13 – Apr 19, 2026

Decided
- Went with go-yaml over mapstructure
- Dropped cost subcommand — claudecost owns pricing

Shipped
- Handle PR-squash chore commits (#11)
- Humanizer visibility banner (#9)
- CWD-fallback git discovery (#10)
- Cost table redesign with per-model breakdown (#12)

Investigated
- goreleaser arm64 Linux matrix gap
- GIT_* env vars override -C flag in subprocesses

Watch
- Classifier aggressive on test: prefixes
```

For multi-day ranges, bullets are deduplicated and merged across days. Date header is a range, not a single day.

---

## What "good output" means — tuning rubric

When dogfooding, grade each day's output against these questions:

1. **Could I paste this into Slack verbatim?** If no — the wording is off.
2. **Does every bullet describe real work I did?** If no — the note filter let noise through.
3. **Is anything I actually did missing?** If yes — either the filter is too strict, or the commit was covered-by-notes incorrectly.
4. **Did Decided/Investigated/Watch bullets land in the right buckets?** If a "decided" showed up in Shipped — the keyword list missed it.
5. **On a chore-only day, does it say "Quiet day"?** If it says "No activity" — the noise-vs-emptiness distinction broke.

Fix the SKILL.md wording — don't add code.
48 changes: 46 additions & 2 deletions internal/collector/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,44 @@ func sanitizedEnv() []string {
return out
}

// unsetGitHookVars unsets process-level GIT_* variables that git sets when
// running inside a hook (e.g. pre-commit). sanitizedEnv only scrubs env for
// subprocesses we launch directly — the production collector code under test
// spawns its own git processes that inherit os.Environ(), so those still see
// the leaked GIT_DIR/GIT_WORK_TREE and target the outer worktree instead of
// the temp repo. Unset at the process level and restore via t.Cleanup.
func unsetGitHookVars(t *testing.T) {
t.Helper()
hookVars := []string{
"GIT_DIR",
"GIT_WORK_TREE",
"GIT_INDEX_FILE",
"GIT_COMMON_DIR",
"GIT_PREFIX",
"GIT_EXEC_PATH",
"GIT_REFLOG_ACTION",
}
for _, k := range hookVars {
old, present := os.LookupEnv(k)
if !present {
continue
}
if err := os.Unsetenv(k); err != nil {
t.Fatalf("unset %s: %v", k, err)
}
t.Cleanup(func() {
_ = os.Setenv(k, old)
})
}
}

func TestGitCollector_CollectFromTempRepo(t *testing.T) {
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git not available")
}
// See unsetGitHookVars — required when the test runs inside a pre-commit
// hook so Collect() targets the temp repo, not the outer worktree.
unsetGitHookVars(t)

// Create a temp repo with commits.
dir := t.TempDir()
Expand All @@ -58,7 +92,13 @@ func TestGitCollector_CollectFromTempRepo(t *testing.T) {
}

run("init")
run("checkout", "-b", "main")
// Disable any global hooksPath — the temp repo inherits ~/.gitconfig
// settings; a developer-machine commit-msg hook (e.g. min-length) would
// otherwise fire inside the test.
run("config", "core.hooksPath", "/dev/null")
// -B (create-or-reset) tolerates init.defaultBranch=main, which makes
// git init pre-create "main" and then reject -b main.
run("checkout", "-B", "main")
// Belt-and-suspenders: also set identity via repo-local config so commits
// resolve to test@example.com even if GIT_AUTHOR_* env doesn't propagate.
run("config", "user.email", "test@example.com")
Expand Down Expand Up @@ -159,6 +199,8 @@ func TestGitCollector_MultiDayCommitsSplitByDay(t *testing.T) {
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git not available")
}
// See TestGitCollector_CollectFromTempRepo for why this is needed.
unsetGitHookVars(t)

dir := t.TempDir()
repo := filepath.Join(dir, "multi-day-project")
Expand Down Expand Up @@ -186,7 +228,9 @@ func TestGitCollector_MultiDayCommitsSplitByDay(t *testing.T) {
)

run(baseEnv, "init")
run(baseEnv, "checkout", "-b", "main")
// See TestGitCollector_CollectFromTempRepo for the rationale on these.
run(baseEnv, "config", "core.hooksPath", "/dev/null")
run(baseEnv, "checkout", "-B", "main")
run(baseEnv, "config", "user.email", "test@example.com")
run(baseEnv, "config", "user.name", "Test User")

Expand Down
Loading