Skip to content

feat: add pt handoff command for unfinished/non-PR records#125

Merged
eriksjaastad merged 2 commits into
mainfrom
feat/pt-handoff-command
May 11, 2026
Merged

feat: add pt handoff command for unfinished/non-PR records#125
eriksjaastad merged 2 commits into
mainfrom
feat/pt-handoff-command

Conversation

@manager-identity
Copy link
Copy Markdown
Contributor

Summary

  • Adds pt handoff command group for recording structured "unfinished work" or "non-PR exempt" records: create, list, show, resolve. Required as the escape hatch for Phase C's session-end gate.
  • New handoffs table via additive migration 010_add_handoffs_table.py. Indexed on card_id, project, unresolved_at. Classified as LOCAL_ONLY in the CR-SQLite manifest (see DECISIONS.md addition for rationale).
  • JSON envelope pt.handoff.v1 matching the schema-versioning pattern from PR feat: add read-only JSON memory CLI for SSH/cron automation #124.

Phase context

Phase D of the Locked Project Hygiene Workflow (umbrella card #6118).

Notable design choice

handoffs is LOCAL_ONLY_TABLES (not replicated cross-machine via CR-SQLite). New entry in DECISIONS.md explains: a handoff exists because there's uncommitted local work in a dirty tree. That dirty tree is, by definition, machine-local — it hasn't been pushed. Replicating the pointer cross-machine would be a tease, not a resume point. Same rationale lives in the migration's docstring.

Test plan

  • 24/24 handoff CLI tests green (pytest tests/test_handoff_cli.py -v)
  • Tests use the real migration runner (db.migration_runner.apply_migration) — no parallel runtime DDL to drift from the migration file.
  • After merge: pt db migrate applies migration 010 cleanly on a fresh DB.
  • After merge: pt handoff create CARD_ID --intent ... --status ... --next ... --guidance ... --json produces a pt.handoff.v1 payload, persists to the new table.
  • After merge: pt handoff list --unresolved-only --json returns only unresolved records.
  • After merge: pt handoff resolve <id> on an already-resolved handoff fails with validation error and preserves the original timestamp/note (regression test for the double-resolve idempotency fix).
  • After merge: pt handoff create --auto-files warns to stderr if git is unavailable or returns non-zero, while still creating the handoff with empty file_list.

Code review history

  • Initial commit 1e1d168: FAIL — 2 MEDIUM (silent git failure in _auto_classify_files, schema drift via parallel runtime DDL), 1 design question (LOCAL_ONLY classification — resolved with Erik), 2 LOW.
  • Fixup commit 2d0f206: PASS — distinct stderr warnings on each git-failure path; _ensure_handoffs_table() removed entirely (tests now drive the real migration runner so schema drift is structurally impossible); --files element-shape validation; double-resolve refused with validation error; LOCAL_ONLY rationale in migration docstring + DECISIONS.md.

Known follow-ups (filed)

  • Two LOW polish items on test coverage (TimeoutExpired branch, one thin error-message assertion). Filed as a follow-up card.

Related

  • Closes #6151
  • Parent: #6118

manager-identity Bot and others added 2 commits May 5, 2026 23:37
Introduces `pt handoff create/list/show/resolve` backed by a new
`handoffs` table (migration 010). Records capture intent, current
status, next command, file classifications, and optional pr_exempt
metadata. All subcommands emit `pt.handoff.v1` JSON envelopes using
the canonical `_emit_json` / `_emit_json_error` / `PtJsonError`
pattern from PR #124. 18 tests green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MEDIUM #1: _auto_classify_files() now surfaces git failures via stderr
  warnings (FileNotFoundError, TimeoutExpired, non-zero exit). Callers
  using --auto-files can no longer mistake "no dirty files" for "git
  unavailable". Two new tests cover FileNotFoundError + non-zero exit.
- MEDIUM #2: Removed _ensure_handoffs_table() entirely. Tests now apply
  the real migration 010 via the migration_runner — eliminates the
  schema-drift risk where DDL in code could lag the migration.
- LOW #3: --files now validates each element is a {path, classification}
  dict with classification in the allowed set. Three new tests.
- LOW #4: pt handoff resolve refuses to overwrite an already-resolved
  record (preserves the original timestamp + note as historical state).
  New test asserts both the validation error and that show still shows
  the first resolution.
- LOCAL_ONLY classification: docstring on migration 010 + new entry in
  DECISIONS.md ("Handoffs are LOCAL_ONLY by design") explaining why
  cross-machine replication of dirty-tree pointers would be misleading.

Test count: 18 -> 24, all green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@manager-identity manager-identity Bot added the feature New feature label May 6, 2026
@eriksjaastad eriksjaastad merged commit a760588 into main May 11, 2026
2 checks passed
@eriksjaastad eriksjaastad deleted the feat/pt-handoff-command branch May 11, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant