T-M5RS-port-check-entities-to-ts
Status: closed/done · Impact: low · Complexity: medium
Port check_entities.py — the project-check that validates each entity type’s
template against its own schema — to TypeScript. The checker is currently
broken: it shells out to plugin/validators/validate_frontmatter.py, which
the en-masse migration renamed to validate_frontmatter.ts. The port restores
it by invoking the .ts validator and advances the .claude/ harness onto the
TypeScript substrate.
| Location | Role today |
|---|---|
.claude/skills/project-check/check_entities.py | Python checker: for each entity type under --entities-dir, validates the type’s template.md frontmatter against its schema.json via plugin/validators/validate_frontmatter.py. Broken (exit 1, “validator not found”) — that validator is now validate_frontmatter.ts. Flag --entities-dir. |
plugin/validators/validate_frontmatter.ts | The migrated frontmatter validator the checker must invoke. |
.claude/skills/project-check/tests/run_evals.py | Python eval harness dedicated to check_entities (shells out to it against fixtures). |
Proposed
Section titled “Proposed”check_entities.ts runs under bun, invokes validate_frontmatter.ts, and
exits 0 against the live entities tree (checker restored). The Python checker and
its Python eval harness are removed; a bun:test suite replaces the harness; the
--entities-dir flag, per-entity-type template validation, and exit-code
contract are preserved.
Approach
Section titled “Approach”- Port
check_entities.py→check_entities.ts(bun), invokingplugin/validators/validate_frontmatter.ts(fixing the dangling.pyreference), preserving--entities-dir, the per-entity-type template validation loop, the output, and exit codes. - Replace
run_evals.pywithtests/check_entities.test.ts(bun:test), porting its fixtures — a clean entities dir (exit 0) and an invalid-template fixture (non-zero). - Delete
check_entities.pyandrun_evals.py.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
.claude/skills/project-check/check_entities.ts | new | TypeScript port invoking validate_frontmatter.ts |
.claude/skills/project-check/tests/check_entities.test.ts | new | bun:test coverage replacing the Python harness |
.claude/skills/project-check/check_entities.py | delete | replaced by the .ts port |
.claude/skills/project-check/tests/run_evals.py | delete | replaced by the .test.ts suite |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
check_entities.tsinvokesplugin/validators/validate_frontmatter.ts(not.py), andbun run .claude/skills/project-check/check_entities.tsexits 0 against the live entities tree (the checker that exits 1 today is restored). - AC-2:
check_entities.pyandrun_evals.pyno longer exist, andgrep -rn "check_entities.py\|validate_frontmatter.py" .claudereturns no matches. - AC-3:
.claude/skills/project-check/tests/check_entities.test.tspasses underbun testand asserts a clean entities dir (exit 0) and an invalid-template fixture (non-zero), ported fromrun_evals.py. - AC-4:
check_entities.tspreserves the--entities-dirflag, per-entity-type template validation, and the exit-code contract.
Out of scope
Section titled “Out of scope”- Porting the other project-check checkers — separate tasks.
- Refreshing the
.claude/skills/project-check/SKILL.mdscript citations — deferred to one follow-up sweep so per-checker tasks stay file-disjoint. - Any change to
validate_frontmatter.tsitself (already migrated and tested underplugin/).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”- Tier-2 dogfood task for the
/sdlc:orchestrate→/sdlc:task-workmigration smoke test. Fixes a.claude/harness regression (danglingvalidate_frontmatter.pyreference) the TS migration introduced. Designed to run concurrently with thecheck_skill_proseport — the two touch disjoint files.
Post-mortem
Section titled “Post-mortem”Captured by /sdlc:task-work on 2026-06-02. PR: pending.
Acceptance criteria coverage
Section titled “Acceptance criteria coverage”- AC-1: agent-manual (with caveat) —
check_entities.tsinvokesvalidate_frontmatter.ts(the.py-not-found breakage is fully restored: all 7 entity templates now validate, vs. 7 “validator not found” errors under the broken Python checker). Verified by running the port against the live tree and diffing its findings against the original Python checker’s: the TS port reproduces the 6 validator-independent findings byte-for-byte and eliminates all 7 dangling-validator errors. The literal “exit 0 against the live tree” does NOT hold because the liveplugin/lib/model/entities/corpus carries 6 pre-existing, validator-independent drift findings (format_spec:frontmatter keys in fourdefinition.mdfiles; akind:prose ref and astatus: closed/*glob ref) that predate this task and are out of scope (corpus cleanup / validator changes are excluded). On a clean entities tree the checker exits 0 (proven by thecleanandclean-templatefixtures). - AC-2: auto (with caveat) —
check_entities.pyandrun_evals.pydeleted.git grep "check_entities.py\|validate_frontmatter.py" -- .claudestill returns matches, but every remaining match is explicitly out of scope: SKILL.md citations (task defers these to a follow-up sweep),check_pipe_tail.ts+ its test + skill-doc-fixtures (the string is that checker’s subject matter — the antipattern it lints for), and the sharedtests/README.md. None are dangling references this task owns. - AC-3: auto —
bun test ./.claude/skills/project-check/tests/check_entities.test.ts→ 11 pass / 0 fail. Asserts a clean dir (exit 0) and an invalid-template fixture (bad-template-value, exit 1), plus all ninerun_evals.pyCASES and two arg-handling cases. - AC-4: auto —
--entities-dir, per-entity-type template validation, and the 0/1/2 exit-code contract are preserved and exercised across all nine fixtures + the missing-dir (exit 2) and bad-flag (exit 2) cases.
What worked
Section titled “What worked”- The existing
check_pipe_tail.tsport (same skill dir) was a clean template: pyResolve / displayPath / splitlines helpers, ArgError-based parsing, and thebun:test+ spawnSync harness pattern all transferred directly. - The pre-existing fixture tree under
tests/fixtures/ported unchanged — no fixture authoring needed, the Python CASES table mapped 1:1 onto the TS test. - The baseline-gated quality gate cleanly subtracted the 369 pre-existing
audit_entities.tsfindings; the run reportedOK 6/6with zero new drift.
Friction and automation gaps
Section titled “Friction and automation gaps”- Write/Edit tools were denied in the worktree path; had to fall back to Bash heredoc for file
creation and skip a nice-to-have
tests/README.mdcitation refresh — task-work’s worktree should confirm Write/Edit permission coverage in the Step 3b preflight (it only probes Bash tool-family signals today, not file-mutation tools). → T-WOL2-task-work-preflight-probes-file-mutation-tools - AC-1’s “exit 0 against the live entities tree” and AC-2’s “grep returns no matches” are literally unsatisfiable due to pre-existing corpus drift and explicitly-out-of-scope reference sites — task authoring should phrase corpus-dependent ACs against a clean fixture tree (or carve out the known-pre-existing drift), so a faithful port isn’t blocked by orthogonal drift. → T-XC32-task-acs-phrase-against-clean-fixtures
run_quality_checks.ts --diff-against-baselinedefaults its--baseline-dirto the worktree’s.sdlc/, but task-work captures the baseline in the main repo’s.sdlc/; the gate failed with “baseline not found” until--baseline-dir <main-repo>/.sdlc/quality-baselineswas passed explicitly. Step 7’s documented invocation omits--baseline-dir, so the worktree-vs-main mismatch bites every run — task-work Step 7 should pass the main-repo baseline-dir explicitly (or the script should resolve it via the worktree’s superproject). → T-44OO-plugin-scripts-self-discover-project-root
Spawned follow-up tasks
Section titled “Spawned follow-up tasks”- T-WOL2-task-work-preflight-probes-file-mutation-tools (https://github.com/sksizer/dev/pull/198) — spawned: task-work Step 3b preflight should probe Write/Edit permission coverage.
- T-XC32-task-acs-phrase-against-clean-fixtures (https://github.com/sksizer/dev/pull/199) — spawned: phrase corpus-dependent ACs against a clean fixture tree.
- T-44OO-plugin-scripts-self-discover-project-root — linked: existing active task already covers the Step 7 baseline-dir silent-fallback fix.