003 — tp story: number, scaffold, and file a story's issue (#23)

Status: shipped (v0.2.1)

Why

Running stories 001 and 002 by hand repeated the same mechanical steps each time: find the next number, copy the template from docs/method.md, then create the forge issue from the story's title and first paragraph and write (#N) back into the heading. Those steps are identical in every project and easy to get subtly wrong (a skipped number, an issue body that drifts from the file), so they belong in task-plus. tp issue now exists to do the forge half.

What changes

  • New command tp story with two subcommands:
    • new TITLE — writes docs/stories/NNN-slug.md from the method's story template, NNN one above the highest existing number (001 in an empty or missing directory), status proposed. Prints the path.
    • issue NNN — creates the forge issue from the story file and stamps (#N) onto the file's heading. Prints #N url.
  • The issue is titled Story NNN: <title>; its body is the first paragraph of Why and a link to the file on the release remote's forge (<web>/<owner>/<repo>/src/branch/<current branch>/<path>). Forge and token come from tp issue's resolution.
  • The template is embedded in tp; docs/method.md stays the description of it. New internal/story package; docs page docs/story.md; README row.

Acceptance

new TITLE, given the files in docs/stories/:

Existing stories TITLE Writes
none, or no directory First thing 001-first-thing.md
001-a.md, 003-b.md Next 004-next.md
001-a.md, notes.md, 002-b.html Next 002-next.md (only NNN-*.md count)
any `tp foo`: do X & Y! slug tp-foo-do-x-y
any a title slugging past 50 characters slug cut at a word boundary, ≤ 50
any empty, or nothing sluggable error, nothing written

The written file has heading # NNN — TITLE, **Status:** ready, and the template's sections (Why, What changes, Acceptance, Out of scope, Decisions, Done when).

issue NNN, given the story file:

Heading Why section Outcome
# 004 — Title has a first paragraph issue Story 004: Title, body = paragraph + link; heading becomes # 004 — Title (#N)
# 004 — Title (#12) any error: "story 004 already has issue #12"; nothing sent
# 004 — Title missing or empty error: "story 004 has no Why paragraph"; nothing sent
no story numbered 004 — error naming the directory
issue creation fails — forge error; file unchanged

Only the heading line changes; the rest of the file is byte-for-byte kept.

Out of scope

  • Closing a story's issue on release and stamping shipped (vX.Y.Z) — the roadmap's tp release item.
  • Re-syncing an issue after the story is edited, listing stories, and configurable story directories or templates.
  • tp adr.

Decisions

None: numbering, slug and issue shape follow what stories 001 and 002 did by hand.

Done when

  • tests express the acceptance tables and pass
  • spec updated (docs/story.md, README command table, docs/method.md tooling section)
  • ADR written if a fork was resolved
  • roadmap ticked and stamped; changelog entry
  • issue closed with a link to the release