Skip to content

t1k:cocos:playable:modularize-refactor

FieldValue
Moduleplayable
Version2.14.4
Efforthigh
Tools—

Keywords: embedded-to-cpm, import-repoint, modularize refactor, playablesync

/t1k:cocos:playable:modularize-refactor
<project-root> --audit <path> --reuse <path> [--arch <path>] [--apply]

Turn the audit + reuse classifications into an ordered project refactor plan and (with --apply) execute it incrementally. Migrates the embedded framework (PLAGameFoundation, PlayableParamterTool) to CPM-package consumption. No package splitting — that is contribute. Part of the t1k-cocos-playable-modularize set — obeys the shared CLI contract.

  • After structure-audit + reuse-scan: produce the ordered migration plan.
  • To execute a migration incrementally (--apply, one package per gate).

Requires BOTH input reports: a structure-audit JSON (--audit) and a reuse-scan JSON (--reuse). plan-refactor.cjs sets preconditionsOk: false if either is missing/empty — the skill then hard-blocks --apply (report the missing input; do not guess a plan).

An architecture-audit JSON (--arch, from t1k-cocos-base-architecture-patterns audit mode) is optional but strongly recommended. Without it Tiers 2.5/2.75 are skipped and the plan reports archAudit: absent — a legacy project then migrates its structural debt into packages untouched.

The design-doc probe BLOCKS Tiers 2.5/2.6/2.75 — always pass --design-probe

Section titled “The design-doc probe BLOCKS Tiers 2.5/2.6/2.75 — always pass --design-probe”
Terminal window
node <system-design>/scripts/probe-design-doc.cjs docs/system-design.md <repo-root> > design-probe.json
node scripts/plan-refactor.cjs --audit <a> --reuse <r> --arch <arch> --design-probe design-probe.json

plan-refactor.cjs records designDoc: ok | foreign | template-verbatim | template-unfilled | non-canonical | absent | indeterminate | unchecked, and emits a machine-readable blockers[] + blockedTiers whenever that verdict is anything but ok. Every step in a blocked tier repeats the block inline as blockedBy, so an --apply walker refuses those units mechanically rather than relying on the operator having read a warning two hundred lines up.

unchecked (flag omitted) blocks too. Not asking is not a pass — it is precisely the state an inherited doc sits in while looking healthy to every other check here (rules/negative-result-scope.md).

Three reasons this is a block and not a warning: (1) a doc describing another project satisfies every other check identically — structure-audit R9 only asks whether the file exists, and generate-manifest’s failure surfaces as the generic designState: null; measured 2026-08-20 (HexaBugFlowPLA), a 16-step plan with six Tier 2.5 module-boundary steps graded against PlayableAdsTemplate’s doc. (2) designState: null and “the doc belongs to someone else” need different repairs — regenerating a manifest fixes the first and is useless against the second, so the plan names them separately (design-manifest-missing vs design-doc-foreign). (3) Tier 2.5 is the only tier that rewrites source logic, and its splits break scene references tsc cannot see; boundaries nobody decided are the most expensive thing this pipeline can produce.

The block is scoped on purpose, and the scoping is what keeps it enabled. Tiers 0/1/2/3/4 are version, folder and import-path work no design doc grades — fully plannable and appliable on a legacy repo with no doc, with plan-refactor.cjs still exiting 0 and still printing the blocked findings. A gate that refuses the whole report is one operators route around, and then it protects nothing.

This is the pillar that genuinely requires docs/system-design.md (pillars A and B do not — see the dependency table in t1k-cocos-playable-modularize). Its § “Code Structure Rules (Mandatory)” is the SSOT Tier 2.5 is graded against, so planning without it means measuring against nothing.

Resolving, authoring and drift-auditing the doc is owned end-to-end by t1k-cocos-base-system-design (authoring + template resolution) and t1k-cocos-base-architecture-patterns (audit), including the missing-template and legacy “no architecture to document” cases. Do not re-derive that procedure here; it is report-or-author only and never mutates code.

Generate the manifest from the doc, then pass it so the plan records what it was graded against:

Terminal window
node <arch-patterns>/scripts/generate-manifest.cjs docs/system-design.md --out docs/design-manifest.json
node scripts/plan-refactor.cjs --audit <a> --reuse <r> --arch <arch> --manifest docs/design-manifest.json

The plan reports manifest: present | absent | unchecked. unchecked (flag omitted) is not absent — the first makes no claim about the project, the second is a checked negative. Omitting the flag on a project that has no doc is the case that reads as fine and is not.

It also records designState — the doc’s tense. A plan built from a to-be manifest moves TOWARD a documented target; from as-is, AWAY from documented current reality. Identical step lists, opposite meaning; say which one you are executing. designParse: "partial" means the module map was only partly readable, so the plan is not fully informed.

designState: null is a third case, and the common one. No manifest was read at all, so the plan moves neither toward a target nor away from a baseline — a bottom-up list of violation fixes whose module boundaries land wherever the split test happened to cut. The script says so on stderr and mirrors it into the artifact as designStateWarning (null in every other case), because a plan built against nothing reads exactly like one built against a target: ordered tiers, real evidence, plausible steps. The fix is upstream: run t1k-cocos-playable-modularize Phase 2.5 (t1k-cocos-playable-preproduction in refactor mode) to author the to-be doc from the as-is doc

  • architecture-audit.json + reuse-scan.json, regenerate the manifest, re-plan with --manifest. Exit stays 0, but the design-probe gate above also raises a design-manifest-missing blocker withholding Tiers 2.5/2.6/2.75 — the report still prints in full, which is what keeps pillars 1 and 2 usable on a repo with no doc. Exiting non-zero is what would get the pipeline abandoned on exactly the legacy projects it exists for; withholding tiers does not.

Before mutating anything, the manifest must still describe the code:

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

Non-zero exit blocks --apply. Planning against a manifest that no longer matches the tree means every Tier 2.5 step is aimed at a file layout that has already moved. Verification is state-dependent, so read pathsChecked in the report: under to-be it is false and a pass proves only internal consistency — it is not evidence the code matches. Unclaimed files are reported and never block; a legacy project is mostly unclaimed and that is the finding, not an error.

The whole-refactor plan is built once, in step 2 below, from all three audits, before any mutation. Architecture findings are an input to planning, not a mid-flight discovery: audit early, mutate in tier order. Do not replan between units — if a finding emerges during --apply, record it and re-plan in a fresh pass.

Ordering (safe → risky) — never reorder

Section titled “Ordering (safe → risky) — never reorder”
  1. Tier 0 — upgrade installed-but-outdated packages: one row per @playablelabs/* package whose installed version is behind the registry latest, from the reuse-scan report’s installedVersions block. Lowest risk, highest value — and the ONLY tier that fires on a project that already finished CPM migration, where Tier 3 is empty by construction. Gated per-unit: an upgrade is a small diff but can still change behaviour.

    The action is a command, never a panel instruction — every row renders as node <refactor-skill>/scripts/upgrade-package.cjs <cocos-project-root> <pkg> --to <latest> --expect-installed <installed>, which self-verifies by re-reading the vendored package.json and exits non-zero unless the version on disk is the one asked for. update-package via package-manager names an editor-panel handler no MCP tool exposes, so --implement reached the row with nothing to run and the upgrade silently never happened (pinned by plan-refactor-tier0-executable-action.test.cjs).

    Two axes decide routine vs BLOCKED, both read from the reuse-scan: vendoredDivergence / locallyModified (#274 — the upgrade overwrites the vendored tree and deletes a local patch while tsc stays clean) and importPathCheck / removedImportPaths (#294 — semver is no proxy: the measured case was a patch bump removing 3 of 14 imported paths). A recorded finding blocks at risk: high with a requires: prerequisite; an absent check blocks at risk: medium (divergence-never-checked / import-paths-never-checked), because unchecked is “nobody compared”, not “nothing is patched”. One row per package carrying every blockReasons entry it trips and one requires: per reason. A Tier 0 row reaches unattended.walkOrder only when both axes ran and neither recorded anything — full matrix in decision-policy rule 5, full rationale in references/migration-playbook.md § Tier 0.

  2. Tier 1 — folder normalizations (create canonical dirs, gitignore artifacts, quarantine orphan metas to report, review unexpected top-level dirs, relocate stray game-assets/ entries). Rules that grade more than one sub-condition (R2, R3) emit one row per sub-condition that actually fired, each carrying only its own evidence — never a fixed action per rule ID (#249). R11 (a script directory that has become the codebase) emits a report-only row, not a move: the audit knows which directory is crowded, only the design doc knows which module each file belongs to. With --manifest the row names the real target modules and points at the Tier 2.6 rows that actually order the moves; without one it says plainly that no targets are known and routes to Phase 2.5, because a split into invented folders is worse than the pile it replaces.

  3. Tier 1.5 — INSTALL a package a live REUSE swap needs and the project does not have, via install-package.cjs. One unit per package ROOT, editorState: closed, and the Tier 2 swap that needs it declares dependsOn this unit. Only a live swap earns an install — a keep-retract, an extend or a manual-queue is a decision NOT to import that package, and installing anyway vendors code the plan already declined. Before this tier the install was a parenthetical (install package first — Tier 3) pointing at a tier that emits nothing for a package which is merely absent: ordered by prose, owned by no tier, executable by nobody (rules/wired-not-just-present.md).

  4. Tier 2 — REUSE swaps for packages installed already or by Tier 1.5 (pure import-path changes). Runs before architecture work: never refactor code a swap is about to delete.

  5. Tier 2.5 — architecture refactor (SOLID + mandatory pattern triggers per rules/code-quality-cocos.md), driven by the --arch findings. Includes enabling extractions — SRP splits whose purpose is to expose a seam that a package can then fill.

  6. Tier 2.6 — MECHANIC SLICE: move each design-doc module into its own vertical folder, one unit per module, editorState: closed. Delegated in full to t1k-cocos-playable-mechanic-split — that skill is the SSOT for the procedure (cid snapshot/diff around every move, .ts + .ts.meta co-move, barrel + README contract, portability-blocker scans). This skill owns only the wrapper: which modules, in what order, gated per unit. Boundaries come from the manifest, never from a coupling audit re-run here — every row invokes it as --mechanics-from docs/design-manifest.json, because a second module map decided by a different method is the one failure this delegation exists to avoid. Rows carry dependsOn the Tier 2.5 extraction that rewrites their files, and a module already living in its own folder emits no row at all. This is the tier that turns R11’s report into work: it stayed report-only for want of the module table, and the manifest is that table.

  7. Tier 2.75 — second REUSE pass over the seams Tier 2.5 exposed (exposesSeamFor in the arch findings). Skipping this makes Tier 2.5 a net loss: more files, same duplicated logic.

  8. Tier 3 — embedded-submodule → CPM migration, per package. Highest blast-radius. Delegated in full to t1k-cocos-playable-submodule-to-package, the SSOT for the procedure (submodule removal, vendoring, playableSync, import repoint + API-signature changes, ParameterToolRuntime seams, scene/prefab uuid remap, its own defect scanner); this skill owns only the wrapper: gate → invoke → both verifiers green → editor confirm → remove embedded dir → pathspec commit. Tier 1.5 supersedes it for a package that is merely ABSENT — Tier 3 ends in “remove the embedded dir”, and there is none when the source was never vendored; before 1.5 this loop doubled as the install path and named the dead panel handler to do it.

  9. Tier 4 — tag CONTRIBUTE (no mutation; hand-off to contribute).

Every step carries editorState — which Cocos-editor state the unit must be applied in:

ValueTiers (default)Why
closed0, 1, 1.5, 2.6Bulk file/.meta moves race the asset importer; a running editor is a second writer. Same reason t1k-cocos-base-migrate demands --editor-closed and t1k-cocos-base-uuid-verify is explicitly file-based. Tier 1.5 belongs here for the same reason Tier 0 does — the package sync is a remove-then-copy of a directory under assets/; Tier 2.6 because a mechanic slice IS the bulk .ts + .meta move.
open2.5, 3 (and any Tier 2 row needing a component re-point)Scene/prefab work — and every “compiles clean” verification, because a playable project has no tsc CLI and the editor is the only compiler.
any2, 2.75, 4Plain-text edits (import specifiers, .gitignore) touching no asset UUID. A report-only row is always any.

The plan also carries an unattended block (schema: t1k-cocos-unattended-walk/1) that the orchestrator’s --implement mode consumes:

  • walkOrder — the ONLY orders that may be auto-applied, in the order they must be. Sorted by (editor phase, tier, order), so every closed/any unit sorts before the first open one and an unreachable editor costs nothing that was already landable (on a Tier-2.5-dominated plan, nothing at all — see editorRequiredFromStart). Tier order itself is never changed; the reordering happens strictly WITHIN a tier, which is safe because a tier’s rows are independent by construction — one per package (Tier 0), per fired sub-condition (Tier 1), per subsystem (Tier 2). Every real cross-tier dependency is declared as data instead: a Tier 2.75 row carries dependsOn naming the Tier 2.5 extraction that exposed its seam and inherits that unit’s phase floor, so the second reuse pass can never sort ahead of the split it re-scans.
  • firstOpenUnit — where to probe the editor before proceeding — and editorRequiredFromStart, true when that is already walkOrder[0]. On a plan dominated by Tier 2.5 that is the normal case, and it means the front-loading buys nothing: the operator must have Cocos Creator open before starting, stated as a precondition rather than discovered at the first hard-stop.
  • reportOnly / manualQueue — the two reasons a step is NOT in walkOrder: nothing to apply, or it needs a human. designBlockedSteps is a labelled subset of manualQueue, never a third peer; the specific name matters because a generic blockedSteps returns [] on a plan whose only blocked rows are Tier 0 blockReasons ones, read as “no blocked work” while units sit queued. A step in none of the lists would read as already handled — the defect this partition prevents.
  • autoDecisions — every fork resolved without asking, each with its rejected alternative. This is the compensating control that makes unattended operation auditable; a decision merely made cannot be reviewed after the fact, a decision recorded can.

The rules that populate autoDecisions and manualQueue are not restated here — they are t1k-cocos-playable-modularize/references/decision-policy.md. The three that change Tier 2 rows: a local-ahead REUSE becomes EXTEND (never a swap); a REUSE over an editor-attached component with no mechanism-equivalence proof is retracted to KEEP; and a candidate with zero TS importers becomes a VERIFY-FIRST row that runs verify-reachability.cjs and branches on the pair (verdict, transitivelyReachable) — because “repoint imports” over a file nobody imports is a silent no-op (what two measured steps turned out to be), and because verdict alone covers only one hop: LIVE + false is delete-eligible, LIVE + true is protected, and anything null/UNKNOWN goes to the manual queue.

Full per-package procedure + rollback: references/migration-playbook.md.

  1. Phase 0 — confirm docs/system-design.md exists and is current (author/correct if not).
  2. Validate <project-root> + confirm --audit/--reuse reports exist (else exit 2). Note whether --arch was supplied; if not, report archAudit: absent and skip Tiers 2.5/2.75.
  3. Plan: node scripts/plan-refactor.cjs --audit <a> --reuse <r> [--arch <arch>] → ordered step JSON (tiers + per-step risk + gate mode). This is the only planning pass.
  4. Report the plan (safe → risky) → reports/ (plan-report format). Close the report with its ## Next action line — the literal --apply invocation for this project root. A plan that ends on the step table strands whoever reads it next.
  5. (--apply only) Per unit: AskUserQuestion gate (proceed-one-unit) → on a dedicated branch, execute the tier’s procedure → verify → commit the unit (pathspec form) → re-gate for the next. Never bulk-proceed Tier 3.
    • Tier 2.5 units are per-extraction, not per-package. Verify = tsc clean plus an editor confirmation that scene/prefab @property refs to the split component were re-wired — the compiler cannot catch a dangling scene ref.
    • Tier 3 units are per-package and run through t1k-cocos-playable-submodule-to-package — do not improvise the migration here. Verify = that skill’s scan-missing-sibling-imports.cjs exit 0 and node scripts/verify-imports.cjs <project-root> --scenes exit 0 (import-resolution gate; the scene-UUID list is advisory) → confirm scene refs and that LOADING → FTUE → GAMEPLAY actually runs in the editor.
  6. (--apply only) Emit the change + status report — REQUIRED, even after one unit, so there is a record of what changed and how far the migration got. Compose it from node scripts/refactor-status.cjs --plan <plan.json> --done <orders> --verify <verify-imports.json> --sync-before/--sync-after <package.json> (per-unit status + gate + playableSync delta) plus git diff --stat. Format: references/report-format.md § “Change
    • status report”. Never mutate the codebase without leaving this report.
  • Scope = assets/scripts. The import repoint + verify work operates on the project’s own scripts (that consume the framework). Package source is consumed as-is; everything is plain, readable TypeScript.
  • Tier 2.5 is the ONLY tier that rewrites source logic. Tiers 1/2/2.75/3 change layout and import paths only. Tier 2.5 restructures the project’s own code under assets/scripts per rules/code-quality-cocos.md — never package source, never a transform beyond what the arch findings authorize.
  • Tier 2.6 relocates files; it does not rewrite them. The other tier touching assets/scripts source, and the distinction is load-bearing: 2.5 changes what the code SAYS, 2.6 changes where it LIVES. A slice that starts editing logic has left its mandate and belongs in a 2.5 row with an arch finding behind it. (t1k-cocos-playable-mechanic-split does permit gated content changes when a move alone cannot reach a boundary — that gate is its own, recorded as an ADR in its audit/decisions.md, not a licence this tier hands out.)
  • Tier 1.5 installs; it never upgrades. install-package.cjs refuses an already-vendored package, because an upgrade over existing files is a remove-then-copy that deletes local work and Tier 0 owns it behind two divergence axes this path deliberately does not carry.
  • Never move/delete a .meta silently (UUID re-point risk). Co-move .meta with its file; orphan metas are quarantine-to-report. references/import-repoint.md.
  • register(ctx) does not exist — repointing is import-path-only.
  • Never git add ./-A — pathspec commits, one unit each.
  • Import-resolution green is the gate to remove embedded source. The --scenes UUID list is advisory only (Cocos compresses scene UUIDs → over-reports); the editor is authoritative for scene refs.
Terminal window
node <system-design>/scripts/probe-design-doc.cjs docs/system-design.md <repo-root> > design-probe.json
# does the doc describe THIS project? exit 0 ok · 1 repair required · 2 usage
node scripts/plan-refactor.cjs --audit <structure-audit.json> --reuse <reuse-scan.json> \
[--arch <architecture-audit.json>] [--manifest docs/design-manifest.json] \
[--design-probe design-probe.json]
# ordered plan (report-only). --arch enables Tiers 2.5/2.75. --manifest carries the doc's tense
# through as designState AND generates the Tier 2.6 rows — no manifest, no 2.6 rows, because
# boundaries are never invented here; omitted, it reports 'unchecked' (no claim, NOT a clean bill).
# --design-probe: verdict != ok (or flag omitted) => blockers[] withholds Tiers 2.5/2.6/2.75
node scripts/install-package.cjs <cocos-project-root> <@scope/name> [--to <version>] [--dry-run] [--json]
# Tier 1.5, editor CLOSED. npm install --no-save -> sync into assets/packages -> playableSync ->
# wipe temp/+library/, then RE-READS the vendored package.json and fails unless it holds the
# requested version. REFUSES an already-vendored package (that is Tier 0's upgrade-package.cjs).
node scripts/upgrade-package.cjs <cocos-project-root> <@scope/name> --to <v> --expect-installed <v>
# Tier 0. Same sync body (scripts/lib/package-sync.cjs), opposite precondition: must be vendored.
node <arch-patterns>/scripts/verify-manifest.cjs docs/design-manifest.json <project-root>
# manifest <-> code. NON-ZERO EXIT BLOCKS --apply. State-dependent: read pathsChecked.
node scripts/verify-imports.cjs <project-root> --scenes # exit 0 iff zero unresolved imports (scene-UUID list advisory)
node scripts/refactor-status.cjs --plan <plan.json> --done 1,2 --verify <verify.json> --sync-before <a> --sync-after <b> # post-apply status
node scripts/refactor-status.cjs --plan <plan.json> --state reports/implement-state.json --done 7 --branch refactor/modularize --project-root <project-root> > reports/implement-state.json.tmp
# unattended walk state; its own output is a valid --state input (t1k-cocos-implement-state/1).
# Prior units union in, so a resumed run passes only what IT landed. --failed <orders> makes
# overall 'hard-stopped'; resume{} names the next unit, whether it needs the editor, and the
# literal command. Write via .tmp + rename — a truncated state file reads like a run that never
# got anywhere.
  • t1k-cocos-playable-submodule-to-package — SSOT for the Tier-3 migration procedure. Invoke per package; never re-derive its API-signature table, seams, or dropped-enum scanner here.
  • references/migration-playbook.md — Tier-3 wrapper (gate, both verifiers, rollback) + tier ordering.
  • references/import-repoint.md — db:///relative path change map + .meta UUID caution + verify gate.
  • references/report-format.md — the plan report AND the required post-apply change + status report format.
  • rules/code-quality-cocos.md — the binding SOLID + pattern-trigger obligations Tier 2.5 executes.
  • t1k-cocos-base-architecture-patterns — produces the --arch findings; owns the audit format. Read-only.
  • t1k-cocos-base-system-design — owns docs/system-design.md and docs/design-manifest.json; supplies --manifest.
  • Migration is the highest-blast-radius step — one package per --apply, branch + rollback each, verify-imports green before removing embedded source.
  • A Tier-3 unit that skips t1k-cocos-playable-submodule-to-package compiles clean and never boots. The ParameterToolRuntime seams, API-signature changes and dropped enum imports are all invisible to tsc and verify-imports.cjs: an import-only repoint passes every gate here, then stalls at LOADING with no error. Delegate.
  • Component UUIDs change on migration → scene/prefab refs to old embedded components go dangling; re-point them (editor/manual) before removing embedded source. verify-imports.cjs --scenes flags the dangling set.
  • Always leave a change + status report after --apply. Never mutate silently — every session records what changed (git diff --stat), the playableSync delta, the verify-imports gate result, and per-unit done/pending/rolled-back status.
  • Do not run without both reports — preconditionsOk: false hard-blocks --apply.
  • Do not --apply a step carrying blockedBy — the design doc it is graded against is absent, foreign, or unverified. Repair the doc first (blockers[].repair names the command), re-probe, re-plan. Applying it anyway means executing module boundaries nobody decided.
  • An action naming an editor-panel button is not an executable step — the defect Tier 0 was fixed for and Tier 1.5 added for. The package-manager extension’s install-package / update-package handlers need a human clicking a panel in a running editor, no MCP tool exposes them, and a plan whose action is that phrase has nothing an unattended walk can run — while the plan, the report and IMPLEMENT.md all read as healthy (rules/wired-not-just-present.md). Every new tier owes a runnable command or an explicit delegation to a skill that has one.
  • A Tier 2.6 row is a delegation, not a recipe. Do not hand-roll the move because the row lists the discipline: the cid snapshot/diff is what makes a broken move visible at all, and a second copy drifting from mechanic-split’s has no symptom until a scene shows Missing Script.
  • Reuse before architecture, then reuse again. Refactoring code a Tier 2 swap is about to delete is the most common wasted effort in a legacy pass; conversely Tier 2.5 without Tier 2.75 is a net loss — a god-class split to expose a seam nobody then fills, ending with more files and the same duplicated logic.
  • Tier 2.5 breaks scene refs that tsc cannot see. Moving behaviour out of an attached @ccclass component leaves its @property refs dangling and the new component unattached. The editor is authoritative; re-wire and confirm before the unit’s commit.
  • editorState describes APPLY, not verify. A unit tagged any can be edited with the editor shut, but if its verification is “compiles clean” it still needs an editor pass eventually — a playable project has no tsc CLI. The walk batches that: everything closed/any lands first, then the editor comes up for the open units and the compile checks.
  • A step absent from unattended.walkOrder is not done. It is report-only, design-blocked, or manual-queue — and which one it is has to be carried into the handoff. Collapsing the three into “not in the walk” is how a Tier 0 BLOCKED row reads as handled.
  • Re-planning mid-migration invalidates recorded unit numbers. order is the positional unit identity refactor-status.cjs keys --done/--rolled-back off, so a second plan gaining any earlier-tier row shifts every later order down. validOrders cannot catch it — the numbers stay valid, they just name different steps. Finish on the plan you started with, or re-record deliberately.
  • Tier 0’s three versionDrift axes each fail the same silent way, and a sync unregisters the package’s @ccclasses while every gate here stays green. state: unchecked on installedVersions, divergence or importPaths means “nobody looked”, not “nothing found”; prose in the reuse-scan input is not a signal; and after every Tier 0 sync the editor cache must be wiped (close, delete temp/ + library/, reopen) or components log Missing class with tsc, UUIDs and git diff all clean. Axis semantics, the unattributed-divergence row, and the cache-vs-real-UUID-break discriminator: references/migration-playbook.md § Tier 0.
  • Without --arch, the plan silently skips the quality tiers. It reports archAudit: absent, but a reader skimming the plan sees a clean migration and may not notice the structural debt is being migrated into packages untouched. Run the architecture audit unless you deliberately want a packaging-only pass.
  • AnimalHunter target: migrate PLAGameFoundation → @playablelabs/game-foundation and PlayableParamterTool → @playablelabs/parameter-tool; folder-normalize game-assets/font and .optimize-data/ first (Tier 1).