Skip to content

Add bw archive: move closed issues out of active consideration#135

Open
jallum wants to merge 1 commit into
beadwork-gxn/date-before-nowfrom
beadwork-2dx/archive
Open

Add bw archive: move closed issues out of active consideration#135
jallum wants to merge 1 commit into
beadwork-gxn/date-before-nowfrom
beadwork-2dx/archive

Conversation

@jallum

@jallum jallum commented May 30, 2026

Copy link
Copy Markdown
Owner

Stacked on #134 (needs resolveDateBeforeNow). Review/merge #134 first; this PR's base will retarget to main once #134 lands.

What

Adds bw archive — moves closed issues into an archive/ tree on the beadwork branch so they leave active consideration.

Archived issues leave the live ID space and the status//labels//blocks/ indexes, so they no longer surface in ready, blocked, list, or ID resolution (and stop crowding ID-prefix matching) — while staying in git and keeping their titles in bw recap. One-way; recover via git history or bw import.

Behavior (per the design discussion)

  • Closed-only. Naming an open issue errors with a --close hint; --close closes it first.
  • Graph-safe. If open work still depends on an issue (it blocks an open issue, or has open children), archive refuses and lists them, unless --detach severs those edges (dependents lose the blocker, open children are orphaned — mirroring delete). Closed dependents need no --detach and are cleaned up automatically.
  • Date sweep. bw archive --before <cutoff> archives every closed issue whose closed_at precedes a past cutoff (2026-01-01, 6 weeks, last monday, …) via resolveDateBeforeNow. Previews by default; --force commits; issues with open work are skipped unless --detach.
  • No ID recycling. Archived IDs are excluded from generateID and explicit---id validation.

How it's built

  • Store (internal/issue/archive.go): Archive(id, {Close, Detach}), ArchiveCheck (non-mutating preview), ArchivedIssue, ClosedBefore; typed NotClosedError / ArchiveBlockedError; new Issue.ArchivedAt.
  • Intent (internal/intent): archive <id> [--close] [--detach] verb + replayArchive. Bulk sweep emits one concrete archive <id> line per ticket (never a date expression) for deterministic replay.
  • Recap: storeLookup.Title falls back to archive/ so historical recaps keep titles.

Tests (TDD)

Store, intent-replay, and command layers each got tests written first (red → green). Beyond units, verified end-to-end against a built binary: clean archive, open-dependent refusal + --detach, --close, --before preview/force, recap title retention, and — the key property — bw sync conflict convergence: a second clone's local create rebased/replayed cleanly on top of another clone's archive, with the archived issue gone from the live list and the new work preserved. Full module suite + go vet green.

Ticket: beadwork-2dx

…ork-2dx)

Adds `bw archive`, which moves closed issues into an archive/ tree on the
beadwork branch. Archived issues leave the live ID space and the
status/labels/blocks indexes — so ready, blocked, list, and ID resolution
skip them and ID-prefix matching stays uncrowded — while remaining in git
and keeping their titles in recap.

Store (internal/issue/archive.go):
- Archive(id, {Close, Detach}) moves issues/<id>.json -> archive/<id>.json,
  freezes status=closed, stamps archived_at, removes status/labels/blocks
  markers, and detaches the dependency graph (mirrors Delete's cleanup).
- Refuses non-closed issues (*NotClosedError) unless Close; refuses issues
  with open dependents/children (*ArchiveBlockedError) unless Detach.
- ArchiveCheck (non-mutating preview), ArchivedIssue (exact-id read),
  ClosedBefore(cutoff) for the date sweep. Adds Issue.ArchivedAt.
- Archived IDs are excluded from generateID and validateExplicitID, so
  they are never recycled (would break recovery).

Intent (internal/intent): `archive <id> [--close] [--detach]` verb +
replayArchive, so the operation converges through bw sync conflicts. The
bulk sweep emits one concrete `archive <id>` line per ticket (never a date
expression) for deterministic replay.

Command (cmd/bw/archive.go): `bw archive <id>...` executes directly;
`bw archive --before <cutoff>` sweeps closed issues whose closed_at
precedes a past date (via resolveDateBeforeNow), previewing by default and
committing with --force, skipping issues with open work unless --detach.

Recap title lookup falls back to archive/ so historical recaps keep titles.
One-way; recovery via git history or bw import. Docs + CHANGELOG updated.
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