Skip to content

feat: add first-class milestone dimension - #7

Merged
budhash merged 2 commits into
mainfrom
feat/milestone-support
Jul 1, 2026
Merged

budhash merged 2 commits into
mainfrom
feat/milestone-support

Conversation

@budhash

@budhash budhash commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a first-class milestone dimension so work rolls up to "how close is milestone M<n>?" — while staying 100% backward-compatible with existing TASKS.md files and with projects that don't use milestones. Implements the acceptance spec (taxjot/docs/process/tasks-milestone-spec.md).

What's new

  • @milestone=<id-or-alias> tag on any feature/task line (mirrors @branch=/@deps=). Absent ⇒ implicit sentinel bucket (default, configurable via TASKS_MILESTONE_SENTINEL; rejected if it looks like an M<n> id, to avoid set --milestone m1 ambiguity). The sentinel is never written to task lines.
  • Optional # Milestones registry (its own H1 section) mapping id → alias → status → title. Present ⇒ alias resolution (@milestone=alpha ≡ @milestone=m1) + rich rollups; absent ⇒ freeform (grouped by raw value).
  • CLI: new … --milestone, set T-N --milestone ("" clears to sentinel), list --milestone, next --milestone, a milestone rollup, milestone <id> detail, milestone --table (milestone × features × status), and migrate-tags-to-milestone <tag> for the interim @tags=<id> convention. show displays a resolved Milestone: line.
  • validate warns (exit 0) on an unknown @milestone= when a registry exists; never hard-fails on milestone data.
  • Orthogonal to @system=/@tags= — @system is not overloaded.

Backward compatibility (hard requirement)

  • Verified byte-for-byte round-trip against taxjot's real 198-line TASKS.md (no milestone data): validate passes, file unchanged, next/list/tree unchanged.
  • taxjot already uses the interim @tags=m1 on 6 tasks; migrate-tags-to-milestone m1 converts them cleanly, preserving their other tags.

Testing

  • TDD: 10 new e2e scenarios (31–40) covering the spec's 7 acceptance criteria plus migration, existing-feature assignment, and the table view.
  • make check green: py_compile + 204 e2e assertions, 0 failures. Python 3.8-safe, zero new dependencies, single file.

Re-vendoring note

Version bumped 1.0.1 → 1.1.0. Sister projects pick this up via tasks selfupdate, then run migrate-tags-to-milestone <id> to move any interim @tags=<id> onto @milestone=<id>.

budhash added 2 commits July 1, 2026 14:45
Add an optional @milestone=<id-or-alias> tag plus an optional # Milestones
registry so work can be tagged and rolled up by milestone — without breaking
existing TASKS.md files or forcing milestones on projects that don't want them.

- Opt-in and backward-compatible: with no milestone data the tool behaves
  exactly as before; untagged items resolve to an implicit sentinel bucket
  (default, configurable via TASKS_MILESTONE_SENTINEL, never an M<n> id). The
  sentinel is never written to task lines, so old files round-trip byte-for-byte.
- Optional # Milestones registry maps id -> alias -> status -> title, powering
  alias resolution (@milestone=alpha == @milestone=m1) and rollups; absent =>
  freeform (grouped by raw value).
- CLI: new/set --milestone (set "" clears to the sentinel), list --milestone,
  next --milestone, a `milestone` rollup + `milestone <id>` detail +
  `milestone --table` (milestone x features x status), and
  migrate-tags-to-milestone for the interim @tags=<id> convention. `show` now
  displays a resolved Milestone line; features and tasks can both carry a
  milestone (assign existing features with `set F-N --milestone`).
- validate warns (exit 0) on an @milestone= value not in the registry when a
  registry exists; never hard-fails on milestone data.
- 10 new e2e scenarios covering the spec's 7 acceptance criteria plus migration,
  feature assignment, and the table view. Docstring/schema/README/CHANGELOG
  updated; version 1.0.1 -> 1.1.0.
Address findings from the PR review of the milestone dimension:

- migrate-tags-to-milestone no longer silently drops a milestone. A task with a
  CONFLICTING existing @milestone= is left untouched and reported (not stripped
  and mis-counted as migrated — that was silent data loss). A redundant tag for
  the same milestone is dropped. The helper now validates its argument, refuses
  the sentinel, and prints a distinct message when nothing matched.
- milestone rollup/detail now group case-insensitively, matching the list/next
  filters, so freeform @milestone=Alpha and `milestone alpha` agree.
- validate now audits registry health (duplicate ids, colliding aliases,
  unparseable entries) as warnings.
- new/set --milestone print a non-fatal warning when assigning a value absent
  from an existing registry, so a typo (e.g. m11) is caught at assignment time
  rather than only by a later validate warning.
- milestone errors on ambiguous `milestone <id> --table` / extra positionals;
  cmd_list pre-initializes its locals; new and set agree on the clear tokens
  ("", clear, or the sentinel name).
- Docs: fix the misleading "alias resolves to its id" example (values are stored
  verbatim, resolved on read), align "clears to sentinel" wording, change
  "may not" -> "must not" for the sentinel guard, and document the clear tokens
  and registry-health warnings.
- Tests: 7 new scenarios (41-47) — clear-via-default/clear, freeform no-warn,
  migrate tag-removal + conflict preservation, zero-task registry milestone,
  alias case-insensitivity, --table row-association, and registry-health warnings.
@budhash
budhash merged commit 0654ea4 into main Jul 1, 2026
5 checks passed
@budhash
budhash deleted the feat/milestone-support branch July 1, 2026 22:40
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