SDK-owned terminal lifecycle policy and durable project history
What changed
- moved the close transaction into the public SDK lifecycle layer and reduced the CLI close module to a compatibility shim
- added public terminal reason and predecessor-edge policy primitives shared by CLI, SDK, and MCP routes
- stopped
update --status closedand direct terminal create from synthesizing immutable close reasons - preserved
blocked_bydependency rows through close, reopen, and reclose while clearing only transient blocked-state scalars - added SDK migration documentation, a compilable SDK-only example, classified public-surface additions, regenerated error provenance, and generated changelog entries
Why
Terminal lifecycle policy lived privately in CLI command modules. That caused two concrete defects: one terminal route bypassed close-reason governance by inventing evidence, and closing a dependent deleted the ordering edges needed to understand historical project context. The SDK now owns this tranche of lifecycle semantics so every presentation surface uses one operation and consumers can inspect or select policy explicitly.
PM lineage
- pm-z5pmf8 — SDK lifecycle ownership
- pm-xm0id4 — preserve historical ordering edges
- pm-2ew0w3 — uniform terminal reason governance
pm-xm0id4 and pm-2ew0w3 are complete. pm-z5pmf8 remains open and unclaimed because the create/update/delete/restore/context/planning SDK-to-CLI inversions are explicitly outside this delivered lifecycle tranche.
Verification
- 6,610 tests; 100% statements, branches, functions, and lines
- build, typecheck, ESLint, jscpd, CodeFactor/static-quality, 100% docstring coverage
- SDK public-surface, package parity, entrypoint cost, CLI transport, token-budget, context/retrieval evaluation gates
- isolated compiled CLI: predecessor survives close → reopen → reclose; reasonless update returns
close_reason_required - fresh packed npm and Bun consumers import SDK lifecycle primitives and run contained
npx/bunxbinaries pnpm audit --audit-level moderate: no known vulnerabilities- secrets scan, packed-npx smoke, and 88-command package-first dogfood
- Sentry/telemetry: critical=0, high=0 over 14 days; best-effort telemetry gate passed
Hosted analysis and review gates are expected to complete against this immutable PR head.
Summary by Sourcery
Move terminal lifecycle semantics into an SDK-owned close operation while aligning reason governance and predecessor-edge policy across CLI, SDK, and MCP surfaces.
Bug Fixes:
- Enforce consistent close_reason_required behavior across direct close, update --status closed, and direct terminal create so terminal transitions never synthesize immutable reasons.
- Preserve blocked_by predecessor dependency edges across close, reopen, and reclose cycles while still clearing transient blocked state scalars.
Enhancements:
- Expose SDK lifecycle primitives including closeItem, terminal transition policy, and reason/order governance as public API and update CLI to act as a thin compatibility shim.
- Introduce terminal lifecycle policy primitives (reason resolution and ordering-edge handling) with a compilable SDK example and dedicated documentation.
- Update error provenance, mocks, and tests so MCP, dedupe, and integration workflows consume the new SDK lifecycle modules consistently.
Documentation:
- Add SDK lifecycle policy documentation and a compilable example demonstrating terminal reason and ordering-edge policy usage.
Tests:
- Expand unit and integration coverage for terminal reason governance, predecessor preservation across lifecycle transitions, and SDK lifecycle policy primitives.
Summary by cubic
Moves terminal lifecycle to SDK-owned operations for consistent close behavior across CLI, SDK, and MCP. Fixes reason governance, preserves predecessor edges, and hardens close provenance (keeps existing reasons and normalizes ids) to keep project history intact. Addresses pm-2ew0w3 and pm-xm0id4; advances pm-z5pmf8.
-
Bug Fixes
- Enforce
close_reason_requiredacross direct close,update --status closed, and direct terminal create; no synthesized reasons, and existing reasons are never overwritten. - Normalize canonical ids on input (accept ids with or without the
pm-prefix) and clear only transient blocked state while preservingblocked_byedges through close → reopen → reclose. - Surface reason provenance via
resolveTerminalReason/requireTerminalReason; update tests and runtime contracts to assert ordering survival and provenance.
- Enforce
-
Migration
- SDK: use
closeItem/runCloseplusrequireTerminalReason,applyTerminalOrderingPolicy, andTerminalTransitionPolicyfrom@unbrained/pm-cli/sdk. - CLI: when using
pm create --status closedorpm update --status closed, pass a reason via--close-reasonor--message; reasonless transitions now fail withclose_reason_requiredunder governance. Expectblocked_byedges to remain after close.
- SDK: use