Skip to content

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.

LocationRole today
plugin/entities/task/schema.jsonv3 schema; status: description doesn’t reflect protocol cache semantics; no prs: property.
plugin/entities/task/migrations/v2-to-v3.pyBody-aware v2→v3 migration; template for the new stamp-only v3→v4.
plugin/entities/task/migrations/v1-to-v2.pySingle-arg migrate(fm) -> new_fm template (the simpler shape v3→v4 will use).
plugin/lib/lease/reconcile.py#detect_tasks_in_progress_without_leaseRead-side enforcement of “status is a cache, lease is the claim” (slice 3).
plugin/conventions/schema-bump-checklist.mdSchema-bump procedure consulted by /sdlc:task-new and the migration skill.

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.

  1. Edit plugin/entities/task/schema.json: bump version: 3version: 4; append the cache-semantics sentence to the status: description; add prs: as {type: array, items: {type: string, format: uri, minLength: 1}, uniqueItems: true}. additionalProperties: false automatically rejects undeclared properties — adding prs: as a declared property is the explicit allow.
  2. Create plugin/entities/task/migrations/v3-to-v4.py with a single-arg migrate(fm: dict) -> dict that returns a fresh dict with schema_version: "4" stamped (no body changes — match the v1-to-v2.py signature, not v2-to-v3.py’s body-aware shape).
  3. Create plugin/entities/task/migrations/test_v3_to_v4.py covering: stamp on a v3 task; idempotent stamp on a v4 task; preserves every other field; rejects non-dict input. Mirror the test_v1_to_v2.py structure.
  4. Run the existing schema audit: plugin/validators/validate_frontmatter.py against a few sample tasks to confirm prs: validates when present and is omitted-OK.
  5. Update plugin/conventions/schema-bump-checklist.md if it cites v3 as the current shape (sanity check only — the checklist should be schema-agnostic).
  6. Run /sdlc:entities-migrate task (against the project root, with --apply) to stamp every active task in docs/planning/tasks/ to schema_version: "4". This bulk commit is part of the same PR. Closed tasks are skipped by default; that’s correct (they’re historical).
LocationKindChange
plugin/entities/task/schema.jsonmodifybump version 3→4; tighten status description; add prs: array property
plugin/entities/task/migrations/v3-to-v4.pynewsingle-arg migrate(fm) → new_fm that stamps schema_version “4”
plugin/entities/task/migrations/test_v3_to_v4.pynewunit tests for the v3→v4 transform
docs/planning/tasks/modifybulk schema_version stamp via /sdlc:entities-migrate (one commit covering all active task files)
  • AC-1: plugin/entities/task/schema.json reports "version": 4 and includes a top-level prs: property; additionalProperties: false still 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 with schema_version: "4" and every other field preserved.
  • AC-3: validate_frontmatter.py accepts a task file with prs: ['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 under docs/planning/tasks/ carries schema_version: "4". Closed tasks are untouched.
  • AC-5: plugin/entities/task/schema.json’s status: description names refs/sdlc/tasks/<id> as the authoritative claim.
  • AC-6: All existing tests pass; project quality checks pass.
  • 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.
  • none

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.


← Back to Tasks