Files
msd-core/docs/features/task-content-resolution-seam.md
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

2.8 KiB

id, title, group
id title group
3970 Per-Task External-Tracker Content-Resolution Seam v1.7.0 Features

Purpose: Let a capability declare that an external issue tracker — beads, Linear, Jira, GitHub Issues — owns a task's content (<action>/<verify>/<acceptance_criteria>/ <read_first>/<done>), not just its status, so execute-plan.md can resolve that content from the tracker at execution time instead of reading it inline out of PLAN.md.

What changed (ADR-3646, #3970):

  • A new optional feature-body manifest field, taskContentResolver, declares a trackerPrefix (matched against a task's <task tracker-id="beads:MSD-42"> attribute — everything before the first :) and a bounded invoke (binary, args carrying the {{id}} placeholder, timeoutMs).
  • execute-plan.md's per-task loop gains one new, unconditional call before that task's read_first gate: msd_run task resolve-content --plan <path> --task-id <tracker-id> --raw. A task with no tracker-id attribute is unaffected — the call is only made when the attribute is present, and resolves instantly to a no-op for every project that declares none.
  • The safety property is a real process exit code, not a prose dispatch. No capability registered for the tracker, or resolution succeeds with empty content, exits 0 with resolved: false and falls back to inline PLAN.md — the one legitimate pre-migration boundary case. Resolution succeeding with non-empty content exits 0 with resolved: true and its content supersedes the task's inline fields for every downstream gate in the execute step. A resolver that is declared but fails — tracker unreachable, id not found, timeout, malformed JSON — makes task resolve-content itself exit non-zero, which execute-plan.md treats as a hard halt: stop, surface the tracker-id/prefix/stderr, never fall back to stale PLAN.md content.
  • execute:task is a new dispatch shape below wave granularity, deliberately not one of the 12 existing loop extension points (discuss:pre … ship:post) and not routed through msd_run loop render-hooks <point> / activeHooks. It exists because the existing step/gate prose-dispatch mechanism cannot deliver a hard-halt guarantee while dispatch reliability at that layer is an open concern (#3647) — see ADR-3646's Context and Rejected Alternatives for the full reasoning.

See Develop a task-content resolver capability for the authoring walkthrough, Capability manifest → taskContentResolver for the field reference, and loop-hook-dispatch.md for how execute:task differs from the twelve prose-dispatched points.