T-YQMJ-bump-task-schema-v4-add-prs-and-status-cache-semantics
Status: closed/done · Impact: medium · Complexity: small
Slice 4a of E0002 retires status: in-progress as the authoritative claim — the lease ref at
refs/sdlc/tasks/<id> is. This task adds an optional prs: array of merged-PR URLs (the Obsidian
affordance from the slice-4a Shape C discussion) and tightens the status: description to name the
lease ref as the authoritative claim. The schema bump is the foundation for the other two slice-4a
tasks: the writers (T-KPOU-task-work-writes-pr-url-to-prs-at-open and
T-TEJX-task-close-out-verifies-prs-against-merged-pr) need prs: declared before they can
populate it.
| Location | Role today |
|---|---|
plugin/entities/task/schema.json | v3 schema; status: description doesn’t reflect protocol cache semantics; no prs: property. |
plugin/entities/task/migrations/v2-to-v3.py | Body-aware v2→v3 migration; template for the new stamp-only v3→v4. |
plugin/entities/task/migrations/v1-to-v2.py | Single-arg migrate(fm) -> new_fm template (the simpler shape v3→v4 will use). |
plugin/lib/lease/reconcile.py#detect_tasks_in_progress_without_lease | Read-side enforcement of “status is a cache, lease is the claim” (slice 3). |
plugin/conventions/schema-bump-checklist.md | Schema-bump procedure consulted by /sdlc:task-new and the migration skill. |
Proposed
Section titled “Proposed”The task entity schema declares prs: as an optional array of full PR URL strings (type: string,
format: uri, uniqueItems: true) at the top level. The status: field’s description retains its
current four-majors prose and appends: “Under the GitHub Ref Leases protocol (see
docs/planning/decisions/github-ref-leases/), this field is a workflow cache — the lease ref at
refs/sdlc/tasks/<id> is the authoritative claim. Reconcile flags any in-progress task without a
matching lease ref.” Schema version is bumped from 3 to 4. A v3-to-v4.py migration (single-arg
shape, like v1-to-v2.py) stamps schema_version: "4" on active tasks; no body changes, no field
shape changes. After running /sdlc:entities-migrate task, every active task in
docs/planning/tasks/ carries the new stamp.
Approach
Section titled “Approach”- Edit
plugin/entities/task/schema.json: bumpversion: 3→version: 4; append the cache-semantics sentence to thestatus:description; addprs:as{type: array, items: {type: string, format: uri, minLength: 1}, uniqueItems: true}.additionalProperties: falseautomatically rejects undeclared properties — addingprs:as a declared property is the explicit allow. - Create
plugin/entities/task/migrations/v3-to-v4.pywith a single-argmigrate(fm: dict) -> dictthat returns a fresh dict withschema_version: "4"stamped (no body changes — match the v1-to-v2.py signature, not v2-to-v3.py’s body-aware shape). - Create
plugin/entities/task/migrations/test_v3_to_v4.pycovering: stamp on a v3 task; idempotent stamp on a v4 task; preserves every other field; rejects non-dict input. Mirror thetest_v1_to_v2.pystructure. - Run the existing schema audit:
plugin/validators/validate_frontmatter.pyagainst a few sample tasks to confirmprs:validates when present and is omitted-OK. - Update
plugin/conventions/schema-bump-checklist.mdif it cites v3 as the current shape (sanity check only — the checklist should be schema-agnostic). - Run
/sdlc:entities-migrate task(against the project root, with--apply) to stamp every active task indocs/planning/tasks/toschema_version: "4". This bulk commit is part of the same PR. Closed tasks are skipped by default; that’s correct (they’re historical).
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
plugin/entities/task/schema.json | modify | bump version 3→4; tighten status description; add prs: array property |
plugin/entities/task/migrations/v3-to-v4.py | new | single-arg migrate(fm) → new_fm that stamps schema_version “4” |
plugin/entities/task/migrations/test_v3_to_v4.py | new | unit tests for the v3→v4 transform |
docs/planning/tasks/ | modify | bulk schema_version stamp via /sdlc:entities-migrate (one commit covering all active task files) |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
plugin/entities/task/schema.jsonreports"version": 4and includes a top-levelprs:property;additionalProperties: falsestill passes against the existing audit. - AC-2:
from migrations.v3_to_v4 import migrate; migrate({"schema_version": "3", "status": "open/ready"})returns a fresh dict withschema_version: "4"and every other field preserved. - AC-3:
validate_frontmatter.pyaccepts a task file withprs: ['https://github.com/sksizer/dev/pull/132']and rejects malformed shapes (non-array; non-string items). - AC-4: After running
/sdlc:entities-migrate task, every active (non-closed) task underdocs/planning/tasks/carriesschema_version: "4". Closed tasks are untouched. - AC-5:
plugin/entities/task/schema.json’sstatus:description namesrefs/sdlc/tasks/<id>as the authoritative claim. - AC-6: All existing tests pass; project quality checks pass.
Out of scope
Section titled “Out of scope”- Populating
prs:for any task — that’s T-KPOU-task-work-writes-pr-url-to-prs-at-open (PR-open) and T-TEJX-task-close-out-verifies-prs-against-merged-pr (close-out). - Renaming or restructuring
status:enum values. Shape C keeps the existing enum; only the description tightens. - Backfilling
prs:for historical closed tasks. Would require git log spelunking; deferred until a use case demands it. - Changes to the lease library, reconcile detectors, or any skill beyond the schema + migration + bulk stamp.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Slice 4a of T-FFHN-github-ref-leases-coordination (GitHub Ref Leases). Chosen Shape: Shape C
from the slice-4a design discussion — lifecycle-only status field + prs: list for Obsidian
visibility, with 3 main commits per task lifecycle (claim, PR-open, close-out). The schema bump is
the foundation; Tasks B and C populate the new field. Reconcile’s read-side enforcement of “status
is a cache” already ships (slice 3, detect_tasks_in_progress_without_lease); this task tightens
the schema to match.