T-DPO2-ensure-ready-stamps-quoted-iso-z
Status: closed/done · Impact: medium · Complexity: small
Auto-generated from a /sdlc:task-work post-mortem. Review and
promote to ready before picking up.
The readiness_verified_at schema pattern currently requires a
literal Z suffix. PyYAML’s default loader auto-parses unquoted ISO
8601 strings into Python datetime objects and re-emits them with
the explicit +00:00 offset — semantically identical to Z but
rejected by the pattern. Loosening the schema to accept both RFC
3339 forms eliminates the round-trip drift class without forcing
ensure-ready to quote-on-write or strip timezone info. Existing Z
stamps remain valid; PyYAML’s natural +00:00 output now also
validates. See T-T5RB-consolidate-task-status-enum for the
originating incident.
“PyYAML auto-parses unquoted ISO 8601 datetime strings into Python
datetimeobjects, which then round-trip as2026-05-19T21:02:01+00:00and fail the schema’sZ-only pattern — task-ensure-ready hit this on first stamp attempt and the bad value landed in a commit before validation caught up.”
plugin/entities/task/schema.json declares:
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?Z$"The strict Z requirement is the constraint that makes PyYAML’s
natural output invalid. Both Z and +00:00 mean UTC; the schema
treats them as different.
Proposed
Section titled “Proposed”Loosen the readiness_verified_at pattern to accept any RFC 3339
UTC suffix: Z, +00:00, or -00:00. The pattern becomes:
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]00:00)$This matches both forms with zero impact on the rest of the contract. Ensure-ready stays simple — it writes whatever PyYAML emits, the schema accepts both.
Approach
Section titled “Approach”- Update the regex in
plugin/entities/task/schema.json(and any sibling entity schemas that carry the same pattern — at minimum audit the field acrossplugin/entities/*/schema.json). - Run the validator across the full task corpus to confirm both
already-stamped
Ztasks and any future+00:00stamps pass. - Add a fixture under
plugin/skills/task-ensure-ready/tests/that stamps a task, runs the YAML round-trip, and asserts the result validates. The fixture should exercise both literal forms so the loosened pattern is pinned against future tightening.
Files to touch
Section titled “Files to touch”plugin/entities/task/schema.json— loosen thereadiness_verified_atpattern.plugin/skills/task-ensure-ready/tests/run_evals.py— add the round-trip + both-forms regression case.
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
plugin/entities/task/schema.json’sreadiness_verified_atpattern accepts both2026-05-19T21:02:01Zand2026-05-19T21:02:01+00:00. Sibling entity schemas (epic, milestone, backlog) carrying the same pattern get the same treatment. - AC-2:
plugin/validators/validate_frontmatter.py docs/planning/tasks/*.mdexits 0 against the current corpus (which contains already-stampedZ-form values). - AC-3: A case in
plugin/skills/task-ensure-ready/tests/run_evals.pyasserts both literal forms validate afteryaml.safe_load+yaml.safe_dumpround-trip.
Out of scope
Section titled “Out of scope”- Broader datetime-handling reform across other skills. This task is narrowly the ensure-ready stamp path.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:task-work post-mortem of T-T5RB-consolidate-task-status-enum on 2026-05-19.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-05-21. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: auto —
plugin/skills/task-ensure-ready/tests/run_evals.py’s newstamp-pattern-round-tripcase asserts the schema regex accepts bothZand+00:00literals (plus fractional-second variants). Sibling-schema audit (command grepfor theZ$pattern acrossplugin/entities/*/schema.json) found only the task schema carries it, so the AC’s “sibling schemas get the same treatment” clause is vacuously satisfied — no other files need editing. - AC-2: auto —
plugin/validators/validate_frontmatter.py docs/planning/tasks/*.mdreports80/80 file(s) passedagainst the loosened schema. - AC-3: auto —
stamp-pattern-round-tripinrun_evals.pyperforms theyaml.safe_load+yaml.safe_dumpround-trip and asserts both forms validate. Full eval suite:8/8 case(s) passed.
What worked
Section titled “What worked”- The change was a one-line regex edit; the regression test pinned both the literal-form check and the PyYAML round-trip check in a single function, keeping the test surface tight.
run_quality_checks.pyran the eval suite (declared as a quality check) automatically — no separate invocation needed to confirm the new case.
Friction and automation gaps
Section titled “Friction and automation gaps”- Step 5b’s
git rebase mainsurfaced a frontmatter conflict between the on-mainstatus: open/ready → in-progressflip and the on-feat-branchreadiness_verified_atstamp refresh (both touched adjacent lines). The conflict was trivial to resolve by hand but is 100% mechanical (always the same two-field merge). A pre-rebase helper that detects “both sides touch task frontmatter only” and auto-merges the union of frontmatter edits would remove a manual step. Likely covered by existing follow-up T-H0W9-task-work-rebase-frontmatter-conflict — verify before spawning a duplicate. → T-H0W9-task-work-rebase-frontmatter-conflict - The task spec said “Sibling entity schemas (epic, milestone, backlog) carrying the same pattern get the same treatment” but no sibling schemas actually carry that pattern. Ensure-ready’s relevance check passed the spec because the cited files exist, but the AC’s universal-quantifier shape wasn’t sanity-checked against the codebase. A relevance-check enhancement that flags ACs-with-implicit-existence-claims (“sibling X also has Y”) and asks the author to confirm before stamping ready would prevent shipping ACs that are vacuous. → T-PCJB-task-ensure-ready-flags-vacuous-universal-acs
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-PCJB-task-ensure-ready-flags-vacuous-universal-acs — new task: ensure-ready disqualifies ACs with unverified universal-quantifier phrasing.
- T-H0W9-task-work-rebase-frontmatter-conflict — linked existing: covers the rebase-frontmatter-conflict friction observed in this run.