Jumping into an undiscovered system now spreads a seeded-random 1–4 legs instead of a fixed 4. Interpretation of the "more circular" part of the issue:
Each leg has a 35% chance to close onto the existing chart: instead of minting a new system it becomes a new two-way route to a randomly chosen existing system — loops in the graph make the map more circular and it grows ~2.3x slower on average (~1.7 new systems per discovery instead of 4).
A leg that would duplicate an already-existing route mints a new system instead (no wasted legs, no PK violations).
Frontier guarantee: at least one new system is always minted per discovery, so the map can never exhaust (invariant the e2e helpers rely on).
All randomness is drawn from the existing seeded expansionRng(seed, turn) stream in a fixed order — the same save + turn always reproduces the same chart.
Also fixes a latent bug: ringEdges for 1-2 members emitted a self-loop / duplicate route that would violate the jump_routes primary key (unreachable before, since the count was fixed at 4; n>=3 output is byte-identical, start region unchanged).
Verification
Unit: 194/194 (rewritten world.test.ts ringEdges + generateRing suite incl. pinned deterministic values and the frontier guarantee; save.test.ts now asserts 1-4 fresh systems; A/B full-DB byte-identity snapshot test unchanged and passing)
E2E (CI-only): new smoke test — jump into undiscovered territory mints 1-4 new systems, each undiscovered and routed to the target, and the graph stays connected (BFS)
## #51 — map spread limit (v0.13.0)
Jumping into an undiscovered system now spreads a **seeded-random 1–4 legs** instead of a fixed 4. Interpretation of the "more circular" part of the issue:
- Each leg has a **35% chance to close onto the existing chart**: instead of minting a new system it becomes a new two-way route to a randomly chosen existing system — loops in the graph make the map more circular and it grows ~2.3x slower on average (~1.7 new systems per discovery instead of 4).
- A leg that would duplicate an already-existing route mints a new system instead (no wasted legs, no PK violations).
- **Frontier guarantee**: at least one new system is always minted per discovery, so the map can never exhaust (invariant the e2e helpers rely on).
- All randomness is drawn from the existing seeded `expansionRng(seed, turn)` stream in a fixed order — the same save + turn always reproduces the same chart.
Also fixes a latent bug: `ringEdges` for 1-2 members emitted a self-loop / duplicate route that would violate the `jump_routes` primary key (unreachable before, since the count was fixed at 4; n>=3 output is byte-identical, start region unchanged).
### Verification
- Unit: 194/194 (rewritten `world.test.ts` ringEdges + generateRing suite incl. pinned deterministic values and the frontier guarantee; `save.test.ts` now asserts 1-4 fresh systems; A/B full-DB byte-identity snapshot test unchanged and passing)
- E2E (CI-only): new smoke test — jump into undiscovered territory mints 1-4 new systems, each undiscovered and routed to the target, and the graph stays connected (BFS)
- Typecheck clean
Closes #51
- ringEdges: n=0 → [], n=1 → [[0,1]], n=2 → [[0,1],[0,2],[1,2]];
n≥3 wheel is byte-identical to the legacy output.
- generateRing: new params attachCandidates, existingEdgeKeys, anchorId;
legCount is seeded-random in [EXPAND_MIN, EXPAND_MAX] (1–4);
each leg may attach a known system (closing a loop) with prob ATTACH_PROB
instead of minting; frontier guarantee converts the last-drawn attach
to a mint when all legs attached.
- RingRegion gains attaches: number[] (candidate indices attached).
- Remove the EXPAND_RING constant (replaced by EXPAND_MIN/EXPAND_MAX).
- resolveJumpTask: build existingEdgeKeys from all jump routes (both
endpoints in the save's system set), pass all systems except the
target as attachCandidates, insert closing routes for each attach.
- save.test.ts: jump test now expects 1–4 fresh systems (was pinned
to exactly 4); A/B snapshot test stays green (both paths share the
same resolveJumpTask code).
- e2e/helpers.ts: update stale comment ('4 fresh neighbours' →
'1–4 new systems').
- e2e/smoke.spec.ts: new test verifying 1–4 mints, all undiscovered,
each routed to the target, and BFS connectivity of the full graph.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#51 — map spread limit (v0.13.0)
Jumping into an undiscovered system now spreads a seeded-random 1–4 legs instead of a fixed 4. Interpretation of the "more circular" part of the issue:
expansionRng(seed, turn)stream in a fixed order — the same save + turn always reproduces the same chart.Also fixes a latent bug:
ringEdgesfor 1-2 members emitted a self-loop / duplicate route that would violate thejump_routesprimary key (unreachable before, since the count was fixed at 4; n>=3 output is byte-identical, start region unchanged).Verification
world.test.tsringEdges + generateRing suite incl. pinned deterministic values and the frontier guarantee;save.test.tsnow asserts 1-4 fresh systems; A/B full-DB byte-identity snapshot test unchanged and passing)Closes #51
- resolveJumpTask: build existingEdgeKeys from all jump routes (both endpoints in the save's system set), pass all systems except the target as attachCandidates, insert closing routes for each attach. - save.test.ts: jump test now expects 1–4 fresh systems (was pinned to exactly 4); A/B snapshot test stays green (both paths share the same resolveJumpTask code). - e2e/helpers.ts: update stale comment ('4 fresh neighbours' → '1–4 new systems'). - e2e/smoke.spec.ts: new test verifying 1–4 mints, all undiscovered, each routed to the target, and BFS connectivity of the full graph.