Stage 14: solver & dictionary split — consume published module + DAWG artifact (TODO-1/TODO-2)
Tests · Go / test (push) Successful in 8s
Tests · Integration / integration (push) Successful in 11s
Tests · Go / test (pull_request) Successful in 8s
Tests · Integration / integration (pull_request) Successful in 11s

- backend/go.mod pins gitea.iliadenisov.ru/developer/scrabble-solver v1.0.0; the engine's
  imports use the published module path; go.work drops the solver replace (GOPRIVATE fetches
  it directly from Gitea). The solver's wordlist/dictdawg are now public packages.
- CI (go-unit, integration): drop the solver sibling-clone, set GOPRIVATE, and download the
  dictionary DAWG release artifact (scrabble-dawg-<DICT_VERSION>.tar.gz from the new
  scrabble-dictionary repo) for BACKEND_DICT_DIR.
- Docs: ARCHITECTURE §5/§11/§13/§14 + backend/README updated to the published-module +
  release-artifact model. PLAN.md re-scoped Stage 14 to the split and added Stages 15 (deploy
  infra & test contour), 16 (prod contour), 17 (dual Telegram bots); TODO-1/TODO-2 marked done.
This commit is contained in:
Ilia Denisov
2026-06-04 20:00:36 +02:00
parent da6665b967
commit ec435c0e7f
19 changed files with 214 additions and 127 deletions
+14 -10
View File
@@ -203,9 +203,10 @@ Key points:
`Registry.LoadAvailable` (only the variants whose DAWG is present there), and a
restart re-loads every resident version via `engine.OpenWithVersions` (the flat
boot version plus each subdirectory). In-flight games keep their pinned version;
new games use the latest. (A future split of the solver into engine + dictionary
generator with versioned artifacts is recorded in [`../PLAN.md`](../PLAN.md)
TODO-2.)
new games use the latest. (The solver is published as a versioned module and the
dictionaries ship as a separate versioned **release artifact** from the
`scrabble-dictionary` repo — TODO-1/TODO-2, Stage 14; the runtime contract above is
unchanged.)
- Move generation/validation/scoring use `Solver.GenerateMoves` (ranked),
`Solver.ValidatePlay` and `Solver.ScorePlay`; board mutation uses
`scrabble.Apply`. The engine adds its own deterministic, seeded tile **bag**
@@ -469,7 +470,7 @@ promotions) is future work and would deliver short markdown messages (text + lin
`OTEL_EXPORTER_OTLP_*` environment) exports to a collector. The Postgres pool is
instrumented with otelsql and `otelgrpc` traces the backend↔gateway push stream
and the gateway↔connector calls. The OTLP collector and Grafana dashboards are
stood up with the deploy (Stage 14).
stood up with the deploy (Stage 15).
- Per-request server-side timing via gin middleware from day one (the access log
carries method, route, status, latency and the active trace id). A
client-measured RTT piggybacked on the next request is a later enhancement.
@@ -516,7 +517,7 @@ a dedicated redeem sub-limit or a longer code is the hardening step if abuse app
## 13. Deployment (informational)
Single public origin, path-routed: a mini-landing at the root, the **Telegram Mini
App under `/telegram/`** (the gateway serves the static UI build, wired in Stage 14;
App under `/telegram/`** (the gateway serves the static UI build, wired in Stage 15;
outside Telegram that path redirects to the root), the gateway public surface and the **admin console
at `/_gm`** (backend-rendered, Basic-Auth at the gateway) share one host that
terminates TLS. The **Telegram connector** runs as a separate
@@ -524,7 +525,7 @@ container with **no public ingress** — it long-polls Telegram and egresses thr
VPN sidecar, answering only internal gRPC. MVP runs one `gateway`, one `backend`, one
Postgres, plus the connector. The connector's Docker/compose ships now
(`platform/telegram/deploy`, mirroring `../15-puzzle`); the gateway's static UI serving
and the full multi-service deploy land in Stage 14.
and the full multi-service deploy land in Stage 15.
## 14. CI & branches
@@ -536,9 +537,12 @@ and the full multi-service deploy land in Stage 14.
`integration` build tag (testcontainers `postgres:17-alpine`, Ryuk disabled,
serial). Further workflows (ui-test, deploy) are added with the components they
cover.
- Since Stage 2 both Go workflows clone the public `scrabble-solver` sibling
(master HEAD, no credentials) into `../scrabble-solver` before building, so the
`go.work` `replace` resolves; the engine tests read the committed DAWGs from
that checkout via `BACKEND_DICT_DIR`.
- The engine consumes `scrabble-solver` as a **published, versioned module**
(`gitea.iliadenisov.ru/developer/scrabble-solver`, pinned in `backend/go.mod`); both Go
workflows set `GOPRIVATE=gitea.iliadenisov.ru/*` so go fetches it directly from this Gitea
(no public proxy/checksum DB, no sibling clone). The dictionaries ship as a **release
artifact** from the `scrabble-dictionary` repo; the workflows download
`scrabble-dawg-<DICT_VERSION>.tar.gz` and point the engine tests at it via
`BACKEND_DICT_DIR` (TODO-1/TODO-2 discharged in Stage 14).
- After any push, the run is watched to green before a stage is declared done
(`python3 ~/.claude/bin/gitea-ci-watch.py`).