fix(core): the last fixes' core half (W1 W2 W5 W19)
Stage 4 of docs/modules/rust/PLAN_LAST_FIXES.md, with the org lead's 2026-10-22 decisions. W19: one module per site at boot, as at install. The first module directory by name holds the site, whether or not it then loads; every other is recorded startup_failed at the manifest stage, before a line of its code is required, with a reason naming the module that holds the site. Module-uo and Module-Rust side by side used to fail the second with a slot collision. Loader, lifecycle, schema and event-contract tests that loaded several fixture modules now load each case alone. W1: a reconcile files a resource the game no longer has, and that is past its `until`, as expired rather than orphaned, with the same log line expired() writes. No MODULE_API bump: `until` and reconcile's answer are unchanged. W5: a dry run that passes on the draft is kept with the fingerprint of the validated spec (three nullable columns on event_definitions). Publish stamps the new version verified, with that dry run's reviewer and time, when the spec it freezes has the same fingerprint, and writes version.verified on the occurrences it re-pins. Verify answers draftRecorded and publish answers verified; OpenAPI regenerated. W2: the run console says "Phase p1: steps done, waiting to advance" and "Why this phase has not advanced", not "has not started". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -477,3 +477,20 @@ test('the size bounds hold', () => {
|
||||
assert.equal(result.ok, false)
|
||||
assert.match(result.errors.join('\n'), new RegExp(`at most ${spec.MAX_PHASES} phases`))
|
||||
})
|
||||
|
||||
test('a fingerprint is the plan, not the order its keys were written in', () => {
|
||||
// W5: publish compares the fingerprint of the spec it freezes with the one a
|
||||
// draft dry run kept. A spec that round-trips through a JSON column with its
|
||||
// keys reordered is the same plan and must carry its pass over.
|
||||
const a = { schedule: { kind: 'manual' }, phases: [{ key: 'main', label: 'Main', steps: [] }] }
|
||||
const b = { phases: [{ steps: [], label: 'Main', key: 'main' }], schedule: { kind: 'manual' } }
|
||||
assert.equal(spec.fingerprint(a), spec.fingerprint(b))
|
||||
assert.match(spec.fingerprint(a), /^[0-9a-f]{64}$/)
|
||||
|
||||
// Array order IS the plan: steps run in it.
|
||||
const c = { schedule: { kind: 'manual' }, phases: [{ key: 'main', label: 'Main', steps: [1, 2] }] }
|
||||
const d = { schedule: { kind: 'manual' }, phases: [{ key: 'main', label: 'Main', steps: [2, 1] }] }
|
||||
assert.notEqual(spec.fingerprint(c), spec.fingerprint(d))
|
||||
// And a key left undefined is the key left out, as JSON has it.
|
||||
assert.equal(spec.fingerprint({ ...a, starts: undefined }), spec.fingerprint(a))
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user