History-derived governance repair

Tracked by pm-wrbe and pm-pivf.

Project history is context: maintenance must preserve when work happened and why related occurrences share an identity.

Recovering legacy closure dates

pm validate --check-metadata --fix-hints
pm validate --check-metadata --auto-fix --fix-scope timestamps --dry-run --json
pm validate --check-metadata --auto-fix --fix-scope timestamps --json

The timestamps scope is opt-in. It fills only missing closed_at fields on terminal items. The exact scope allowlist leaves unrelated metadata, estimates, resolution and lifecycle repairs gated. A dry run performs no item mutation. Checks describe the pre-repair state; run validation again to prove convergence.

Dates come from verified replay of the item's complete available history, including a comparison against the current item. The selected date is the first transition in its final uninterrupted terminal interval. A reopen resets that interval. Ordinary metadata edits do not advance it. Terminal creation counts; a compaction or repair baseline carrying terminal state alone does not establish when the original closure happened. Existing dates and completed_at are never rewritten. Custom terminal statuses and their registered aliases are recognized.

Missing, unreadable, invalid or insufficient history is reported in closure_timestamp_residual with a reason and total count. Bounded human output marks truncated rows; JSON or --verbose-diagnostics restores full diagnostics (subject to the separately declared output budget). closure_history_inspected distinguishes a lightweight missing-date count from a verified derivation pass.

Every applied date is re-derived under the normal item mutation lock and appends an audited update event. A stale proposal fails instead of assigning an unverified date. Retrying an already repaired item is a no-op.

The public @unbrained/pm-cli/sdk/governance surface exposes deriveClosureTimestamp, scanClosureTimestamps, applyClosureTimestampFix and runValidate. SDK hosts can use runValidate({checkMetadata: true, autoFix: true, fixScope: ["timestamps"], dryRun: true}, {path: pmRoot}) to obtain the same plan as the CLI; timestamp repairs do not need a CLI mutation adapter.

Shared issue codes and typed lineage

Duplicate issue-code validation accepts explicit discovered_from, supersedes and incident_from links targeting another item in the same issue-code group. This joins the existing parent/child and adjudicated-duplicate rules. A follow-up can retain its real upstream issue code without renaming historical work.

Derivation must reach a root. Cycles and their dependent followers remain collisions, as do unrelated items, self references, references to different code groups, and related, implements or ordering links. An independent collision still appears when a group also contains legitimate follow-ups. No graph edges are fabricated to satisfy validation.

Repository backfill verification

Before applying a historical backfill, save the generated changelog's item-to- release membership and inspect the complete repair preview. Regenerate with the latest pm-changelog package afterward and compare membership. Row ordering may change when a proven date replaces a mutable fallback; release attribution must remain intact. Run history-drift validation and repeat the timestamp preview to prove integrity and idempotence. Any generator defect belongs in pm-changelog.


History_governance_repair remote
Ein Problem melden