clone

a browser grid puzzle game where you push words around to rewrite the rules of each level

main
miau-is-true / openspec / changes / archive / 2026-09-23-expose-sentence-spans / design.md
design.md 3.0K source

Context

The engine already deduplicates semantic rules so simulation does not apply the same subject IS predicate more than once. The designer's sentence bars need a different view: every physical sentence on the board, including exact duplicates and stacked-word paths. E3 has been implemented in the engine and tests; this change records that landed contract before the implementation is committed.

Goals / Non-Goals

Goals:

  • Expose state.sentences: [{ ids, axis }] for presentation consumers.
  • Preserve one semantic rule per unique sentence meaning in state.rules.
  • Keep exact duplicate physical runs, stacked-word paths, and horizontal/vertical axes deterministic.
  • Drop strict subset spans when a longer span exists on the same axis.

Non-Goals:

  • Changing rule semantics, movement, transformations, contact effects, or event payloads.
  • Drawing sentence bars or choosing their visual placement.
  • Adding new vocabulary or changing the parser beyond the physical span projection.

Decisions

1. Keep semantic rules and physical spans as separate projections

The parser discovers candidate source paths once. It emits every physical path into state.sentences, while the existing semantic map keeps only the first deterministic source for each rule text. A renderer uses spans for bars and rules for behavior.

2. Store only source IDs and axis in spans

The span contract is intentionally small: ids preserves the source word entity order and axis is h or v. Positions and text remain available from state objects, avoiding a second mutable representation that could drift from the board.

3. Filter strict subsets by axis and source membership

After candidates are collected, remove a span when another candidate on the same axis has more source IDs and contains every ID in the shorter span. Exact duplicates are retained because they are distinct candidate records and have equal length. This matches the prototype parser's maximal-span behavior.

4. Recompute spans with rules

state.sentences is rebuilt whenever rules are refreshed, including reset, word movement, undo restoration, and transformations that trigger a re-scan. It is derived state and is not independently edited by mods or renderers.

Risks / Trade-offs

  • [ID membership can mistake disjoint spans for subsets] → Require same-axis and strict-length comparisons while retaining candidate order; fixtures cover horizontal, vertical, stacked, and duplicate cases.
  • [Consumers assume semantic rule count equals bar count] → Document state.sentences as the physical source and keep state.rules as the semantic source of truth.
  • [Parser changes alter bar order] → Preserve deterministic discovery order and assert exact ordered spans in engine tests.

Migration Plan

  1. Keep existing state.rules consumers unchanged.
  2. Read state.sentences in sentence-bar rendering when that separate presentation change lands.
  3. Archive this change after the engine implementation and tests are committed.

Open Questions

None for the E3 data contract.