T-356Q-fix-guard-project-shape-baseline
State: open/ready · Impact: medium · Complexity: small
AUTO-DEFINED: this spec was best-effort machine-authored by /sdlc:task-auto-define on 2026-09-13 because the task is autonomy: autonomous/pr. Review the Goal, Approach, Today, Files-to-touch, and Acceptance-criteria carefully before trusting it.
scripts/guard-project-shape.ts is already red on main:
product-suspenders and product-system-graph match no aspect. A
pre-existing failure means the guard cannot ratchet new violations —
any new violation added alongside these is invisible. Fix the aspect
mapping (or the guard’s baseline) so the guard is green on main again
and can ratchet.
scripts/guard-project-shape.ts is already red on main (product-suspenders, product-system-graph match no aspect), so the guard cannot ratchet — pre-existing, needs its baseline updated.
— from T-4VNC-learning-p1-scaffold-solution’s post-mortem
| Location | Role today |
|---|---|
scripts/guard-project-shape.ts#ASPECT_BASELINE | The assertion-4 ratchet set: 3 layer: configuration ids plus 16 layer: application ids that match no gate-supplying moon aspect. product-suspenders and product-system-graph are absent from it, so aspectRatchetViolations reports both as new (unbaselined) violations and bun scripts/guard-project-shape.ts exits 1 on main. |
solutions/ontological/products/suspenders/moon.yml | Declares layer: 'application', stack: 'frontend', no tags:. Its own header comment already records the gap: “This product has the matching package.json scripts but no aspect of its own yet, so those three verbs are not reachable through moon here.” |
solutions/ontological/products/system-graph/moon.yml | Same shape as suspenders: layer: 'application', no tags:, no gate-supplying .moon/tasks/*.yml reaches it. |
.moon/tasks/determined-nuxt.yml | The nearest existing Nuxt-product aspect (fmt/fmt-check/lint/build/build-desktop), explicitly scoped by its own header comment to “the 24 solutions/determined/products/*” — not registered on either solutions/ontological/products/* product. |
.moon/tasks/nuxt-product.yml | The check (vue-tsc) aspect, tagged nuxt-product onto exactly three solutions/determined products by design (“Tag another product only if it ever mounts something these three do not”) — also not applicable to suspenders / system-graph today. |
Confirmed live: bun scripts/guard-project-shape.ts on this branch (same content as
main) prints exactly two violations, both assertion-4 (“matches no
gate-supplying aspect (S-0013 rule 6)”) — one for product-suspenders
(solutions/ontological/products/suspenders), one for product-system-graph
(solutions/ontological/products/system-graph). Assertions 1, 2, 3 and 5
(vocabulary rule 6/2, project metadata) are clean for both projects: each
manifest already declares format, format:check and lint with no
mutating gate, and each moon project already declares layer and stack.
Proposed
Section titled “Proposed”Add product-suspenders and product-system-graph to
scripts/guard-project-shape.ts#ASPECT_BASELINE’s layer: application group
— the same treatment the guard already gives the other 16 unaspected
application-layer projects (“CI’s affected step filters these out
(projectLayer!=application) … so ‘no aspect’ is not ‘no gate’ for them
either”). That restores bun scripts/guard-project-shape.ts to exit 0 on
main, which is what lets assertion 4 ratchet the next drift instead of
failing on a pre-existing, already-known gap every run.
This is the baseline-side fix the Goal names as an alternative to an
aspect-mapping fix. A real aspect-mapping fix — a dedicated
solutions/ontological-scoped Nuxt-product aspect mirroring
.moon/tasks/determined-nuxt.yml / .moon/tasks/nuxt-product.yml, giving
these two products fmt/fmt-check/lint/check reachable through
moon run — is real follow-on work and is deliberately left out of this task
(see Out of scope): it is a design decision (new aspect file, tag wiring,
possibly new CI steps) an order of magnitude larger than a two-entry baseline
edit, and the guard’s own docstring already treats “layer: application, no
aspect yet, CI runs it as an explicit step instead” as an accepted, tracked
category rather than a defect to eliminate on sight.
Approach
Section titled “Approach”- Confirm the current red state: run bun
scripts/guard-project-shape.ts(the same command.github/workflows/ci.yml’s “Guard — project shape conforms to the task vocabulary” step andmoon.yml’sroot:guard-project-shapetask both run) and verify it prints exactly the two violations named in Today, with no other assertion failing for either project. - In
scripts/guard-project-shape.ts#ASPECT_BASELINE, add'product-suspenders'and'product-system-graph'to thelayer: applicationgroup, in alphabetical order between'photo-review'and'vault-backup'(matching the group’s existing sort). - Refresh the two count call-outs in the same file that describe this exact
set’s size, so the edit does not leave a stale comment behind it:
- the assertion-4 bullet in the top-of-file docstring (“19 projects match no gate-supplying aspect”) → 21.
- the ratchet paragraph (“19 of 170 projects match no gate-supplying
aspect. Sixteen are
layer: application… and three arelayer: configuration”) → update “19” to 21 and “Sixteen” to “Eighteen”; leave the “170” total alone (see Out of scope — that figure is separately stale for unrelated reasons and re-truing it is not this task’s job).
- Re-run bun
scripts/guard-project-shape.tsand confirm it now exits 0, printing theOKsummary line with the full moon-project count on the aspect ratchet and no violations. - Run bun test
scripts/guard-project-shape.test.tsand confirm the existing suite still passes unmodified — it drivesaspectRatchetViolationsagainst synthetic fixture projects built by the localproject()helper, never against the liveASPECT_BASELINEconstant or a realmoon query projectscall, so it does not need to change to reflect this edit.
| Area | Note |
|---|---|
scripts/guard-project-shape.ts#ASPECT_BASELINE | Add product-suspenders and product-system-graph to the layer: application baseline group (alphabetically); refresh the two adjacent docstring counts that describe this set’s size. |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: bun
scripts/guard-project-shape.tsexits 0 (it exits 1 onmaintoday, citingproduct-suspendersandproduct-system-graph). - AC-2:
scripts/guard-project-shape.ts#ASPECT_BASELINEcontains both the string'product-suspenders'and the string'product-system-graph'. - AC-3: bun test
scripts/guard-project-shape.test.tspasses. - AC-4:
git diff --statfor the change touches exactly one file,scripts/guard-project-shape.ts. - AC-5: The top-of-file docstring’s two count call-outs for assertion 4
(the “19 projects match no gate-supplying aspect” bullet and the “19 of
170 … Sixteen are
layer: application” ratchet paragraph) read 21 and Eighteen respectively, matching the two-entry baseline addition.
Out of scope
Section titled “Out of scope”- Designing or wiring a dedicated Nuxt-product moon aspect for
solutions/ontological/products/*(mirroring.moon/tasks/determined-nuxt.yml/.moon/tasks/nuxt-product.yml) soproduct-suspendersandproduct-system-graphgain realfmt/fmt-check/lint/checktasks reachable throughmoon run. This task only unblocks the ratchet; it does not add per-project moon attribution for either product. - Any change to
.moon/tasks/determined-nuxt.ymlor.moon/tasks/nuxt-product.yml. Both are explicitly scoped by their own header comments tosolutions/determined/products/*and are not extended tosolutions/ontological/products/*here. - Adding CI steps for either product (e.g. an explicit
moon run product-suspenders:checkstep alongside “Typecheck the Nuxt products” in.github/workflows/ci.yml). Neither product carries achecktask today, so there is nothing yet for such a step to run. - Removing or re-litigating any of the pre-existing 19 baseline entries. Assertion 4’s shrink-only direction (an entry that “now matches an aspect” or “is no longer a project”) is unaffected by this change.
- Correcting the module docstring’s total-project-count figure (“170”). A
live
moon query projectson this branch reports 181 projects total — a pre-existing drift unrelated to, and not caused by, this task’s two-id baseline addition.
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”Spawned by /sdlc:spawn-task-pr on 2026-09-13 UTC from T-4VNC-learning-p1-scaffold-solution in git@github.com:sksizer/dev.git.