Commit 98301d4
chore(deps): engine ranges 2.x → ^3.8.0 — and the de-dup blocker is a release, not a range (#33)
* chore(deps): the export lane compiles against the engine it targets
C0 checklist item 1, open since the engine cut 3.0.0 and unticked through
eight minor releases. All six @ai-rpg-engine/* ranges go 2.x → ^3.8.0:
content-schema ^2.0.1, core ^2.0.1, modules ^2.1.0, pack-registry ^2.0.2,
character-creation ^2.0.2, equipment ^2.0.2. Six ranges is what the tree
holds, which is what the contract doc said — this time verified against the
package.json rather than the prose.
Zero source changes and zero fixture churn: build clean, 132 files / 2403
tests green. That is the finding, not an absence of one. C1 had already
repaired everything the major boundary actually moved forge-side (the
engineVersion range, the twelve real module ids, the content hash), so the
remaining 3.x surface the converters touch — EquipmentSlot, ItemRarity,
GameManifest, PackMetadata, DialogueNode.text — either did not change or
was WIDENED across the major. version-skew.json predicted three drifts;
none of them break a type. What they cost instead is documented in
ENGINE_CONTRACT.md rather than in a compiler error.
The lockfile is regenerated SURGICALLY, not wholesale. A full
`rm package-lock.json && npm install` also bumped 94 unrelated transitive
packages (pixi.js 8.16→8.19, react 19.2.4→19.2.8, playwright 1.59→1.62,
parse-svg-path 0.1.2→0.2.0 — a 0.x minor, which is a major); every one of
those is a way for this errand to break something it never touched. So the
seven @ai-rpg-engine entries were stripped from the lock and re-resolved on
their own: 7 of 229 packages changed, and `npm ci` reproduces all six at
3.8.0.
⚠ The first `npm install` did NOT produce a coherent tree, and the diff
looked fine. npm resolved the direct deps to 3.8.0 but left the hoisted
copies at 2.x for the transitive `*` ranges it already had on disk, so
content-schema@3.8.0 sat on core@2.0.1 — two copies of one package, which
is a type-identity break waiting to happen. `npm ls` is what said so; the
lockfile diff did not. Verified after: one core in the tree, at 3.8.0.
Refs C0 item 1 · [[2p5d-forge-engine-dep-bump-kickoff]] §1.1
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(deps): ⚠ ANDON — the hash de-duplication is blocked by a release, not a range
The errand was briefed to delete `content-hash.ts` and import the engine's
canonical `computeContentHash`, on the standing reasoning that only the 2.x
dep ranges stood in the way. The ranges are bumped. The import is still
impossible, and the reasoning was wrong before this errand started.
MEASURED: `computeContentHash` does not exist in any PUBLISHED
@ai-rpg-engine package. It lives in `content-schema/src/gate.ts` — a file
C1 ADDED to engine `main` (merge `00001de`, 2026-07-29) and which has never
been released. npm's `latest` for @ai-rpg-engine/content-schema is 3.8.0,
published 2026-03-07, months before C1 existed. Installed all 26 published
3.8.0 packages and grepped: zero hits for `computeContentHash`,
`runLoadGate` or `applyContentPack`. The blocker is a release; publishing is
not this errand's to do (§2/§3), so I stopped.
Consequences, both recorded rather than worked around:
- `content-hash.ts` STAYS. Its header carried the false justification
("2.x has no such export") and now carries the measured one, because a
comment that has drifted into being wrong is the exact failure C0
documented — DEFAULT_MODULES became nine phantoms that way.
- the engine-side cross-repo equivalence test is NOT retired. Retiring it
was justified by "with one shared function it asserts a tautology";
there is still no shared function, so it is still the only thing between
two implementations and a silent divergence.
`engine-deps-3x.test.ts` makes both halves mechanical instead of
remembered. The first block pins the bump: six ranges declared at ^3.8.0
(enumerated from package.json, so a seventh cannot ride along undeclared),
six RESOLVING at 3.8.x, and the stamped `>=3.8.0 <4.0.0` agreeing with the
range that is installed. The second block is the ANDON: it asserts the C1
gate surface is absent and FAILS the moment a release makes the de-dup
possible, with the four steps written in the failure's own comment.
The resolution assertion is not redundant with the declaration one. The
first install of this errand declared all six at ^3.8.0 and still left
content-schema@3.8.0 sitting on core@2.0.1 — npm reused the 2.x copies it
already had for the transitive `*` ranges. The lockfile diff looked fine.
⚠ Every assertion in the ANDON block is an ABSENCE, and a broken import
looks identical to one. So it opens with a positive control proving the
probe can see an export at all. Worth the four lines: the control failed on
first run — I had guessed the export name — which is the only reason I know
it discriminates.
Refs [[2p5d-forge-engine-dep-bump-kickoff]] §1.2 · C1 REPORT §7.6
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(deps): the forge resolves its own module ids against a booted engine
C1 put the decisive module check in the engine repo for one reason, written
into both files: world-forge could not boot a 3.8.0 engine to resolve ids
against, because its dependencies were 2.x. That reason is gone.
One devDep — `@ai-rpg-engine/starter-fantasy@^3.8.0`, ONE package and 19
lines of lockfile, no transitive additions since its four deps are already
this package's deps — and the four checks land in the file whose header
already described the gap: boot a published starter, read its
ModuleManager, resolve every id `convertManifest` emits. Twelve for twelve.
That is inside the errand's stated budget (devDeps + one test file), so no
ANDON.
The engine-side check is NOT retired or demoted, and the header now says
why in a way "it lives there because we can't do it here" did not. It
resolves against the engine's own unreleased `main`; this resolves against
what `npm install` actually hands a consumer. Those are two different
engines right now — see the sibling ANDON commit, where that gap is a whole
unpublished module — so an id that resolves in one and not the other is a
fact worth failing over, not duplicated work.
Both controls are here because a resolution test with neither proves only
that the ids are plausible:
- RED: the nine retired phantoms resolve against nothing, 9 for 9. These
are the exact strings that used to ship, so the negative is historical
input rather than an invented one.
- the boot itself is asserted before anything is resolved against it. A
silently empty registry would fail the resolution test in a way that
reads exactly like phantom ids returning, and send the next reader into
convert-pack.ts after a bug that is not there.
The near-miss pairs are checked against the LIVE registry — traversal-core
resolves where movement-core does not — instead of against
RETIRED_PHANTOM_MODULES, which the structural block above already asserts
against itself.
Also corrected while rewriting the header: it pointed at
`packages/cli/src/c1-forge-manifest.test.ts`, which does not exist. The
checks are in `c1-gate.test.ts`. Noted in the file rather than quietly
fixed — a cross-repo pointer nobody follows is how the EB-011 comment
rotted into nine phantoms.
133 files / 2412 tests.
Refs [[2p5d-forge-engine-dep-bump-kickoff]] §1.3
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(deps): the contract describes the engine that exists
ENGINE_CONTRACT.md opened with "This exporter depends on the ai-rpg-engine
2.x API" and an eight-item checklist to work "*before* bumping the dep
ranges." The engine reached 3.8.0 with not one box ticked, and the ordering
is why: bumping first is what makes drift visible, and holding the ranges
back is what let nine nonexistent module ids ride in every manifest this
exporter wrote. The 4.x checklist at the bottom now says bump FIRST.
Every claim re-measured against the installed 3.8.0 `.d.ts` files and a
booted engine, not carried over. Items 1/3 closed by this errand, 2/3 by C1,
5/6/7 verified closed, 4 ANDON'd, 8 recorded:
⚠ ITEM 4 IS AN ANDON, not an oversight. TONE_MAP 8/8 and DIFFICULTY_MAP 3/3
match at 3.8.0. GENRE_MAP does not — 3.x added `mercantile` and `pursuit`,
the genres of the two newest starters, and convert-pack.ts:147 silently
falls them back to 'fantasy'. Two identity entries LOOK mechanical. They are
not, because the forge has three genre vocabularies that already disagree:
`project.genre` is a free string, the editor picker offers six fixed options
that match neither list (SaveTemplateModal.tsx:12), and GENRE_MAP has eleven
keys onto nine targets. Mapping two strings the editor cannot author reaches
them only by hand-editing a project file. Which layer owns genre is C3's
question.
Two overclaims caught while writing, both from trusting a shape instead of
reading it:
- item 5 first read "structurally guarded, an engine change breaks the
build." Guarded in ONE direction. `Set<ItemDefinition['slot']>` with
literal members fails to compile if the engine REMOVES a slot and
silently omits one it ADDS — the same shape as the GENRE_MAP gap two
items up. Now says so, and names the fix (derive from EQUIPMENT_SLOTS).
- item 6 reads "closed as far as it can be", not "closed". At 3.8.0
`EntityBlueprint.type` is still a bare string with no enum, so there is
nothing for the six-roles-onto-two-types collapse to be verified
against. The item reads clean because it is unconstrained.
Item 7 closed with zero fixture churn, and the note it used to carry
("dialogue text is an array of { text } blocks on 2.x") never described what
convert-dialogues emits — a plain string, then and now. 3.8.0's
`string | TextBlock[]` widened the constraint out of existence rather than
satisfying it.
Item 8 is NOT done: no bump, no tag, no publish. It is a standing release
note in the doc — retargeting the exporter 2.x→3.x is breaking for anyone
resolving this package's engine peers, so the release that ships it takes a
major and says so.
Also recorded, deliberately not acted on: `@ai-rpg-engine/character-creation`
is declared and imported by nothing (dropping a dep from a published package
is consumer-visible), and convert-pack.ts:5 imports VALID_GENRES/TONES/
DIFFICULTIES type-only and never uses them — which is the ready-made handle
for the drift guard item 4 will want.
The known-blocker section carries the content-hash ANDON so the next reader
finds it in the contract rather than only in a test comment.
Refs [[2p5d-forge-engine-dep-bump-kickoff]] §1.4
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(deps): flip the forge-side 2.x claims, and pin contentHash at the type level
Three places in this repo asserted a world that the dep bump ended. Two were
wrong in a second way that only surfaced when I went to correct them.
`export.ts` — `ExportedManifest` intersects `contentHash` into
`GameManifest`, and said it did so because "contentHash was added to the
engine's GameManifest in engine 3.8.0+, but this repo's core dependency is
still installed at 2.0.1." Both halves were wrong. `core` resolves 3.8.0
now, AND the published 3.8.0 `GameManifest` has no `contentHash` — the field
was added by C1 on engine `main` (`bf496e7`) and never released, the same
unpublished surface that blocks the hash de-duplication. So the intersection
stays for a different reason than the one it recorded: not a range behind, a
release behind.
That correction is now a TYPE-LEVEL PIN rather than a comment, which is the
whole lesson of the nine phantom module ids. `PinnedContentHashState`
resolves to one literal while the installed `GameManifest` lacks the field
and to another the moment it gains it, so a published engine breaks
`npm run build` with the fix written in the type's own name.
⚠ I PROVED IT FAILS. Injected `contentHash?: string` into the installed
`core/dist/types.d.ts`, rebuilt, and got the intended error:
engine-deps-3x.test.ts(165,11): error TS2322: Type
'"absent-from-published-manifest"' is not assignable to type
'"PUBLISHED — drop the ExportedManifest intersection in export.ts"'
then restored node_modules with `npm ci` and confirmed zero residue. A pin
that has never fired is a comment with extra syntax.
`c0-export-table.test.ts` — the six 2.x version literals here are NOT
flipped, deliberately. They are a frozen C0 stamp sitting beside
`forgeCommit: 'feat/c0-alignment-audit'`; bumping the versions while leaving
the commit would make the artifact claim the C0 audit ran against 3.8.0
deps, which it did not. A dated record stays dated. Commented as a frozen
stamp, with a pointer to where current dependency truth actually lives
(`engine-deps-3x.test.ts`, which reads it live).
Also corrected here: a second pointer to `packages/cli/src/c1-forge-manifest.test.ts`,
which does not exist — same dead reference as the one in
`c1-manifest-truth.test.ts`. The checks are in `c1-gate.test.ts`. Two files
pointed at a file nobody had opened, which is the EB-011 failure mode in
miniature.
133 files / 2413 tests.
Refs [[2p5d-forge-engine-dep-bump-kickoff]] §1.5
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(deps): handback — two ANDONs, one of them the errand's own premise
Short, because this was an errand. Records what landed, the two halts, and
the four things the advisor should look at before merging: the engine-side
scope call (I flipped four version-skew items where the brief named one, and
items 2/3 revert cleanly if that reads as over-reach), the GENRE_MAP ANDON
routed to C3, the one-directional item-slot guard, and two declarations left
deliberately untouched.
Also carries the errors, since they are the reusable part: the type pin
proven to fail by injecting the field and rebuilding; the positive control
that failed on first run and is the only reason I know the ANDON block
discriminates; and two files pointing at a test file that does not exist.
Compensator table included — nothing beyond the authorised set was done.
Refs [[2p5d-forge-engine-dep-bump-kickoff]] §5
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(deps): correct the 3.8.0 publish date — the night before C1, not months
The errand's evidence conflated npm's package 'created' timestamp
(2026-03-07, the v1.x-era first publish) with 3.8.0's publish time
(2026-07-28T23:12Z). The conclusion stands unchanged — the C1 gate
surface has never been published — and the corrected fact sharpens it:
the packages were cut the night before C1 merged. Advisor amendment at
the verification gate.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>1 parent 86e54f1 commit 98301d4
9 files changed
Lines changed: 698 additions & 107 deletions
File tree
- docs/engine-deps-3x
- packages/export-ai-rpg
- src
- __tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
| 53 | + | |
54 | 54 | | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
62 | 65 | | |
63 | 66 | | |
0 commit comments