feat(thressgame-coverage): Wave 2 (entity attrs + aura + RNG + marker factory)
- T6: 7 new entity attrs (EntityKind, MarkerKind, MarkerLifetime, MarkerOwner, MarkerLinks, RngSeed, RngStream) + registerAttrConsumer - T7: aura compute admits markers via EntityKind discriminator (default-to-piece policy); +getEntityKind helper - T8: 5 movement-replacement attrs (MovesAs, MovesAlsoAs, SlideMustBeMaxDistance, BlockAllExceptKing, KingExtraReach) - T9: Mulberry32 PRNG (SeededRng) + deriveSeedFromGameId + engine.rng()/setRngSeed() with persistent RngStream advancement - T10: engine.spawnMarker/removeMarker/getMarkersAtSquare with hardcoded priority table (portal-end<frozen-square<mine<...<blocked) + entity-id tiebreak Tests: 1970 -> 2014 (+44). bun run check exit 0.
This commit is contained in:
parent
2368a24b15
commit
abe5bf49a8
12 changed files with 1315 additions and 16 deletions
|
|
@ -185,3 +185,314 @@ The 100-iteration loop itself (excluding Vitest startup) executes well under the
|
|||
- Audit file: **342** lines, **75** numbered callsite rows
|
||||
- Evidence: `.sisyphus/evidence/task-4-position-audit.txt`
|
||||
|
||||
|
||||
## [2026-04-26T08:21Z] T6 entity / marker / RNG attrs
|
||||
|
||||
### What landed
|
||||
- 3 named type aliases ABOVE `ChessAttrMap` in `packages/chess/src/schema.ts`:
|
||||
`EntityKindValue`, `MarkerKindValue`, `MarkerLifetimeValue`.
|
||||
All exported so downstream tasks (T7 EntityKind filters; T10 marker
|
||||
factory; T19 lifetime decrementer; RNG primitives) can import them.
|
||||
- 7 attrs appended to `ChessAttrMap` in declaration order:
|
||||
`EntityKind, MarkerKind, MarkerLifetime, MarkerOwner, MarkerLinks,
|
||||
RngSeed, RngStream`.
|
||||
- 7 `registerAttrConsumer(...)` calls appended to the END of the
|
||||
block in `packages/chess/src/modifiers/apply.ts` (lines 116-122).
|
||||
Placement at end-of-block minimises merge friction with T8 (which
|
||||
the brief warned will also append here).
|
||||
- 7 new tests in `packages/chess/src/schema.test.ts` under describe
|
||||
`T6 marker + RNG attrs`.
|
||||
|
||||
### Import paths verified (use these in T7/T8/T10)
|
||||
- `EntityId` — `import type { EntityId } from "@paratype/rete"` (already
|
||||
imported at `schema.ts:9`; no re-import needed by future tasks that
|
||||
pull from `./schema.js`).
|
||||
- New value types — `import { type EntityKindValue, type MarkerKindValue,
|
||||
type MarkerLifetimeValue } from "./schema.js"`.
|
||||
|
||||
### Conventions followed
|
||||
- `MarkerOwner` value type is `PieceColor` (`"white" | "black"`); absence
|
||||
of the fact encodes "no owner" — do NOT insert `undefined`. (Brief
|
||||
rationale was correct.)
|
||||
- `MarkerLifetime` field names are `kind` + `expiresAtMove` exactly,
|
||||
matching `decisions.md:44`. `expiresAtMove` is an ABSOLUTE move count
|
||||
comparison (T19 will compare against `FullmoveNumber` or equivalent).
|
||||
- `MarkerKind` is the locked 8-value union — no `string` widening.
|
||||
|
||||
### Surprises / gotchas
|
||||
- Brief said `apply.ts` block is at `packages/chess/src/modifiers/custom/apply.ts`
|
||||
lines 95-113; ACTUAL location is `packages/chess/src/modifiers/apply.ts`
|
||||
lines 95-114. The `custom/apply.ts` file is the descriptor walker, not
|
||||
the consumer registration site. Mirror this when wiring T7/T8.
|
||||
- `schema.test.ts` uses `chessFact()` factory + `EntityId` brand cast
|
||||
via `mkId(n)` helper — NOT a live `Session`. Mirror this lighter
|
||||
pattern; full Session round-trip belongs in engine-level integration
|
||||
tests, not the pure-schema test file.
|
||||
- `bun run check` runs typecheck → lint → vitest (workspace mode).
|
||||
Vitest project name for chess is `|chess|`. Test count after T6 =
|
||||
**1990** (was 1970 baseline; +20 because parallel tasks have already
|
||||
landed in the same wave window — the +7 from T6 alone is included).
|
||||
- `assertSeedConsumerIntegrity` only asserts that EVERY primitive-seeded
|
||||
attr has a consumer; it does NOT complain about consumers without
|
||||
seed-side coverage. So registering `RngSeed`/`RngStream` consumers
|
||||
before any RNG primitive seeds them is safe and forward-compatible.
|
||||
|
||||
### Verification
|
||||
- `bun test packages/chess/src/schema.test.ts` → 18 pass / 0 fail
|
||||
- `bunx vitest run schema.test.ts manifest.test.ts` → 23 pass
|
||||
- `bun run check` → exit 0, 1990 tests across 170 files
|
||||
- Evidence: `.sisyphus/evidence/task-6-attrs.txt`
|
||||
|
||||
|
||||
## [2026-04-26T08:24Z] T9 RNG (Mulberry32 + engine.rng + GAME_ENTITY seeding)
|
||||
|
||||
### What landed
|
||||
- `packages/chess/src/util/rng.ts` — `class SeededRng` (Mulberry32) +
|
||||
`deriveSeedFromGameId(gameId)` (FNV-1a 32-bit). No deps; verbatim
|
||||
reference Mulberry32 constants — do NOT "optimize" the bit pattern,
|
||||
it's load-bearing for cross-impl determinism.
|
||||
- `packages/chess/src/util/rng.test.ts` — 13 tests / 5086 expects.
|
||||
Includes 1000-iter range guards on `next()` and `nextInt(N)`,
|
||||
golden-sequence regression for seed=1 (any value change is a plan-
|
||||
amending event), pick/empty throw, FNV uint32 invariant.
|
||||
- `packages/chess/src/engine.ts` —
|
||||
1. New `gameId?: string` field on `EngineOptions`.
|
||||
2. RngSeed/RngStream seeded UNCONDITIONALLY in the constructor,
|
||||
BEFORE `applyProfileToSession` / preset activation, so any
|
||||
`onActivate` hook that draws (future RNG-shuffled starting
|
||||
positions, etc.) sees initialized facts. Default seed when no
|
||||
gameId = `deriveSeedFromGameId(undefined)` = 1.
|
||||
3. `engine.rng()` returns a handle with `next/nextInt/pick`. EACH
|
||||
call advances the persistent RngStream by 1 by re-reading the
|
||||
fact, constructing a fresh `SeededRng(seed + currentStream)`,
|
||||
then `insert(GAME_ENTITY, "RngStream", currentStream + 1)`.
|
||||
4. `engine.setRngSeed(numberOrString)` resets stream to 0 and
|
||||
overrides seed; for tests / late-binding server boot.
|
||||
|
||||
### RNG init location decision
|
||||
- **Constructor**, NOT integration preset boot. Rationale:
|
||||
RngSeed/RngStream are GAME-level facts (not modifier-related); the
|
||||
constructor is the only call site guaranteed to fire for every
|
||||
engine regardless of whether a profile / preset is active. The
|
||||
`__modifier-profile-integration__` preset only activates when a
|
||||
profile is supplied — putting RNG init there would make any
|
||||
profileless engine throw at first `engine.rng()` call.
|
||||
- This decision keeps T9 independent of T6's preset boot path; no
|
||||
edits to `modifiers/custom/apply.ts` or `modifiers/apply.ts`
|
||||
needed.
|
||||
|
||||
### engine.rng() return shape (for Wave 7 — T36 with-probability, T37 random-pick)
|
||||
```ts
|
||||
{
|
||||
next(): number; // [0, 1) — advances stream by 1
|
||||
nextInt(max: number): number; // [0, max) — advances stream by 1
|
||||
pick<T>(arr: readonly T[]): T; // throws on empty — advances stream by 1
|
||||
}
|
||||
```
|
||||
**Critical for T36/T37**: ONE call = ONE stream advance = ONE
|
||||
draw. Don't cache the handle then call `next()` 5 times expecting
|
||||
the same value; each call re-reads the stream. To draw N times for
|
||||
one effect, call N times — the stream offset is what makes each
|
||||
distinct.
|
||||
|
||||
### Subtleties for downstream RNG consumers
|
||||
- The "draws-before-suspension" invariant (decisions.md:140) is
|
||||
enforced in the VALIDATOR (T19), not in the engine — the RNG
|
||||
itself doesn't know about suspension. T36's `with-probability`
|
||||
must call `engine.rng().next()` BEFORE selecting then/else arm,
|
||||
and the validator must reject any `request-choice` nested inside
|
||||
with-probability.
|
||||
- `setRngSeed` mid-game IS allowed but breaks replay-from-this-
|
||||
point. Server boot path: pass `gameId` to constructor for the
|
||||
authoritative session; clients receive `RngSeed`/`RngStream`
|
||||
facts via the standard fact-sync (no special-casing needed —
|
||||
they're just facts on GAME_ENTITY).
|
||||
- `assertSeedConsumerIntegrity` (T6) already covers
|
||||
RngSeed/RngStream consumer registration; T9 added zero
|
||||
registerAttrConsumer calls (per brief — would have raced T6).
|
||||
|
||||
### Verification
|
||||
- `bun test packages/chess/src/util/rng.test.ts` → 13 pass / 0 fail
|
||||
- `bun test packages/chess/src/engine-presets.test.ts` → 24 pass / 0 fail (added 9 rng integration tests)
|
||||
- `bun run check` → exit 0, 1999 tests across 170 files (added 13 unit + 9 engine-integration; net delta vs previous T6 baseline reflects parallel tasks landing in the same wave)
|
||||
- Evidence: `.sisyphus/evidence/task-9-rng.txt`
|
||||
|
||||
## [2026-04-26T08:30:00Z] T8 movement-replacement attrs
|
||||
|
||||
### Added (Wave 2 schema/registration only)
|
||||
|
||||
5 new attrs on `ChessAttrMap` in `packages/chess/src/schema.ts`:
|
||||
|
||||
| Attr | Type | Scope |
|
||||
|------|------|-------|
|
||||
| `MovesAs` | `PieceType` | per-piece (override native pattern) |
|
||||
| `MovesAlsoAs` | `PieceType` | per-piece (additive secondary pattern) |
|
||||
| `SlideMustBeMaxDistance` | `boolean` | per-piece OR `GAME_ENTITY` |
|
||||
| `BlockAllExceptKing` | `boolean` | `GAME_ENTITY` only |
|
||||
| `KingExtraReach` | `number` | per-piece |
|
||||
|
||||
5 matching `registerAttrConsumer(...)` calls appended to
|
||||
`packages/chess/src/modifiers/apply.ts` (location confirmed
|
||||
consistent with T6 — NOT `modifiers/custom/apply.ts`). Append-only
|
||||
edit; T6's 7 RNG/marker registrations were already present, so no
|
||||
race / overwrite occurred.
|
||||
|
||||
### Confirmation re: apply.ts location
|
||||
|
||||
T6's earlier learnings entry was correct: the file is
|
||||
`packages/chess/src/modifiers/apply.ts` (line ~88+ holds the existing
|
||||
`registerAttrConsumer` block). The `modifiers/custom/apply.ts` file
|
||||
exists but is for custom-modifier *application*, not consumer
|
||||
registration. T8 followed T6's pattern.
|
||||
|
||||
### Scope guardrails honoured
|
||||
|
||||
- NO move-gen wiring touched. `MovesAs` / `MovesAlsoAs` / etc. are
|
||||
pure schema entries; the readers land in Wave 7 (T40 set-moves-as,
|
||||
T41 pawn-pushes-pieces) and Wave 10 (T64 ice-physics test consumes
|
||||
`SlideMustBeMaxDistance`).
|
||||
- NO defaults seeded. Move-gen treats absence-of-fact as "use
|
||||
natural movement", per the brief.
|
||||
- NO validator gate on `MovesAs: "king"` — V1 just stores; the
|
||||
reject-on-king restriction is T40's job (validator wave).
|
||||
|
||||
### Test deltas
|
||||
|
||||
- Added 5 tests in `packages/chess/src/schema.test.ts` under
|
||||
`describe("T8 movement-replacement attrs (Wave 2)")` mirroring
|
||||
T6's chessFact round-trip pattern.
|
||||
- Schema test file: 18 → 23 pass.
|
||||
- Workspace total: 1999 → **2006 pass** (delta +7 = my 5 + 2 from
|
||||
expanding existing T6-style "every PieceType" loops).
|
||||
|
||||
### Verification
|
||||
|
||||
- `bun test packages/chess/src/schema.test.ts` → 23 pass / 0 fail.
|
||||
- `bun test packages/chess/src/modifiers/primitives/consumer-integration.test.ts` → 6 pass / 0 fail (no regression — `assertSeedConsumerIntegrity` happy with the 5 new declarations).
|
||||
- `bun run check` → **exit 0, 2006 tests / 170 files**.
|
||||
- Evidence: `.sisyphus/evidence/task-8-movement-attrs.txt`
|
||||
|
||||
## [2026-04-26T14:29Z] T7 aura compute + markers
|
||||
|
||||
### What landed
|
||||
- `packages/chess/src/modifiers/auras.ts` — added exported `getEntityKind(session, id)` helper + renamed internal walker `collectPiecesWithPositions` → `collectPositionedEntities`. Walker now filters via the `EntityKind` discriminator (admits `"piece"` and `"marker"`) instead of the raw `id > 0` rejection. Net behavior change for current callers = **none** (no markers exist yet); structural surface for T10 / T18 / T28 = **ready**.
|
||||
- `packages/chess/src/modifiers/auras.test.ts` — +2 tests under new describe `aura compute — markers participate (T7)`. All 10 prior tests pass byte-identical.
|
||||
|
||||
### CROSS-CUTTING DECISION — `EntityKind` default policy
|
||||
- **Locked policy**: `EntityKind` defaults to `"piece"` when **absent AND `PieceType` is set**. Returns `undefined` if neither is set.
|
||||
- Rationale: `engine.spawnPiece` (engine.ts:841-869) does NOT seed `EntityKind` (T6 only added the schema slot). A retroactive sweep through `spawnPiece` + every test fixture that bypasses the factory would be a Wave-2-scope-creep. Defaulting to `"piece"` keeps every legacy piece visible to EntityKind consumers, while markers (T10) MUST insert `EntityKind = "marker"` explicitly.
|
||||
- **Every later EntityKind consumer MUST honor this policy** — call `getEntityKind` directly. Specifically:
|
||||
- T10 (marker factory): set `EntityKind = "marker"` explicitly. Don't rely on absence.
|
||||
- T18 (on-piece-entered-marker): use `getEntityKind` to confirm the entering entity is a piece, and probe markers at the destination via `EntityKind === "marker"`.
|
||||
- T28 (spawn-marker primitive): same — explicit `"marker"` fact.
|
||||
- Audit fixes from `position-audit.md` (T6/T7 column): when adding `EntityKind === "piece"` filters, prefer `getEntityKind(session, id) === "piece"` to inherit the legacy default.
|
||||
- Once a future cleanup sweep adds `EntityKind = "piece"` to `engine.spawnPiece`, the `PieceType`-fallback branch in `getEntityKind` can be retired without behavior change.
|
||||
|
||||
### Helper location
|
||||
- `getEntityKind` lives in `packages/chess/src/modifiers/auras.ts` (top of file, exported). Reasoning: T7 is the first consumer; a dedicated `util/entity-kind.ts` file would be premature for a 30-line helper. T10 / T18 import via `import { getEntityKind } from "../modifiers/auras.js"`. If a 3rd consumer arrives outside `modifiers/`, hoist to `util/` then.
|
||||
|
||||
### Test harness pattern (REUSE for T10, T18, T28, Wave 8/10)
|
||||
- Markers can be raw-inserted in tests until `engine.spawnMarker` lands:
|
||||
```ts
|
||||
const markerId = engine.session.nextId();
|
||||
engine.session.insert(markerId, "EntityKind", "marker");
|
||||
engine.session.insert(markerId, "MarkerKind", "treasure"); // any locked kind
|
||||
engine.session.insert(markerId, "Position", squareIndex);
|
||||
// optional: AuraSpec, MarkerLifetime, MarkerOwner, MarkerLinks
|
||||
```
|
||||
- This pattern is BACKWARD-COMPATIBLE — the type system accepts it (T6 added the attrs). When T10's factory lands, tests can migrate or coexist.
|
||||
- Square index reminder: file + rank*8. e2 = 12, d3 = 19, e1 = 4. Same convention as T2's harness notes.
|
||||
|
||||
### Subtle behavior contracts pinned by tests
|
||||
1. **Marker → adjacent piece**: marker with `AuraSpec` IS picked up as an emitter; pieces in range receive contributions normally. Locked.
|
||||
2. **Piece → marker (benign noop)**: marker WITHIN range of a piece's aura DOES receive an `AuraContributions` fact. Documented as benign because nothing reads piece-only attrs (HpBonus, AttackBonus, etc.) off a marker. **Contract**: if a future feature exposes piece-attrs on markers, this test will catch the hazard. T10 / T22 must NOT introduce piece-attr reads on marker entities without revisiting this test.
|
||||
|
||||
### Surprises / gotchas
|
||||
- `Session<…>` IS NOT generic at the public-API surface used here — `session.allFacts()` returns untyped facts. Casts (`f.value as Square`) are still needed. The `getEntityKind` signature uses raw `Session` (no generic param) to match the existing aura code's style; same casts apply.
|
||||
- `EntityKindValue` is exported from `schema.ts:32` (T6). Use the type alias, not a string-literal union, when typing helpers.
|
||||
- The pre-existing `id > 0` filter in `collectPositionedEntities` is RETAINED as defense-in-depth: `EntityKind` defaults catch most cases but `GAME_ENTITY` (id 0) and `PRESET_STATE_ENTITY` (id -1) might accidentally carry a `Position` fact via unrelated subsystems. Belt + suspenders.
|
||||
- Existing `findPieceAtSquare` test helper in auras.test.ts pre-dates the marker era — it returns the FIRST entity at a square. With markers in play it could now match a marker. Tests in this file place markers on squares with no overlap with pieces under test, so this hasn't surfaced; downstream tests should prefer an EntityKind-filtered helper or use distinct squares.
|
||||
|
||||
### Verification
|
||||
- `bun test packages/chess/src/modifiers/auras.test.ts` → 12 pass / 0 fail (10 existing + 2 new), 165 expects
|
||||
- `bun run check` → exit 0, **2006 tests** across 170 files (T7 added +2; T8 landed in the same wave window contributing +5)
|
||||
- LSP diagnostics: clean on `auras.ts` AND `auras.test.ts`
|
||||
- Evidence: `.sisyphus/evidence/task-7-marker-aura.txt`
|
||||
|
||||
|
||||
## [2026-04-26T08:32Z] T10 marker entity factory (engine.spawnMarker / removeMarker / getMarkersAtSquare)
|
||||
|
||||
### Method signatures (added to ChessEngine in `packages/chess/src/engine.ts`)
|
||||
```ts
|
||||
spawnMarker(
|
||||
kind: MarkerKindValue,
|
||||
square: Square,
|
||||
opts: {
|
||||
readonly lifetime: MarkerLifetimeValue;
|
||||
readonly owner?: PieceColor;
|
||||
readonly links?: readonly EntityId[];
|
||||
},
|
||||
): EntityId;
|
||||
|
||||
removeMarker(id: EntityId): void; // idempotent — guarded by per-attr `get` check
|
||||
getMarkersAtSquare(square: Square): EntityId[]; // sorted by MARKER_KIND_PRIORITY asc, tie-break by entity id asc
|
||||
```
|
||||
|
||||
- File location: `packages/chess/src/engine.ts:920-998` (right after
|
||||
`spawnPiece`, before `dealDamage`). Did NOT conflict with T9's
|
||||
`rng()` / `setRngSeed()` block (those are above in the same class).
|
||||
|
||||
### Priority table location
|
||||
- `MARKER_KIND_PRIORITY` is a module-level const in `engine.ts`
|
||||
(above the `ChessEngine` class). Hardcoded verbatim from T0 ADR
|
||||
in `decisions.md` § Marker Collision Priority. Do NOT introduce
|
||||
a runtime override path — adding a new marker kind is a
|
||||
plan-amending event.
|
||||
- `MARKER_ATTRS` (sibling const) is the canonical list of attrs
|
||||
`removeMarker` retracts: EntityKind, MarkerKind, Position,
|
||||
MarkerLifetime, MarkerOwner, MarkerLinks. T18 and T30 should
|
||||
reference this same list when implementing on-piece-entered-marker
|
||||
cleanup and the despawn-marker primitive (don't rebuild it).
|
||||
|
||||
### Tie-break choice (LOCKED for T18 dispatch parity)
|
||||
- Secondary sort in `getMarkersAtSquare` is `(a as number) - (b as number)`
|
||||
— entity id ASCENDING. So two markers of the SAME kind on one
|
||||
square always resolve in spawn order (older id wins). T18's
|
||||
`on-piece-entered-marker` MUST iterate the result of
|
||||
`getMarkersAtSquare` directly to inherit this ordering — do not
|
||||
re-sort, do not invert.
|
||||
|
||||
### Optional-fact discipline (cross-task contract)
|
||||
- `MarkerOwner` and `MarkerLinks` are ONLY inserted when
|
||||
caller-supplied. `engine.session.get(id, "MarkerOwner")` returns
|
||||
`undefined` for neutral markers — consumers MUST treat undefined
|
||||
as "no owner" (do not coerce to a default color). T18/T28/T29/T30
|
||||
primitives that read MarkerOwner need an explicit `=== undefined`
|
||||
check.
|
||||
- `removeMarker` retracts each attr individually (guarded by a
|
||||
presence check) so it is safe on entities that never had owner
|
||||
or links facts. Idempotent — calling twice does not throw.
|
||||
|
||||
### Cascade-removal NOT in scope (T30 deferral)
|
||||
- `removeMarker` does NOT touch `MarkerLinks` partners. Removing a
|
||||
portal-end marker leaves its paired endpoint intact; T30
|
||||
(despawn-marker primitive) owns paired-cleanup semantics so
|
||||
callers retain control over portal-pair behavior.
|
||||
|
||||
### EntityKind discriminator filtering
|
||||
- `getMarkersAtSquare` iterates `session.allFacts()` filtering
|
||||
`attr === "Position" && value === square`, then narrows by
|
||||
`session.get(id, "EntityKind") === "marker"`. Confirms T7's
|
||||
EntityKind audit pattern — every Position-attr consumer that
|
||||
cares about pieces vs. markers must perform the same narrowing.
|
||||
- Pieces in the standard starting layout do NOT have EntityKind
|
||||
facts seeded yet (T7's job per the audit list). The
|
||||
`getMarkersAtSquare(0)` test on a starting-position rook returns
|
||||
`[]` because `EntityKind` on the rook is `undefined`, which
|
||||
fails the `=== "marker"` check — works either way (filter is
|
||||
positive, not negative).
|
||||
|
||||
### Verification
|
||||
- `bun test packages/chess/src/engine.spawnMarker.test.ts` → 8 pass / 0 fail / 20 expects
|
||||
- `bun run check` → exit 0, **2014 tests** across 171 files (was 1999 after T9; +8 from T10's new file, +7 from T7/T8 parity tests landing in same wave)
|
||||
- Evidence: `.sisyphus/evidence/task-10-marker-priority.txt`
|
||||
|
|
|
|||
|
|
@ -568,7 +568,7 @@ Max Concurrent: 8 (Waves 5+6+7+9 overlap)
|
|||
- Message: `docs(thressgame): param walker var-conflict audit`
|
||||
- Files: `.sisyphus/notepads/thressgame-coverage/var-conflict-audit.md`
|
||||
|
||||
- [ ] 6. New entity attrs (EntityKind, MarkerKind, MarkerLifetime, MarkerOwner, MarkerLinks, RngSeed, RngStream)
|
||||
- [x] 6. New entity attrs (EntityKind, MarkerKind, MarkerLifetime, MarkerOwner, MarkerLinks, RngSeed, RngStream)
|
||||
|
||||
**What to do**:
|
||||
- Edit `packages/chess/src/schema.ts`: extend ChessAttrMap with `EntityKind: "piece" | "marker"`, `MarkerKind: "mine" | "pit" | "portal-end" | "frozen-square" | "treasure" | "death-square" | "tornado" | "blocked"`, `MarkerLifetime: { kind: "permanent" } | { kind: "moves"; expiresAtMove: number } | { kind: "one-shot" }`, `MarkerOwner: "white" | "black" | undefined`, `MarkerLinks: readonly EntityId[]`, `RngSeed: number`, `RngStream: number`
|
||||
|
|
@ -610,7 +610,7 @@ Max Concurrent: 8 (Waves 5+6+7+9 overlap)
|
|||
- Message: `feat(chess): marker + RNG entity attrs`
|
||||
- Files: `packages/chess/src/schema.ts`, `packages/chess/src/modifiers/custom/apply.ts`, `packages/chess/src/schema.test.ts`
|
||||
|
||||
- [ ] 7. Aura compute filter (markers participate)
|
||||
- [x] 7. Aura compute filter (markers participate)
|
||||
|
||||
**What to do**:
|
||||
- Edit `packages/chess/src/modifiers/auras.ts`: in `computeAuraFacts()`, where it walks all entities, change filter from "has PieceType" to "EntityKind in {piece, marker}"
|
||||
|
|
@ -652,7 +652,7 @@ Max Concurrent: 8 (Waves 5+6+7+9 overlap)
|
|||
- Message: `feat(chess): aura compute includes markers`
|
||||
- Files: `packages/chess/src/modifiers/auras.ts`, `packages/chess/src/modifiers/auras.test.ts`
|
||||
|
||||
- [ ] 8. Movement-replacement attrs
|
||||
- [x] 8. Movement-replacement attrs
|
||||
|
||||
**What to do**:
|
||||
- Edit `packages/chess/src/schema.ts`: add `MovesAs: PieceType | undefined` (per piece — overrides movement pattern), `MovesAlsoAs: PieceType | undefined` (per piece — additive secondary pattern), `SlideMustBeMaxDistance: boolean` (per piece OR game), `BlockAllExceptKing: boolean` (game), `KingExtraReach: number` (per piece)
|
||||
|
|
@ -690,7 +690,7 @@ Max Concurrent: 8 (Waves 5+6+7+9 overlap)
|
|||
- Message: `feat(chess): movement-replacement attrs`
|
||||
- Files: schema.ts, apply.ts, schema.test.ts
|
||||
|
||||
- [ ] 9. Mulberry32 PRNG utility + integration-preset seed init
|
||||
- [x] 9. Mulberry32 PRNG utility + integration-preset seed init
|
||||
|
||||
**What to do**:
|
||||
- Create `packages/chess/src/util/rng.ts` exporting `class SeededRng { constructor(seed: number); next(): number /* 0..1 */; nextInt(max: number): number; pick<T>(arr: readonly T[]): T }`
|
||||
|
|
@ -733,7 +733,7 @@ Max Concurrent: 8 (Waves 5+6+7+9 overlap)
|
|||
- Message: `feat(chess): seeded Mulberry32 PRNG + integration preset init`
|
||||
- Files: `packages/chess/src/util/rng.ts`, `packages/chess/src/util/rng.test.ts`, `packages/chess/src/modifiers/custom/apply.ts`
|
||||
|
||||
- [ ] 10. Marker entity factory (engine.spawnMarker)
|
||||
- [x] 10. Marker entity factory (engine.spawnMarker)
|
||||
|
||||
**What to do**:
|
||||
- Edit `packages/chess/src/engine.ts`: add `spawnMarker(kind: MarkerKind, square: Square, opts: { lifetime: MarkerLifetime; owner?: Color; links?: readonly EntityId[] }): EntityId` (mirrors `spawnPiece` pattern at engine.ts:741-769)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue