Skip to content

T-M2OV-pre-merge-frontmatter-validation-gate

Status: closed/superseded · Impact: medium · Complexity: small

Auto-generated from a /sdlc:task-work post-mortem. Review and promote to open/ready before picking up.

A planning/spec PR can merge today with invalid task frontmatter — an out-of-enum status:, a missing required field — and the breakage only surfaces later when a downstream skill chokes on it. This task adds a pre-merge gate that runs validate_frontmatter.py over the entity files a PR touches so schema-invalid frontmatter is caught before merge rather than after pickup. Closing this gap removes a class of manual fix(tasks) correction commits on main. Surfaced by T-75LX-establish-plugin-lib-convention.

LocationRole today
plugin/validators/validate_frontmatter.pyValidates one or more entity files against their schema; run ad hoc by skills (task-new, task-ensure-ready, spawn-from-post-mortem) but not wired into any merge gate
.github/workflows/No CI workflow validates entity frontmatter on PRs; whatever lands in docs/planning/<type>/ merges unchecked
plugin/scripts/run_quality_checks.pyPer-task local gate run by /sdlc:task-work Step 7; runs audit_entities.py but only at task-pickup time, not as a pre-merge check on the PR itself

There is no enforcement point between “author edits a task file” and “the task file is on main.” The originating post-mortem records the failure verbatim:

Task merged (PR #106) with invalid status: open/draft (not in the schema enum) — required a manual fix(tasks) correction commit on main before pickup. A pre-merge validate_frontmatter.py gate on planning/spec PRs would have caught it before merge.

The breakage was only caught at pickup, requiring a hand-authored fix(tasks) correction commit on main before /sdlc:task-work could start.

Any PR that touches files under docs/planning/<type>/ runs validate_frontmatter.py against the touched entity files (or the full corpus) as a required check, so a schema-invalid frontmatter blocks the merge. The check reuses the existing validator unchanged — this task only wires it into a merge gate, it does not change validation rules.

  1. Decide the gate mechanism. Two candidates: (a) a GitHub Actions workflow keyed on docs/planning/** paths that runs the validator over the changed files; (b) a lefthook pre-push / pre-commit hook that does the same locally. CI is the binding gate (it runs regardless of local config); a local hook is the fast-feedback complement. Prefer CI as the required check; add the local hook only if cheap. Open decision: validate just the PR’s changed entity files (git diff --name-only origin/main...HEAD filtered to docs/planning/) vs the whole corpus. Changed-files-only avoids failing on pre-existing drift unrelated to the PR — coordinate with the drift-scoping work in T-H69K-run-quality-checks-isolates-pre-existing-drift.
  2. Implement the chosen gate, invoking validate_frontmatter.py with the resolved file list.
  3. Verify the gate fails on a fixture PR carrying an out-of-enum status: and passes on a clean one.
LocationKindChange
.github/workflows/validate-frontmatter.ymlnewCI gate running validate_frontmatter.py over a PR’s changed entity files (path-filtered to docs/planning/**)
plugin/validators/validate_frontmatter.pymodifyPossible CLI affordance to accept a changed-files list / a --changed-only mode, if not already supported
plugin/conventions/sdlc-yaml.mdmodifyDocument the pre-merge frontmatter gate alongside the existing quality-check conventions

(Workflow path and validator-flag shape are best guesses pending the Approach step 1 decision; the lefthook variant would touch lefthook.yml instead of .github/workflows/.)

  • AC-1: A PR that changes a file under docs/planning/<type>/ to carry an out-of-enum status: (e.g. open/draft) fails the gate with a non-zero exit and a message naming the offending file and field.
  • AC-2: A PR whose touched entity files all validate passes the gate.
  • AC-3: The gate runs only when the PR touches docs/planning/** (or is otherwise cheap enough to run unconditionally without slowing unrelated PRs).
  • AC-4: The gate reuses validate_frontmatter.py unchanged in its validation logic — no schema rules are duplicated in the gate definition.
  • Changing validation rules or the status enum itself. This task only adds an enforcement point for the existing rules.
  • Auto-fixing invalid frontmatter. /sdlc:entities-migrate owns mechanical fixes; this gate only blocks the merge.
  • Validating prose-section drift (missing template H2s). That’s audit_entities.py’s job; this gate is frontmatter-only.

Spawned by /sdlc:task-work post-mortem of T-75LX-establish-plugin-lib-convention on 2026-05-23.

Bullet: Task merged (PR #106) with invalid status: open/draft (not in the schema enum) — required a manual fix(tasks) correction commit on main before pickup. A pre-merge validate_frontmatter.py gate on planning/spec PRs would have caught it before merge. Keywords searched: validate_frontmatter, correction, pre-merge, required, planning, invalid, merged, status Excluded: 2026-05-23-establish-plugin-lib-convention Top candidates (score / status / headline):

  • 61 / closed/done / 2026-05-19-consolidate-task-status-enum — Consolidate task status enum and migrate existing instances
  • 57 / closed/done / 2026-05-19-build-import-planning-skill — Build /sdlc:import-planning skill — extract tasks/milestones from existing repo docs
  • 37 / closed/done / 2026-05-19-extract-task-close-out-skill — Extract task-work Step 11 into /sdlc:task-close-out skill
  • 32 / closed/done / 2026-05-19-add-obsidian-bases-setup-flag — Add —obsidian flag to /sdlc:setup that generates Obsidian Bases files per entity
  • 30 / closed/done / 2026-05-19-task-ensure-ready-accepts-in-progress — task-ensure-ready accepts in-progress when readiness_verified_at is set Decision: SPAWNED

← Back to Tasks