Skip to content

t1k:cocos:base:system-design

FieldValue
Modulebase
Version3.3.2
Effortlow
Tools—

Keywords: as-is, converged, design-doc, design-manifest, doc-contract, generate-manifest, migrate-design-doc, module-map, module-table, system-design, to-be, verify-manifest

/t1k:cocos:base:system-design
[generate|verify|migrate] <path> [--out <path>] [--apply]

Owns docs/system-design.md as a machine-checkable artifact: its blank, its module-table contract, and the scripts that read, verify, and migrate it.

This skill owns the ARTIFACT, not the architecture. Architecture doctrine — SOLID, module boundaries, mandatory class roles, anti-patterns — lives inside docs/system-design.md itself (§ “Code Structure Rules (Mandatory)”). When a pattern becomes mandatory, and whether a codebase conforms, belong to t1k-cocos-base-architecture-patterns, which reads this artifact and never writes it. Keeping the two apart is the point: a skill that both defines the target and grades against it can never report that the target is wrong.

Producing docs/system-design.md is distributed on purpose, because the producers genuinely differ. Forcing them through one authoring mode would mean one procedure pretending to fit four jobs:

ProducerWritesFrom
t1k-cocos-playable-preproductionto-bea spec, no code — the greenfield archetype
t1k-cocos-playable-modularize (Phase 0)as-isa legacy repo, from the code as it exists
t1k-cocos-playable-preproduction (refactor mode)revised to-bethe as-is doc + architecture-audit.json + reuse-scan.json — modularize Phase 2.5
t1k-docs-manageredits in placea doc that already exists

The refactor row is a distinct job, not a variant of row 1. Rows 1 and 3 share one procedure — top-down module slicing, which is why preproduction owns both — but the input differs completely: greenfield slices a spec, refactor slices a documented baseline against a list of what is wrong with it. Leave row 3 unassigned and the refactor archetype’s lifecycle (as-is → revised to-be → converged, below) has a step nobody performs, and every plan downstream is built at designState: null.

What makes multiple producers safe is that the contract is verifiable, not that everyone remembered the guideline:

Terminal window
node scripts/verify-manifest.cjs docs/design-manifest.json <project-root>

A producer proves conformance by running it. That is the whole reason this skill exists as a contract rather than a style note.

You areDo this
Producing a docTake the blank (Step 0a), fill it, generate, verify
Holding a non-canonical or tree-shaped docmigrate
Consuming the module mapRead docs/design-manifest.json — and read parse beside modules
Grading code against the docNot here — t1k-cocos-base-architecture-patterns audit
Looking for the SOLID / anti-pattern rulesNot here — the project’s docs/system-design.md

Deterministic, no judgment, no LLM step (rules/ai-driven-design.md). The doc is the sole SSOT, and generating the manifest from it is what makes doc↔manifest drift impossible by construction rather than policed by a gate.

Terminal window
# does this doc describe THIS project at all? Exit 0 ok · 1 repair required · 2 usage error.
node scripts/probe-design-doc.cjs docs/system-design.md <project-root> [--project-name <name>]
# doc -> manifest. One-way; never writes into the doc.
node scripts/generate-manifest.cjs docs/system-design.md --out docs/design-manifest.json
# manifest <-> code. Exit 0 verified · 1 verification failed · 2 usage error.
node scripts/verify-manifest.cjs docs/design-manifest.json <project-root> [--scan-root <rel>]
# non-canonical or tree-shaped doc -> canonical table. Report-only unless --apply.
node scripts/migrate-design-doc.cjs docs/system-design.md [--apply] [--print]

<project-root> is the directory containing assets/ — frequently a subdirectory of the repo (<repo>/CocosFooPLA/), not the repo root. probe is the one exception: pass it the repo root, because that is where it locates the Cocos project directory to read the project’s identity from.

probe runs FIRST — the other three assume a doc that is already yours

Section titled “probe runs FIRST — the other three assume a doc that is already yours”

generate and verify answer “does the doc match the code?”. Neither asks the question one level up: is this doc even about this project? A doc inherited verbatim from PlayableAdsTemplate and never rewritten answers every existing check exactly as a real doc does — structure-audit R9 only asks whether the file EXISTS, generate-manifest fails on the missing state: and that failure is reported downstream as the generic designState: null, and the refactor plan is emitted anyway behind a prose warning. Measured 2026-08-20 (HexaBugFlowPLA): the doc named PlayableAdsTemplate four times and the actual game zero times, and a 16-step plan carrying six Tier 2.5 module-boundary steps was produced against it.

probe closes that gap deterministically. Verdicts, worst first; all matched signals are reported and verdict is the worst, so a doc failing three ways never hides two of them:

VerdictMeansRepair
absentno file, or emptyauthor it — Step 0a, fill from the code, state: as-is
template-verbatim≥60% of substantive lines match the vendored blank or a sibling *-template.mdrewrite it for this project
template-unfilled[Placeholder] tokens surviveresolve every placeholder
foreignnever names this projectrewrite the overview + § Module Architecture from THIS codebase
indeterminateproject identity unresolvablepass --project-name; fails closed on purpose
non-canonicalno state: and/or no § Module Architecturemigrate-design-doc.cjs
okcanonical and project-specificnone — run verify-manifest next

ok is a claim about identity and shape, not about drift; drift is still verify-manifest’s question. Identity matching ignores spacing and case, so a doc titled “Hexa Bug Flow” is not foreign to CocosHexaBugFlowPLA.

Who reads the probe: refactor (plan-refactor.cjs --design-probe), which withholds Tiers 2.5/2.75 while the verdict is not ok — see that skill’s § “Hard precondition”.

Who reads the manifest: reuse-scan (enumerate-subsystems.cjs --manifest), refactor (plan-refactor.cjs --manifest, plus verify as an --apply gate), and architecture-patterns audit. Who does not: structure-audit reads neither the doc nor the manifest — it grades folders against a pinned blueprint, and that is legitimate, not a gap.

Schema lives in references/design-manifest.md — field semantics, the module-table contract, and the state: frontmatter placement. Do not restate it here; the copy is the one people read.

Reading the output — the four fields that decide whether you can trust it

Section titled “Reading the output — the four fields that decide whether you can trust it”
  • parse — complete | partial | unparseable. modules: [] alone means nothing; read parse beside it. unparseable means the doc could not be read, not that the project has no modules. A tree-shaped or non-canonical doc lands here and names migrate-design-doc.cjs.
  • priorArt — searched | unavailable. A consumer may skip its own doc_search only on searched. unavailable means unverified, not disproven.
  • pathsChecked (verify) — false under to-be. A passing to-be verification is not evidence the code matches.
  • scan.scanned (verify) — false means the scan root was unreadable, so unclaimedFiles is null, not 0. Usually the repo root was passed instead of the Cocos project root.
  • cohesion (verify) — findings lists each directory that more than one module calls home, derived from files. enforced is true only under to-be, where such a finding fails the verification: a target doc gives every module its own directory. Under as-is/converged the same finding is reported and ignored — a legacy flat layout is the truth an as-is doc records.

Unclaimed files are reported, never failed on. A legacy project is mostly unclaimed — that is the finding, not an error. verify fails on exactly three things: internal-consistency errors, unresolvable paths in the states that check them, and a to-be doc whose modules share a home directory.

state: is not a label — it changes what verification means.

ArchetypeLifecycle
From scratchcreated to-be → build → converged
Existing doc, auditconverged → verify vs code → drift is the finding
Old code, refactoras-is → revised to-be (git keeps the as-is) → plan = diff → converged on land
Old code → new gameplayas-is from code → to-be = retained + new modules → converged

as-is and converged check that every documented file resolves; to-be checks internal consistency only, because the code is expected not to match — that is the work. Without this carve-out a to-be doc fails verification by design, and a gate that fails by design gets switched off within a week.

Flipping to converged when the work lands is a required step, not a nicety. While a doc sits at to-be nothing compares it to code, so that flip is the only gate that ever catches a to-be doc drifting from what was actually built.

The delta never lives in the doc. The doc holds one state; plan-refactor.cjs output is the delta, and git holds the previous state (development-principles.md § “Automate Over Manual — Git Is Truth”).

Resolve two things independently — the filled doc, and the blank it is authored from. Many repos (older playables, forks, anything predating the template) have neither.

Template stateAction
docs/system-design-template.md presentUse it. It is byte-identical across studio projects.
AbsentCopy this skill’s vendored blank, stripping the kit frontmatter (see unfm below): unfm assets/system-design-template.md > <project>/docs/system-design-template.md. A filled reference is vendored alongside as assets/system-design-example.md.
Present but modifieddiff --strip-trailing-cr <(unfm assets/system-design-template.md) <project>/docs/system-design-template.md. An intentional project change is fine — keep it and note it. An accidental drift should be reset to the vendored copy.

The vendored files are copy-payloads, not documentation, but they live under .claude/ so CI stamps kit origin: frontmatter into them like every other .md. Strip it on both sides of any copy or diff — otherwise the payload pollutes the project’s docs/ and the drift check reports a phantom 7-line delta:

Terminal window
unfm() { awk 'NR==1 && $0=="---"{f=1;next} f && $0=="---"{f=0;next} !f' "$1"; }

Passes files through untouched when they have no frontmatter, so it is safe on the project-side copy too.

⚠ Always pass --strip-trailing-cr. Line endings are inconsistent across studio projects: the vendored copies are LF, but most project checkouts are CRLF. A bare diff then reports every line as changed and reads as total drift when the content is identical. Verified 2026-08-03 — system-design-example.md is LF in PlayableAdsTemplate and CRLF in AnimalHunterPLA, Arrow3DPLA, BeadsOutMapGenerator, and BearKnitColorPuzzlePLA; content matches exactly once CR is stripped. Use git diff --ignore-cr-at-eol for the same reason.

Doc stateAction
AbsentAuthor it from the template, filling § Module Architecture, Communication Flow, Class Summary, Signal Contracts, Class Reference from the code as it exists today. Document reality, not the aspiration — the refactor is what closes the gap. Run t1k-cocos-base-knowledge-sweep while filling § Module Architecture: a module that already exists upstream should be recorded as such from the start, so the refactor plan never schedules work to rebuild it.
PresentAudit it — architecture-patterns audit. Drift is a finding in its own right.
Present but staleCorrect it to current reality first, then proceed. Never plan a refactor against a design doc you know is wrong.

When the project genuinely has no architecture to document

Section titled “When the project genuinely has no architecture to document”

A legacy playable may have no modules, no signals, and one 900-line GameController — nothing § Module Architecture can describe. Do not skip the doc and do not invent a structure. Fill it with what exists (one row: the god-class, its files, its responsibility) and mark everything else TBD. That doc is correct: it accurately records a project with no architecture, and every TBD becomes a Tier 2.5 refactor target — which is exactly the signal the refactor plan needs.

migrate — adopting the canonical template

Section titled “migrate — adopting the canonical template”

scripts/migrate-design-doc.cjs <doc> [--apply]. Report-only by default; --apply rewrites in place and requires a clean git tree.

Detected formatAction
canonical — § Module Architecture holds a module tablenone; already migrated
canonical-tree — § Module Architecture holds a fenced ASCII treetree lifted into the table, sub-paths preserved; original tree retained below as human reference
non-canonical — § Project Structure + § Key Architecture Componentsre-rooted at assets/scripts/, then lifted into the table
anything elseexit 3, nothing written

This is the only place the ASCII-tree parser lives, and that is deliberate. Reading a tree means recovering structure from indentation columns over a guessed connector charset; every way it fails is silent. As a one-time migration whose report a human reviews, that is acceptable. As a gate between every doc edit and every consumer, it was not — see references/design-manifest.md § “Why this is a table”.

  • The manifest is generated. Editing it is always wrong. Fix the doc and regenerate. A hand-edited manifest reintroduces exactly the drift this design eliminates, and nothing detects it. verify rejects a manifest with a missing priorArt partly because that is the fingerprint of one.
  • Generation is one-way. generate-manifest.cjs never writes into the doc — not to normalize the table, not to add a missing state:. A generator that “fixes” its own input makes the doc’s history unreadable.
  • modules: [] alone means nothing. Always read parse alongside it. This is the single most likely way a consumer of this file goes wrong.
  • unclaimedFiles: 0 is only meaningful when scan.scanned is true. An absent assets/scripts (usually: the repo root was passed instead of the project root) reports null, not 0.
  • Write real sub-paths in the Files column — combat/hit/HitDetection.ts, not HitDetection.ts. A shortened path resolves to nothing and reports as missing under as-is; under to-be nothing checks it at all and it propagates silently.
  • status is transcribed, never inferred. An empty Files cell does not make a module TBD. That inference used to launder “the parser captured nothing” into “declared, not built yet”, which then fed work to rebuild modules that already existed.
  • A bare diff on the vendored assets lies twice — CRLF and the CI-injected kit frontmatter. See the warning in Step 0a; getting either wrong makes a clean file look completely rewritten.
  • status: "TBD" is a legitimate entry, not an incomplete one. A legacy project records its god-class as one module and marks the rest TBD; each is a Tier 2.5 target for refactor and ADD-mode input for contribute.
  • references/design-manifest.md — SSOT for the manifest schema, the state/parse/priorArt semantics, and the § Module Architecture module-table contract. Consumers link here; nothing restates it.
  • assets/system-design-template.md + assets/system-design-example.md — verbatim vendored copy-payloads. Strip the CI-injected kit frontmatter (unfm) on both copy and diff --strip-trailing-cr. Each carries a second frontmatter block holding state: — that block is the payload and must survive the copy; do not merge it into the kit block.
  • scripts/ — the three deterministic modes, with suites in tests/ (node --test tests/).
  • t1k-cocos-base-architecture-patterns — reads this artifact to grade code against it. Owns the pattern triggers and the audit; owns none of this.
  • t1k-cocos-base-knowledge-sweep — prior-art sweep; what makes an → @playablelabs/… upstream claim evidence rather than a guess.
  • t1k-cocos-playable-preproduction / t1k-cocos-playable-modularize — the producers. preproduction writes both to-be docs (greenfield from a spec; refactor from an as-is doc + audits); t1k-cocos-playable-modularize writes the legacy as-is baseline at its Phase 0 and calls preproduction at its Phase 2.5 for the target. See § “This skill does not author your doc”.
  • rules/code-quality-cocos.md — the binding obligation the artifact serves.