| name | solver-search |
| description | Use when changing search, heuristics, pruning tables, generated two-phase solving, or pattern databases. |
Generated from ai/registry.json. Do not edit manually.
Canonical skill: ../../../ai/skills/solver-search.md.
Referenced context:
../../../ai/rules/solver-search-rules.md
../../../ai/rules/testing-rules.md
../../../ai/architecture/project-architecture.md
../../../ai/architecture/solver-search.md
../../../ai/architecture/cube-engine.md
../../../ai/glossary/cube-terms.md
This file is compiled from canonical AI knowledge files. Edit canonical files under ai, then run npm run ai:sync.
Compiled AI Skill: solver-search
Canonical Skill: ai/skills/solver-search.md
Solver Search
Use this skill when adding or changing IDA*, generated two-phase search, heuristics, pruning, or pattern database code.
Goal
Add search behavior only on top of correct cube state and move semantics.
Read First
ai/rules/solver-search-rules.md
ai/rules/testing-rules.md
ai/architecture/project-architecture.md
ai/architecture/solver-search.md
ai/architecture/cube-engine.md
ai/glossary/cube-terms.md
Workflow
- Verify cube move behavior before trusting search results.
- Start with shallow deterministic cases.
- Keep heuristics separate from traversal logic.
- Mark whether each heuristic is admissible.
- Add node/depth metrics for non-trivial algorithms.
Expected Output
- Search returns explicit move sequences and metrics.
- Tests cover solved state and shallow known scrambles.
- No learned or external inference heuristic is introduced without an explicit current product requirement.
Verification
- Run
cargo test -p cube-engine when Rust is installed.
- Include targeted tests for the changed search module.
Referenced Context
Reference: ai/rules/solver-search-rules.md
Solver Search Rules
Rules for search, heuristics, and pattern database work.
Always
- Keep search algorithms in
crates/cube-engine/src/search unless a later crate boundary is introduced.
- Keep heuristics explicit about admissibility.
- Prefer bounded IDA* and generated two-phase paths after move tables are correct.
- Prune inverse moves and repeated same-axis branches where correctness allows it.
- Measure node counts and depth limits for non-trivial search changes.
Never
- Do not depend on brute force as the final strategy.
- Do not mix pattern database generation with runtime search unless the boundary is explicit.
- Do not add learned or external-inference heuristics without an explicit current product requirement.
- Do not claim optimality unless the heuristic and search mode guarantee it.
Verification
- Test solved states return an empty solution.
- Test shallow scrambles with known inverse solutions.
- Test heuristic lower bounds on solved and simple states.
Reference: ai/rules/testing-rules.md
Testing Rules
Testing rules for this repository.
Always
- Add Rust unit tests next to pure functions when behavior is introduced.
- Add integration tests under the owning crate when behavior crosses module boundaries.
- Add regression tests next to changed behavior when fixing bugs.
- Test observable cube behavior: solved state, inverse moves, notation parsing, scramble inversion, validation, and search output.
- Test HTTP/API behavior through request and response contracts when
crates/api behavior changes.
- Test web API-client and UI behavior through public component or request boundaries when frontend behavior changes.
- Test scanner training code with deterministic fixtures or fixed seeds.
- Keep algorithm tests deterministic.
- Run the narrowest test first, then the affected crate test command.
- Use Vitest APIs such as
describe, it, expect, vi.fn, and vi.spyOn for web unit and component tests.
- Keep
web tests in __tests__/ folders beside the source area they cover.
- Use Testing Library for React component behavior and public accessibility queries.
- Use Playwright accessibility queries for E2E flows and shared E2E helpers for non-native controls such as Radix Select.
- Timer keyboard regressions MUST cover navigation into the timer and closing timer controls that normally restore focus, then prove keyboard timing works without manually focusing the timer display.
- Keep web API request and hook tests in the nearest API-domain
__tests__ directory, including the established root, client, and domain-level locations; use shared helpers under apps/web/src/test.
- Keep
apps/web/src/core tests under apps/web/src/core/<category>/__tests__/<name>.test.ts.
- Keep global
web coverage thresholds at 90% for statements, branches, functions, and lines.
Never
- Do not rely on random tests without a fixed seed.
- Do not assert implementation details when public cube behavior can be asserted.
- Do not leave focused-only tests such as
.only in committed test files.
- Do not add duplicate test helpers when nearby crate, web, API, or scanner helpers already cover the setup.
- Do not add tests for future surfaces that do not exist yet.
- Do not use Jest-only APIs or
jest.mock patterns in Vitest tests.
- Do not place
web tests as loose sibling *.test.ts(x) files when a nearby __tests__/ folder is available.
- Do not add duplicate web test helpers when
apps/web/src/test/render.tsx or apps/web/src/test/api.ts already covers the setup.
- Do not use Playwright
selectOption() or locator('option') for Radix Select controls; use helpers under tests/e2e/select-helpers.ts.
Verification
- Cube engine tests:
cargo test -p cube-engine.
- API tests:
npm run api:test or cargo test -p rubiks-cube-solver-api.
- Workspace tests:
cargo test.
- Web build/lint:
npm run build and npm run lint -w @rubiks-cube-solver/web.
- Web unit tests:
npm run test -w @rubiks-cube-solver/web.
- Web coverage:
npm run test:coverage -w @rubiks-cube-solver/web.
- Web Storybook:
npm run storybook:build -w @rubiks-cube-solver/web.
- End-to-end tests:
npm run test:e2e after the API, web app, and pruning-table prerequisites are available.
- E2E split commands:
npm run test:e2e:smoke for product/responsive/timer smoke, npm run test:e2e:scan for serial manual scan coverage, and npm run test:e2e:full for the complete non-heavy suite.
- Product gate:
npm run product:gate for release-level or cross-boundary validation.
- AI routes:
npm run ai:check.
Reference: ai/architecture/project-architecture.md
Project Architecture
The target is a Rubik's Cube solver with a Rust engine, search algorithms, heuristics, pattern databases, a native HTTP API, optional scanner support, and a modern web visualization.
Current Structure
crates/cube-engine: Rust crate for cube representation, moves, notation, scramble handling, search, and heuristics.
crates/api: Axum HTTP API around the Rust engine and generated pruning-table artifacts.
apps/web: Vite React app built as static HTML for indexable routes, hydrated with React, then operated as an SPA.
apps/wca-data: independent NestJS/Fastify workspace with a PostgreSQL-backed public WCA reference API and a separate import worker.
packages/rubiks-cube: active private workspace for puzzle-specific Three.js visualization and playback adapters.
scanner: Python scanner contracts, FastAPI runtime, and offline scanner training/evaluation tooling.
ai: canonical AI knowledge base and route generation system.
docs/project-plan.md: current technical direction, implementation rules, and puzzle boundaries.
Generated Artifacts
- Native pruning tables are generated by
cube-engine binaries and loaded by crates/api.
- Solver quality reports and real-scramble gates are executable verification artifacts, not frontend behavior.
Runtime And Deployment
- Docker dev is the default development runtime. Use
npm run dev to build/recreate the rubiks-dev Compose project, wait for health, and serve web/API/vision on ports 5173, 8788, and 8791.
- Local non-Docker fallback uses
dev:local:prepare and dev:local for development/debugging when Docker is not desired.
- Docker production uses the
rubiks-prod Compose project. Use live:deploy after merges to pull origin/main, rebuild/recreate containers, wait for app health, and print status.
- Use
live:restart only when the checkout is already current and containers need to be rebuilt/recreated.
live:start runs production deploy first and then starts the Cloudflare tunnel for speedcube.com.br with cloudflared tunnel run --token "$CLOUDFLARED_TUNNEL_TOKEN". live:tunnel runs only the tunnel command and assumes production Docker is already healthy.
- Docker dev, Docker production, and scanner training use separate Compose projects/commands so they do not collide.
Multi-Puzzle Direction
- Additional puzzles must own puzzle-specific state, move models, notation parsers, validators, solvers, heuristics, coordinates, and artifact rules.
- Shared multi-puzzle code is limited to metadata, registries, budgets, results, compatibility checks, API contracts, and visualization adapter selection.
- Do not introduce a generic puzzle engine, universal move type, universal state type,
BaseMove, BaseState, BasePuzzle, or inheritance-style puzzle hierarchy.
Future Or Optional Boundaries
crates/wasm: optional future wasm-bindgen bridge around the Rust engine if browser-local solving becomes a concrete product requirement.
- Additional frontend routing, shared component libraries, or state managers should wait for current UI complexity to require them.
Ownership
- Cube state, moves, validation, search, and heuristics belong in Rust.
- The API validates HTTP contracts, applies safety limits, calls Rust solver code, and returns typed solver results.
- Frontend code should only render, collect notation/limits, send solve requests, receive states, and play animations.
- Scanner runtime code may produce visual evidence, but reviewed stickers, cube validation, and solving remain Rust/product boundaries.
- WCA reference data, import lifecycle, and its public
/api/wca-data/v1 contract belong to apps/wca-data, not the Rust solver API.
Reference: ai/architecture/solver-search.md
Solver Search Architecture
Search builds on top of a correct cube engine.
Current Layers
- Bounded IDA* for depth-limited deterministic search.
- Generated two-phase search for the current classical 3x3 solver path.
- Pattern databases for fast admissible lower bounds where implemented.
- Solver portfolios for comparing deterministic strategies within explicit budgets.
Boundaries
- Search functions should accept cube states and return move sequences plus metrics.
- Heuristics should be explicit about admissibility and input assumptions.
- Pattern database generation should be separated from runtime lookup.
Reference: ai/architecture/cube-engine.md
Cube Engine Architecture
The cube engine is the source of truth for puzzle state, moves, validation, search, and replay verification. It must stay independent from UI, scanner, and HTTP transport concerns.
Modules
cube/*: current 3x3 state, moves, notation, facelets, scrambles, and high-level cube API.
puzzles/cube2/*: 2x2-specific state, moves, notation, solver, visual state, and quality reporting.
puzzle/*: puzzle identities, metadata, input kinds, visualization kinds, and strategy registry.
search/*: search, generated two-phase, pruning, and heuristic modules that consume puzzle state.
State Model
The primary representation is cubie based:
- corner permutation
- corner orientation
- edge permutation
- edge orientation
Sticker strings, Kociemba strings, and visual states are adapter formats; they should not replace the core model.
Multi-Puzzle Boundary
Additional puzzles should live in puzzle-specific modules with their own state, move model, notation parser, validation, search, heuristics, coordinates, and artifacts.
Do not add a generic puzzle engine, universal move type, universal state type, BaseMove, BaseState, BasePuzzle, or inheritance-style hierarchy. Shared Rust code should be limited to puzzle-neutral metadata, budgets, results, registries, compatibility checks, and artifact plumbing.
Unsupported Behavior
Any unimplemented puzzle behavior must fail explicitly instead of pretending to mutate, validate, or solve a state.
Reference: ai/glossary/cube-terms.md
Cube Terms
Cubie
A physical movable piece of the cube. The core engine tracks cubies rather than face colors as the primary model.
Corner
A cubie with three stickers. A 3x3 cube has eight corners.
Edge
A cubie with two stickers. A 3x3 cube has twelve edges.
Permutation
Which cubie occupies each position.
Orientation
How a cubie is twisted or flipped in its current position.
Move
A face turn such as R, U, R', or U2.
Scramble
A sequence of moves applied from the solved state to produce a valid cube state.
Heuristic
An estimate of distance from a cube state to the solved state.
Admissible Heuristic
A heuristic that never overestimates the true distance to the solved state.
Pattern Database
A precomputed lookup table mapping partial cube states to minimum solution distances.
Kociemba String
A facelet string format commonly used by two-phase solvers. It can be an adapter format, not the primary engine model.