Skip to content

feat: auto-emit journal entries on interview lifecycle (Phase 4b)#30

Merged
cleak merged 2 commits into
masterfrom
claude/phase-4b-interview-auto-emit
Apr 29, 2026
Merged

feat: auto-emit journal entries on interview lifecycle (Phase 4b)#30
cleak merged 2 commits into
masterfrom
claude/phase-4b-interview-auto-emit

Conversation

@cleak
Copy link
Copy Markdown
Owner

@cleak cleak commented Apr 29, 2026

Summary

Second slice of Phase 4 from `docs/journal-spec.md` §9: hook the CLI `interview start/answer/commit` commands and the MCP `interview_start`/`_answer`/`_adjust`/`_commit` tools into the journal so each lifecycle moment of an AI-assisted design interview gets captured automatically.

Event Kind Notes
Started `plan` provisional
AnswerRecorded `finding` provisional
PhaseAdvanced `finding` provisional; emitted alongside answer/adjust when phase changes
Adjusted `finding` provisional; covers adjust/add/edge tentative-graph mutations
Committed `outcome` `passed = true`, `final = true` (finalizes journal session)

Rollback is in the spec but the interview engine has no rollback operation today — when/if that lands, this module gains a sixth variant. "All provisional until session commit" is honored: every event during the interview is provisional; commit emits one non-provisional `outcome` that finalizes the journal session and triggers publish.

Code structure

Split `tempyr_journal::auto_emit` into a directory:

```
auto_emit/
mod.rs - re-exports
summary.rs - shared clamp_summary helper
task.rs - Phase 4a transitions (no behavior change)
interview.rs - Phase 4b events (new)
```

CLI: `interview start/answer/commit` each grow `--agent` (default "claude"), mirroring `tempyr status`. MCP: handlers build an `InterviewEvent` after the operation succeeds and route through `self.emit_interview_event(graph_dir, event)` — anchored on the resolved project, never the server cwd.

Test plan

  • `cargo test --workspace` (587+ pass; 7 new `auto_emit::interview` unit tests + 1 new CLI integration test)
  • `cargo clippy --workspace --all-targets -- -D warnings`
  • `cargo fmt --check`
  • Manual smoke: `tempyr interview start ...`, then `answer`, then `commit` in a real repo; confirm `plan` / `finding` / `outcome` entries appear under `/tempyr/journals/open/`

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Interview commands (start, answer, commit) accept an --agent flag (default: "claude")
    • Automatic journal entry generation for interview lifecycle events, including final commit outcomes and operation metrics
  • Behavior Changes

    • Emission failures are non-fatal and surfaced as soft warnings (logged/returned) instead of aborting operations
  • Tests

    • New integration test validating end-to-end interview journal auto-emission and commit finalization
  • Documentation

    • Updated journal spec describing interview auto-emission behavior and soft-failure handling

Second slice of Phase 4: hook the CLI `interview start/answer/commit`
commands and the MCP `interview_start`/`_answer`/`_adjust`/`_commit`
tools into the journal so each lifecycle moment of an AI-assisted
design interview gets captured automatically. Per
`docs/journal-spec.md` §9 Phase 4:

  | Event             | Kind     | Notes                              |
  |-------------------|----------|------------------------------------|
  | Started           | plan     | provisional                        |
  | AnswerRecorded    | finding  | provisional                        |
  | PhaseAdvanced     | finding  | provisional; emitted when reanaly- |
  |                   |          | sis bumps the phase                |
  | Adjusted          | finding  | provisional; covers adjust/add/    |
  |                   |          | edge tentative-graph mutations     |
  | Committed         | outcome  | passed = true, final = true        |

Rollback is in the spec but the interview engine has no rollback
operation today — when/if that lands, this module gains a sixth
variant. Until then, "all provisional until session commit" is
honored end-to-end: every event during the interview is provisional,
the commit emits one non-provisional `outcome` that finalizes the
journal session and triggers publish.

Code structure: split the auto_emit module into a directory so task
and interview event mappings live alongside without crowding one
file. New layout:

  auto_emit/
    mod.rs        - re-exports
    summary.rs    - shared clamp_summary helper (200-char floor,
                    UTF-8-safe)
    task.rs       - Phase 4a transitions (no behavior change)
    interview.rs  - Phase 4b events (new)

CLI plumbing: `interview start/answer/commit` each grow an `--agent`
flag mirroring `tempyr status` (default "claude"). MCP plumbing:
each handler builds an `InterviewEvent` after the operation succeeds
and routes through `self.emit_interview_event(graph_dir, event)`,
which anchors on the resolved project root (NOT the server cwd) and
returns Option<String> for soft-warning callers — same pattern as
the task transition helper.

Tests: 7 new unit tests in `auto_emit::interview::tests` covering
the mapping; 1 new CLI integration test
`test_interview_lifecycle_auto_emits_journal_entries` driving start
→ answer → commit and asserting plan/finding/outcome entries land
plus the .ready marker is written on the final outcome.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 647ad617-0d28-4892-8348-ffbfd50fa6bf

📥 Commits

Reviewing files that changed from the base of the PR and between a2f4e9a and 4f0e6d7.

📒 Files selected for processing (3)
  • crates/tempyr-cli/src/commands/interview_cmd.rs
  • crates/tempyr-cli/src/commands/status_cmd.rs
  • crates/tempyr-mcp/src/handler.rs

📝 Walkthrough

Walkthrough

Adds best-effort interview-lifecycle journal auto-emission. CLI and MCP handlers accept an agent parameter and emit InterviewEvent variants (Started, AnswerRecorded, PhaseAdvanced, Adjusted, Committed) via a new auto-emit subsystem that clamps summaries, writes provisional/final entries, and surfaces write problems as non-fatal warnings.

Changes

Cohort / File(s) Summary
CLI Command Interfaces
crates/tempyr-cli/src/main.rs, crates/tempyr-cli/src/commands/interview_cmd.rs
Added --agent flag (default "claude") to interview subcommands; updated InterviewAction variants and run_start/run_answer/run_commit signatures to accept and forward agent. Emission helper emit_interview_event wraps auto-emit and logs/swallow errors.
CLI Integration Test
crates/tempyr-cli/tests/integration.rs
New integration test verifying auto-emitted journal entries for interview start, answer, and commit and that commit finalization writes a .ready marker.
Journal Auto-Emit Interview Module
crates/tempyr-journal/src/auto_emit/interview.rs
New public InterviewEvent<'a> enum and auto_emit_interview_event implementation that builds clamped EntryDrafts for Started, AnswerRecorded, PhaseAdvanced, Adjusted, and Committed (final outcome includes counts). Includes unit tests for truncation and summary constraints.
Auto-Emit Infrastructure
crates/tempyr-journal/src/auto_emit/mod.rs, crates/tempyr-journal/src/auto_emit/summary.rs
New auto_emit module exposing interview and task; added shared clamp_summary, MAX_SUMMARY_CHARS (200), and TRUNCATION_MARKER to centralize truncation logic.
Task Auto-Emit Refactor
crates/tempyr-journal/src/auto_emit/task.rs
Refactored to use shared clamp_summary; removed duplicate truncation code and updated tests to reference shared constants.
Journal Crate Re-exports
crates/tempyr-journal/src/lib.rs
Expanded public re-exports to include InterviewEvent and auto_emit_interview_event.
MCP Server Integration
crates/tempyr-mcp/src/handler.rs
Added best-effort emit_interview_event helper; handlers emit appropriate InterviewEvents (start, answer, phase-advance, adjust, commit) and attach soft-write warnings into session-state JSON responses.
Status Command Journal Handling
crates/tempyr-cli/src/commands/status_cmd.rs
emit_journal_for_transition now distinguishes NotAGitRepo (silently ignored) from other failures (logged to stderr) when resolving git directories for auto-emits.
Docs
docs/journal-spec.md
Documented scope of interview-lifecycle auto-emit (5 operations), location of implementation, and that write failures are treated as non-fatal warnings.

Sequence Diagram

sequenceDiagram
    participant User as User / MCP Client
    participant Handler as CLI / MCP Handler
    participant Engine as Interview Engine
    participant Git as Git (repo metadata)
    participant Journal as Journal Auto-Emit

    User->>Handler: interview start (agent)
    Handler->>Engine: create session
    Engine-->>Handler: session_id, phase, root info
    Handler->>Git: resolve repo/top-level
    Handler->>Journal: auto_emit_interview_event(Started)
    Journal-->>Handler: write outcome (ok / soft-fail)
    Handler-->>User: session_id

    User->>Handler: interview answer (session_id, answer, agent)
    Handler->>Engine: record answer
    Engine-->>Handler: filled_gaps, new_phase
    Handler->>Journal: auto_emit_interview_event(AnswerRecorded)
    alt phase changed
        Handler->>Journal: auto_emit_interview_event(PhaseAdvanced)
        Journal-->>Handler: write outcome
    end
    Handler-->>User: updated session state (includes warnings)

    User->>Handler: interview commit (session_id, agent)
    Handler->>Engine: commit/finalize
    Engine-->>Handler: node_count, edge_count, files_created
    Handler->>Git: resolve repo/top-level
    Handler->>Journal: auto_emit_interview_event(Committed)
    Journal-->>Handler: final outcome entry written
    Handler-->>User: commit confirmed (includes warnings)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through code at break of day,

Emitting journals along the way—
Start, answer, phase, adjust, and then commit,
Agent in paw, each entry neatly writ.
🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: implementing automatic journal entry emission for interview lifecycle events as part of Phase 4b.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/tempyr-cli/src/commands/interview_cmd.rs`:
- Around line 295-302: The code currently returns early on any Err from
jpath::git_common_dir and jpath::repo_toplevel, swallowing all errors; change
each match to capture the error (e) and only silently return for the expected
“not a git repo” case, otherwise print the error to stderr (e.g. eprintln!) with
context and the error details before returning. Concretely, replace Err(_) arms
for git_common_dir and repo_toplevel with Err(e) => if e indicates “not a git
repository” (or the library’s equivalent variant/message) { return } else {
eprintln!("failed to resolve git_common_dir/repo_toplevel: {}", e); return },
referencing jpath::git_common_dir, jpath::repo_toplevel, common_dir and
worktree_top to locate the spots to change.

In `@crates/tempyr-mcp/src/handler.rs`:
- Around line 1319-1330: Replace stderr-only warning side-effects with adding
the returned soft-failure string into the MCP response warnings: when calling
emit_interview_event(...) (e.g., the InterviewEvent::Started, ::Answered and
::Adjusted calls inside interview_start, interview_answer and interview_adjust),
capture the Option<String> and if Some(w) push/append it into the operation
result/response warnings collection (the same field used by interview_commit)
instead of calling eprintln!; ensure you update the code paths at the three call
sites so the response exposes those warnings to clients.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 38d2cd67-69bf-4afa-b793-6af02c6f1cc4

📥 Commits

Reviewing files that changed from the base of the PR and between dcba655 and a2f4e9a.

📒 Files selected for processing (10)
  • crates/tempyr-cli/src/commands/interview_cmd.rs
  • crates/tempyr-cli/src/main.rs
  • crates/tempyr-cli/tests/integration.rs
  • crates/tempyr-journal/src/auto_emit/interview.rs
  • crates/tempyr-journal/src/auto_emit/mod.rs
  • crates/tempyr-journal/src/auto_emit/summary.rs
  • crates/tempyr-journal/src/auto_emit/task.rs
  • crates/tempyr-journal/src/lib.rs
  • crates/tempyr-mcp/src/handler.rs
  • docs/journal-spec.md

Comment thread crates/tempyr-cli/src/commands/interview_cmd.rs
Comment thread crates/tempyr-mcp/src/handler.rs
Two findings on PR #30 (Phase 4b):

1. The CLI auto-emit helpers were swallowing all errors from
   `jpath::git_common_dir` / `repo_toplevel` with `Err(_) => return`.
   `NotAGitRepo` is a distinct enum variant — silently skipping it
   is the right call (tempyr supports operating outside a git repo)
   but bundling Io / Git failures into the same arm hides real bugs.
   Match `NotAGitRepo` explicitly and log anything else to stderr
   with context. Apply the same fix to `status_cmd.rs` (slice 4a
   code), which has the identical pattern.

2. MCP `interview_start`, `interview_answer`, and `interview_adjust`
   were calling `eprintln!` for journal auto-emit failures. MCP
   clients don't see server stderr, so a write failure was
   effectively invisible. `interview_commit` already exposes
   warnings via the response's `warnings` field; mirror that on the
   other three handlers. Adds a small `attach_warnings` helper that
   inserts `warnings` into the JSON value `session_state_json`
   returns; `interview_answer` uses an inline `json!` literal so the
   field gets added there directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cleak cleak merged commit 0cd7a1d into master Apr 29, 2026
1 check passed
@cleak cleak deleted the claude/phase-4b-interview-auto-emit branch April 29, 2026 18:19
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