Skip to content

T-YYZU-moon-yml-schema-depth-check

Status: open/ready · Impact: medium · Complexity: small

AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-07-20 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.

A directory move left moon.yml files pointing at $schema paths whose relative depth no longer resolved. Moon itself ignores $schema, so nothing failed — editor validation just stopped working, silently. This task adds a depth-aware check so a future move cannot re-break it without a loud failure.

After T-C9RD’s directory move, 12 moon.yml files carried $schema paths with stale relative depths (e.g. ../../.moon/cache/schemas/project.json pointing one level too shallow). Harmless to moon itself, which ignores $schema, but editor validation silently died with no error anywhere. Add a depth-aware $schema check that walks every moon.yml in the repo, resolves its $schema relative path against the file’s own location, and fails with file:line citations when the target does not exist. Wire it into the existing project-check pre-commit family in lefthook.yml alongside project-check-identifier-shape.

— from T-C9RD-consolidate-augmented-into-solutions

LocationRole today
.moon/workspace.ymlThe one and only moon workspace root in this repo. find . -name .moon -type d returns exactly ./.moon, so every moon.yml in the tree belongs to this single workspace.
.gitignoreIgnores .moon/cache/ — moon’s generated cache, where the fetched schemas/project.json lands. The directory is absent in a fresh checkout and in CI.
packages/ts/obsidian-astro/moon.ymlCarries $schema: '../../.moon/cache/schemas/project.json' at a 3-deep location, resolving to packages/.moon/... — one level too shallow.
solutions/determined/apps/vault-engine/moon.ymlOne of the eight determined moon.yml files whose too-shallow 2-hop $schema was corrected to ../../../../ by PR #1175’s migration commit — the depth drift this task guards against has now happened (T-C9RD) and been hand-fixed (#1175) once each; nothing automated prevents a third round.
solutions/augmented/apps/learn_web/moon.ymlA 4-deep project whose $schema depth is correct (../../../../), showing the intended shape at that depth.
solutions/augmented/apps/augmented_web/moon.ymlUses the remote https://moonrepo.dev/schemas/project.json form instead of a relative path — a shape the check must tolerate, not flag.
solutions/augmented/apps/vimit_prototype/moon.ymlHas no $schema: key at all — the other shape the check must tolerate.
.claude/skills/project-check/Home of the deterministic project-check scripts. No script inspects moon.yml today.
.claude/skills/project-check/check_identifier_shape.tsAdapter-shaped check (thin wrapper over a lib op) — the pattern used when the capability belongs in the SDLC substrate.
.claude/skills/project-check/check_pipe_tail.tsSelf-contained check (all logic in-script, --skills-dir override for fixtures) — the pattern used for repo-local lints.
.claude/skills/project-check/tests/check_pipe_tail.test.tsbun:test suite that builds an ephemeral fixture tree under tmpdir() and shells the checker at it. The template for new check tests.
.claude/skills/project-check/SKILL.mdDocuments each check (a ### N. description block plus a ### Step N invocation block) and lists the commit-time scripts in its intro paragraph.
lefthook.ymlDeclares the project-check-* pre-commit family. Each entry is a comment block plus a run: line; lefthook aborts on the first non-zero exit.

A self-contained deterministic check, check_moon_schema_paths.ts, that walks every moon.yml in the repo, resolves each relative $schema value against the file’s own directory, and fails with file:line citations when the normalized result is not the workspace-root .moon/cache/schemas/project.json. Wired into the project-check-* pre-commit family in lefthook.yml, with the one still-stale path (packages/ts/obsidian-astro/moon.yml) fixed in the same change so the gate is green on landing. (The eight determined files this task originally listed were fixed by PR #1175’s migration commit.)

The check compares normalized paths, not on-disk existence. .moon/cache/ is gitignored, so the schema target is absent in a fresh checkout and in CI — an existence check would fail on all 29 currently-correct files. Normalizing the relative path and comparing it to the known workspace-relative target catches exactly the depth drift this task is about, and does so without requiring moon sync to have run.

  1. Add .claude/skills/project-check/check_moon_schema_paths.ts, a self-contained bun script following the check_pipe_tail.ts shape (all logic in-script, no lib op). This is a repo-infrastructure lint about the moon workspace, not an SDLC entity concern, so it stays a dev-repo self-lint like apps/sdlc/scripts/check_command_seam.sh rather than becoming an sdlc op — the op registry is the consumer API.
  2. Give it a --root <dir> flag defaulting to the repo root (resolved from import.meta.url, as check_identifier_shape.ts does) so tests can point it at an ephemeral fixture tree.
  3. Walk the root for files named moon.yml, pruning node_modules and .git. Read each and find the first line matching ^\$schema:\s*(.+)$, recording the 1-based line number. Strip surrounding single or double quotes from the value.
  4. Classify each value:
    • No $schema: line → skip, not a violation.
    • Value matching ^https?:// → skip, not a violation.
    • Otherwise → resolve: join the moon.yml’s root-relative directory with the value, normalize away . and .. segments, and compare to the literal .moon/cache/schemas/project.json.
  5. On mismatch, record a violation carrying the root-relative file path, the line number, the declared value, and the normalized result. Also flag a value that normalizes above the root (leading .. survives normalization) with the same violation shape.
  6. Emit the expected replacement value per violation — ../ repeated once per path segment of the file’s directory, or ./ for the root moon.yml — so the failure message is directly actionable.
  7. Print Moon $schema paths: OK and exit 0 when clean; print one FAIL <path>:<line>: ... line per violation followed by a N moon.yml $schema violation(s) summary and exit 1 otherwise. Exit 2 on an internal error (unreadable root), matching the family’s convention.
  8. Fix the one remaining stale $schema value: packages/ts/obsidian-astro/moon.yml (../../../../../). The eight determined files this task originally listed were already corrected to ../../../../ by PR #1175’s migration commit. Without this fix the new gate blocks every subsequent commit.
  9. Add .claude/skills/project-check/tests/check_moon_schema_paths.test.ts modeled on check_pipe_tail.test.ts: build an ephemeral tree under mkdtempSync(join(tmpdir(), ...)), write moon.yml fixtures, shell the checker with --root, assert exit codes and output substrings. Cover the correct-depth, too-shallow, too-deep, root-./, remote-URL, and no-$schema cases.
  10. Register the check in .claude/skills/project-check/SKILL.md: add a ### 1h. moon.yml $schema depth (deterministic) description block after the ### 1g. block, add a matching ### Step 1h invocation block after Step 1g, and add check_moon_schema_paths.ts to the commit-time script list in the intro paragraph.
  11. Add a project-check-moon-schema-paths: entry to the pre-commit job list in lefthook.yml, alongside project-check-identifier-shape, with a comment block explaining the normalized-path (not existence) semantics and run: bun run .claude/skills/project-check/check_moon_schema_paths.ts.
LocationKindChange
.claude/skills/project-check/check_moon_schema_paths.tsnewThe depth-aware $schema checker: walk, resolve, compare, cite, exit 0/1/2.
.claude/skills/project-check/tests/check_moon_schema_paths.test.tsnewbun:test suite over ephemeral moon.yml fixtures via --root.
lefthook.ymlmodifyAdd project-check-moon-schema-paths: to the pre-commit project-check-* family.
.claude/skills/project-check/SKILL.mdmodifyAdd the ### 1h. check description, the ### Step 1h invocation block, and the script name in the intro roster.
packages/ts/obsidian-astro/moon.ymlmodify$schema ../../../../../. (The eight determined moon.yml fixes originally listed here landed via PR #1175’s migration commit.)
  • AC-1: bun run .claude/skills/project-check/check_moon_schema_paths.ts exits 0 and prints Moon $schema paths: OK against the repo after the packages/ts/obsidian-astro/moon.yml fix lands.
  • AC-2: Reverting packages/ts/obsidian-astro/moon.yml back to its ../../ value (or setting any correct-depth moon.yml, e.g. solutions/determined/apps/vault-engine/moon.yml, too shallow) makes that same command exit 1 and print a FAIL <path>:<line> line naming that file, its line number, the declared value, and the expected replacement.
  • AC-3: grep -rn --include=moon.yml -F '$schema' . (excluding node_modules) shows every relative value normalizing to .moon/cache/schemas/project.json when resolved against its own file’s directory.
  • AC-4: The checker exits 0 on a fixture tree whose only moon.yml has $schema: 'https://moonrepo.dev/schemas/project.json', and 0 on a fixture tree whose only moon.yml has no $schema: line — matching the live solutions/augmented/apps/augmented_web/moon.yml and solutions/augmented/apps/vimit_prototype/moon.yml shapes.
  • AC-5: The checker exits 0 on the repo while .moon/cache/ does not exist on disk, demonstrating the check does not depend on moon sync having run.
  • AC-6: bun test ./.claude/skills/project-check/tests/check_moon_schema_paths.test.ts exits 0, and the suite contains a case for each of: correct depth, too-shallow, too-deep, root ./ form, remote URL, and absent $schema.
  • AC-7: lefthook.yml contains a project-check-moon-schema-paths: entry under pre-commit whose run: invokes bun run .claude/skills/project-check/check_moon_schema_paths.ts, and lefthook run pre-commit exits 0 on the clean tree.
  • AC-8: .claude/skills/project-check/SKILL.md names check_moon_schema_paths.ts in its commit-time script roster, in a ### 1h. description block, and in a ### Step 1h invocation block.
  • Creating .moon/cache/schemas/project.json or un-gitignoring .moon/cache/.
  • Adding a $schema: key to moon.yml files that omit it (solutions/augmented/apps/vimit_prototype/moon.yml) — absence stays tolerated.
  • Rewriting solutions/augmented/apps/augmented_web/moon.yml from the remote URL form to the relative form.
  • Validating moon.yml content against the schema; this check verifies the pointer resolves, not that the document conforms.
  • Extending the check to .moon/workspace.yml, .moon/toolchains.yml, or .moon/tasks/*.yml.
  • Any equivalent $schema depth check for non-moon YAML or JSON in the repo.
  • none

Spawned by /sdlc:spawn-task-pr on 2026-07-20 UTC from T-C9RD-consolidate-augmented-into-solutions in https://github.com/sksizer/dev.


← Back to Tasks