Skip to content

Releases: CoderGamerUnknow/Project-Tango

v3.2.0

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 21:37

Four gaps between what this project claimed and what it actually verified.
One breaking change, and it is the honest kind: the server now refuses to
start on a runtime that cannot durably store your data. No tool name, parameter
or response field changed.

Changed

  • Node 22.5 is now the floor — breaking for anyone on Node 18. The package
    claimed engines.node >= 18.0.0 while node:sqlite has only existed since
    22.5, and it claimed that in the one field npm checks at install time. So a
    Node 18 user got a clean install, a working --help, and then a server that
    failed at its first write with a stack trace about a module that does not
    exist in their runtime — after they had already pointed a real agent at it.
    The claim is now true (>=22.5.0), and on an older runtime the server exits 1
    with a plain sentence explaining which version it needs and why, before it
    creates a data directory or prints a mock-data warning that would have sent
    them looking in the wrong place.
  • Two escape hatches, for the runtimes that cannot be upgraded. Set
    PROJECT_TANGO_PERSIST=0 to run stateless (nothing is written, nothing is
    lost, it just does not survive a restart), or PROJECT_TANGO_STORE=json to
    keep the JSON backend and accept that it cannot notice another process
    replacing the catalog underneath it. Both start normally, and both are stated
    in the README's new Runtime floor section rather than left in the source.

Added

  • A release gate that runs before a release, not after one. Two releases in
    a row went out over a red CI run, and the changelog/tag lineage checks that
    would have caught the cause can only run once the tag exists — so they run
    minutes after the release is public. scripts/release-check.mjs moves every
    one of those conditions to the moment you can still do something about them:
    the version agrees across package.json, package-lock.json and
    SERVER_VERSION; the changelog has a dated heading and a link for it; the tag
    is annotated, sits on main's lineage, is dated the day the heading claims,
    and is an ancestor of HEAD. It is wired as npm run release:check and runs
    in CI on tag pushes, so the mistake is caught on a private commit as often as
    on a public tag.
  • A Windows CI leg. Every gate in this project had only ever run on Linux,
    on a machine whose line endings, path separators and shell differ from the
    platform a surprising share of agent tooling is actually installed on. CI now
    builds and tests on ubuntu-latest and windows-latest in the same matrix,
    with fail-fast: false so a Windows failure is visible rather than inferred.
  • The published tarball is installed and booted before it is believed. The
    package smoke test used to run against the working tree, so it could pass on a
    build whose tarball was missing the entry point. CI now packs, installs into a
    clean directory, boots the real binary over stdio and completes a real
    place_order against it — the same check, run against the artefact users
    download.
  • The start-up refusal is tested end to end. src/bootstrap.test.ts spawns
    the real index.ts as a child process and asserts on its exit code and
    stdout: a normal runtime answers initialize, an old one exits 1 with an
    explanation and an empty stdout, and — the assertion that matters — a refused
    start leaves no data directory behind, so the failure cannot be mistaken for a
    corrupt install.

Fixed

  • The concurrency soak could not fail. 3.1.2's freshness test asserted no
    read trailed a committed write by more than one commit. Measured, that bound
    was never tested: a read cost about a quarter of a write, so the reader was
    almost always reading between commits and worstLag was structurally zero. A
    reader that refreshed only one read in sixty would have passed. The reader now
    pauses briefly between reads, so roughly three quarters of the gaps it
    observes contain two or more commits, and a new assertion fails the suite if a
    run never once put the reader behind — the test can no longer pass vacuously.
    Lazy-refresh and zero-delay variants were confirmed to fail it.
  • The Windows leg's own smoke script is verified locally, not just in CI. It
    was extracted from the workflow YAML and run against a real local pack before
    being trusted, including the case where the binary is missing and the script
    must exit non-zero rather than pass quietly.

Project Tango v3.1.2

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 17:15

Breaking for backend authors only. StateStore.changeToken is now
required rather than optional. Nothing an MCP client can see changed — no
tool name, parameter or response field — so if you only run the server,
upgrading is a normal reinstall.

Coming from 3.1.0? Those releases' data-loss defects are repaired
automatically by 3.1.1 and later; see the README's upgrade note.
Tightens the seam that 3.1.1 left loose, and proves it holds under load.
One breaking change, to the StateStore interface rather than to anything an
MCP client can see: no tool name, parameter or response field changed, and
upgrading is a normal reinstall.

Changed

  • StateStore.changeToken is now required — breaking for backend authors.
    3.1.1 fixed a server that kept serving a catalog another process had
    replaced, and made the fix reachable by omitting an optional member: a
    backend added later could leave changeToken off the interface and silently
    reinstate the exact defect, with nothing to notice it. Every backend this
    project can return already provided one, so no shipped behaviour changes. A
    backend that genuinely cannot detect another writer must now say so with
    stableToken(reason) — the limitation becomes a decision someone wrote down
    rather than a gap nobody noticed. The requirement is only that a rival's
    commit is detectable: a token that also moves on the provider's own writes is
    merely less efficient, which is what the JSON backend's size:mtime token does.
    Correctness never depends on which kind a backend provides.

Added

  • Freshness verified under load. Two real server processes, one data
    directory, forty commits spread across four products while the reader serves
    hundreds of interleaved list_all_products calls. The assertions are the ones
    that only fail once the two have had time to drift apart: no read trails a
    committed write by more than one commit, the reader is current within three
    reads of the writer going quiet, it follows the stream rather than jumping once
    at the end, and it never serves a catalog mid-write or reports stock moving
    backwards. Both ways of breaking it were confirmed to fail the suite — pinning
    the token, and refreshing only one read in sixty.
  • A performance guard on the token check. The reload the token exists to
    avoid is the expensive path; if the check ever got slower than the reload it
    would be pure overhead. A guard holds changeToken at least 20x cheaper than a
    full load on the shipped dataset (measured ~72x).

Fixed

  • The 3.1.0 release record was wrong in a way that mattered. Its body had
    stray blank lines from the original extraction, and — more importantly — it
    described two data-loss defects without telling anyone who installed it that
    they were carrying them. Both it and 3.1.1's now lead with the upgrade path: if
    your stored state holds fewer products than the seed catalog, 3.1.1 repairs it
    on its own, with no manual step and nothing you placed lost.

Project Tango v3.1.1

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 15:18

Coming from 3.1.0? Read this before anything else. The two data-loss
defects fixed below are repaired automatically on first run: the missing seed
products are re-added and written back, with no manual step. See
3.1.0.

Bug fixes and release tooling. No tool names, parameters or response fields
changed. Two data-loss defects and one write failure, all found while trying to
make a server notice that another process had written, plus the workflow that
gives every release a verified artifact.

Fixed

  • A server listed thirteen products and then refused to sell one of them.
    Saved state can legitimately hold fewer products than the seed catalog — a
    state.json written before a product was added, or one whose rows were pruned
    — and the startup reconcile put the missing ones back in memory. A transaction
    then re-read the store under its write lock and adopted that smaller row set
    verbatim, so the catalog collapsed to whatever the file happened to contain,
    and simulate_order_placement answered no product found with id "prod_001"
    for a product list_all_products had just returned. The commit that followed
    persisted the loss, so the erosion survived every restart. Reconciliation now
    happens wherever stored state is adopted, and because a commit writes what is
    in memory, the stored catalog is repaired rather than eroded.
  • A running server kept serving a catalog another process had replaced.
    Reads came from the process's own copy, which only caught up when that process
    wrote something itself — so an agent could place an order in one window and be
    told stale inventory in the next. Reads now compare a cheap change token first
    (PRAGMA data_version, stat on the JSON backend) and reload only when
    another process committed. The check is skipped during a transaction, where a
    reload would discard state that has not committed yet.

Added

  • Releases carry a verified installable tarball. A new workflow builds it,
    installs it into a clean directory, drives the binary that install ships, and
    only then attaches it to the release — on release: published, so it happens
    without being asked. Two things this fixes: v3.1.0 shipped source only, and
    an artifact attached from a contributor's machine turned out to be corrupt
    there (GitHub's asset endpoint stored the multipart envelope along with the
    file on every framing tried, so a "successful" upload produced an unusable
    download). Attaching from a runner also means the published file is the one
    that was executed, not one built alongside the release and never run.
  • StateStore.changeToken?() — an optional cheap token that moves when
    another process committed. Optional on purpose: a backend that cannot detect
    another writer keeps the previous behaviour instead of re-reading blindly.
  • Order ids carry their process id. nextOrderId proved unique only within
    one process: its sequence is module state, so two servers sharing a data
    directory minted the same id for orders placed in the same millisecond. With
    orders.id a primary key, the stored list then held that id twice and the
    second write was rejected outright — one server's order could not be placed at
    all. The pid closes the gap with no randomness: two live processes cannot share
    one, and a recycled pid only collides with an id from a different millisecond.

Fixed

  • A rejected save reported itself as a successful one. save() swallowed
    every write failure and logged it, which is right for the environment (a
    read-only disk, a closed handle) and wrong for the data: SQLITE_CONSTRAINT
    means the rows are not storable, which is a defect in what was built rather
    than where it is stored. That combination is how a caller comes to believe an
    order was placed when the transaction behind it was rolled back — the exact
    "silent partial write" this project promises cannot happen. Constraint failures
    are now rethrown; environmental ones still degrade with a warning.

Project Tango v3.1.0

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 13:02

Upgrade: install 3.1.1 before trusting this release.

3.1.0 shipped two data-loss defects. If your saved state holds fewer products
than the seed catalog — which happens after any upgrade from the old
state.json format — this release lists all thirteen products and then
refuses to sell one of them, committing the shortfall so it survives every
restart. It also reported a rejected save as a successful one, so an order can
come back with a receipt that was never written.

3.1.1 repairs this on its own. Its first transaction re-adds the missing
seed products and writes the repaired catalog back, so no manual step is
needed — install it and restart the server. Nothing you placed is lost; orders
recorded against the missing products are still in state.db and resolve again
once the products are back.

State is now durable across processes, and the v2.0.0 lineage's two useful
ideas are in main. Tool names, parameters and response fields are unchanged
from 3.0.1, except that list_all_products now returns its matches ranked.

Added

  • A SQLite durable store (src/sqliteStore.ts). State moved from a
    state.json snapshot to state.db, using Node's built-in node:sqlite — no
    new dependency, nothing to install, nothing to host. An existing state.json
    is imported on first run, validated record by record with exactly the rules
    the JSON store used, and kept as state.json.migrated.
  • Cross-process write transactions. StateStore gained an optional update,
    and the SQLite store implements it as BEGIN IMMEDIATE — the write lock is
    taken before the state is read, so a second server validates against what
    the first one committed rather than against a snapshot it has already moved
    past. MockDataProvider.transact() uses it, so order placement's whole
    read-validate-write is exclusive. This is the change that makes concurrent
    writes safe: ten server attempts at 5 units against a stock of 42 fill
    exactly eight orders and refuse the other two with a reason, where before the
    last writer's snapshot simply overwrote the others.
  • Search ranking (src/productIndex.ts), ported from the v2.0.0 lineage's
    src/trie.ts — but as a ranking layer, not the filter it was there. See
    the note below.
  • PROJECT_TANGO_STORE=json to force the previous whole-snapshot backend,
    for a runtime without node:sqlite (Node < 22.5). It keeps publishing one
    process's complete snapshot and is still last-writer-wins across processes;
    the README says so where it documents that flag.

Fixed

  • Two servers starting together could split one catalog across two files.
    PRAGMA journal_mode = WAL returns SQLITE_BUSY immediately, ignoring
    busy_timeout, so opening the store raced: the loser gave up, fell back to
    the JSON backend, and two processes then wrote state.db and state.json as
    separate catalogs that each believed they owned the stock. The store now
    retries the open with backoff and waits out a lock another process holds
    instead of routing around it.
  • Falling back to a different on-disk store is worse than losing durability.
    Two files disagreeing about inventory is not recoverable; losing state across
    a restart is. A store that cannot be opened now degrades to memory with a
    warning on stderr, never to a second file.
  • A test run could create the real ~/.project-tango catalog. The store is
    resolved — and therefore created — when mockData.ts is imported, and
    src/storage.test.ts asked for the default directory to check its
    description. The runner now pins a throwaway data directory for every test
    process (src/testGlobalSetup.ts), and a suite-hygiene test fails if that
    wiring is ever dropped.

Known limitation

Reads are served from a running process's own in-memory catalog, so a
long-lived server can trail another process's last commit until it writes
something itself. Writes never read a stale snapshot — they re-read under the
transaction lock — and a freshly started process is always current. Two servers
driven from one client are the case this shows up in; the lifecycle suite reads
the final state through a new process for exactly that reason.

Why the v2.0.0 trie was ported as ranking

v2.0.0 replaced substring search with prefix-only matching and called it an
improvement. Measured against this catalog, it is not: "tch" matches 7
products by substring and 5 by token prefix, and "a" matches 13 against 6.
Substring matching reaches inside tech and stitch; a prefix only matches from
the start of a token. Shipping it as written would have cut recall while
looking like a speed-up.

So the index here ranks instead of filtering. filterProducts still decides the
candidate set, and the trie only orders it — a product whose own token is the
query outranks one that merely contains it, on three tiers (the query is a whole
name/SKU/category/tag, is one word of one, or starts one). The tier is what
separates Cable from Cable Management Tray: both carry a cable token, and
a token-level comparison alone lets the longer name win on accumulated prefix
matches.

Project Tango v3.0.1 — lookback window fix, restored-state validation

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 10:59

Bug fixes

A bug-fix release: no API changes, no new tools, no behaviour change beyond the two defects below.

smart_restock_predictor measured one day more than it reported

The sales lookback window subtracted the full salesLookbackDays from its anchor date while the window filter includes both bounds — so a 30-day lookback actually covered 31 calendar days of demand and still divided by 30. Every velocity ran about 3% high, daysOfCover ran low, and recommendedReorderQuantity came out too large.

The window now spans exactly salesLookbackDays calendar days counting the anchor day, so the reported window.start/window.end match the arithmetic that produced the figures.

Verified end to end: a product selling 1 unit/day for 30 days, plus one order a week older than the window, previously reported unitsSoldInWindow: 31, dailyVelocity: 1.033, daysOfCover: 1.9, reorder 20. It now reports 30, 1, 2, 19.

Non-finite numbers in a restored state file broke every analytics tool

The state store validated restored records with typeof x === "number", which accepts Infinity — the value JSON.parse("1e999") produces — and fractional quantities. Those passed validation, reached the catalog, and then failed the tools' own declared output schemas:

MCP error -32602: Output validation error: Invalid structured content for tool
analyze_sales_metrics: Invalid input: expected number, received Infinity

One bad field in one record turned analyze_sales_metrics, smart_restock_predictor and find_orders into hard failures for the whole dataset. JSON.stringify cannot express either value, so only a hand-edited or foreign-written state file could produce it — but the file's stated contract is that an unreadable state degrades to the seed dataset rather than taking the tools down.

Record validation now requires finite numbers, and integers where the schemas declare them, so such records are dropped and warned about like any other malformed record.

Verification

Gate Result
npm run typecheck 0
npm run lint 0 errors, 0 suppressions
npm run test:coverage 210/210 tests, 42 suites, above the 98/94/96 floors
npm run build 0
Live stdio run 8 tools, 30-day window matches policy, write path intact

Upgrade

Drop-in: no tool names, parameters or response fields changed. If you compare restock output against v3.0.0, reorder quantities will be slightly lower — that is the over-ordering being corrected, not a regression.

Project Tango v3.0.0 — modular restructure, scoped tools, quality gates

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 09:39

What's new in v3.0.0

A full restructure of the server plus two long-requested tool capabilities — every change verified by the suite and by an end-to-end run against the built server.

Tools

  • Real category scoping — get_low_stock_alerts, analyze_sales_metrics and smart_restock_predictor accept an optional category and echo the filter they actually applied. The weekly_inventory_review prompt now scopes every step it sequences (the old "only step 1 is scoped" disclaimer is gone with the gap it covered).
  • find_orders bounding — new optional limit returns the newest N matches while totalMatches always reports the full match count. The default stays deliberately uncapped: no pagination, nothing dropped.
  • Honest responses throughout: blank arguments echo back as null, zero matches are successes, and tool descriptions interpolate their policy values and tool names so prose cannot drift from code.

Architecture

  • createServer(dataProvider) — the whole MCP surface (8 tools, 1 prompt, 1 resource) takes its DataProvider as an argument; index.ts is a thin stdio bootstrap. The seam is exercised in-process against stub providers.
  • Split into focused modules: server.ts, reviewPrompt.ts (pure prompt renderer), responses.ts, toolNames.ts, alongside the existing analytics split.

Correctness

  • Cross-process safe state writes: per-write temp files so two writers can never publish a torn state.json, with cleanup on failed rename; a two-writer race is pinned by test.
  • The README's dataset figures (130 matches / 142 orders / 46 KB) are asserted against live data by docs.test.ts.

Quality gates

  • 204 tests / 42 suites / 0 fail, coverage 99.96% lines / 96.16% branches / 98.17% functions enforced by floors (98/94/96).
  • Type-aware ESLint with zero suppressions; GitHub Actions CI runs typecheck → lint → coverage floors → README test-count drift check → build (all green on this commit's pipeline).
  • TypeScript 6.0.3 (typescript-eslint does not support the TS 7 API yet; typecheck remains clean).

Upgrade notes

No breaking changes. All new input parameters are optional and response fields (filters, totalMatches, limit) are additive — existing clients keep working unchanged.


Full changelog: v2.0.0...v3.0.0

v2.0.0 — The Hybrid Engine

Choose a tag to compare

@freebuff-web freebuff-web released this 14 Jul 10:26

🚀 v2.0.0 — The Hybrid Engine

Project Tango is now a production-grade MCP server powered by a three-pillar hybrid architecture: SQLite persistence, prefix-trie instant search, and a reactive event broker with saga rollback.

Previous release: v1.0.0


🏗️ Architecture

┌───────────────────────────────────┐
│     Client (Claude / LLM)         │
└──────────────┬────────────────────┘
               │  MCP Protocol (stdio)
               ▼
┌───────────────────────────────────┐
│    Project Tango MCP Server       │
└──────────────┬────────────────────┘
               │
    ┌──────────┴──────────┐
    ▼ (Atomic Writes)     ▼ (Read Cache)
┌─────────────────┐  ┌─────────────────┐
│    SQLite DB    │──►│  Prefix Trie    │
│  (Single Source)│  │ (O(k) Search)   │
└─────────────────┘  └─────────────────┘
    │                       │
    └────── Event Broker ───┘
          (Real-time Subs)

Three Pillars

1. 🗄️ SQLite Persistence (src/database.ts)

  • Full relational schema: products, orders, order_items with foreign keys
  • WAL mode for concurrent reads, journaled writes for crash safety
  • Parameterized queries — zero SQL injection risk
  • DataProvider interface implemented against SQLite: all 6 provider methods

2. ⚡ Prefix Trie Search (src/trie.ts)

  • In-memory Trie indexing every token from product names, SKUs, categories, and tags
  • Search in O(k) where k = query length (not O(n) like a linear scan)
  • Prefix matching, wildcard support, relevance scoring
  • Fully atomic index rebuild on server start — always in sync with SQLite

3. 🔄 Reactive Event Broker & Saga Rollback (src/engine.ts)

  • Event bus emits typed events (product:updated, order:placed, inventory:changed)
  • Subscribers push notifications/resources/updated to the MCP client in real time
  • Saga rollback: on any mid-transaction failure, the engine restores the before-state — no partial mutations, no corrupted data

🛠️ 7 MCP Tools

Tool Description
list_all_products Browse/search catalog with category & price filtering
search_products 🆕 New! Trie-powered instant prefix search — returns results in <1ms
get_low_stock_alerts Scan inventory for low/critical stock levels
analyze_sales_metrics Gross revenue, AOV, top sellers, order-status breakdown
smart_restock_predictor Recommends reorder quantities from demand velocity
draft_product_copy Generates marketing copy + SEO tags for a SKU
simulate_order_placement Places a simulated order with stock validation

🔒 All Fixes & Hardening (v1.0.0 → v2.0.0)

Critical

  • ✅ addOrder now clones before storing — prevents caller mutation of internal state
  • ✅ .convex/ secrets removed from tracking — adminKey and instanceSecret no longer at risk
  • ✅ prod_006 data inconsistency fixed — stock 1→3, order qty 2→1 to reflect available inventory

High

  • ✅ Order IDs use crypto.randomUUID() — unique even at sub-millisecond concurrency
  • ✅ Saga rollback on order failure — inventory restore, cache rebuild, structured telemetry

Medium

  • ✅ Input validation bounds added — .max() on all string parameters (category, sku, customer_name, product_id)
  • ✅ Error boundaries — withSanitizedErrors wrapper on all 7 tool handlers, no stack leaks
  • ✅ npm test script added — run npm test to execute the 38-check integration suite
  • ✅ .gitignore updated — node_modules/, .env*, .convex/ all protected
  • ✅ Unused imports & dead code removed from integration test

Low

  • ✅ formatZodIssues — human-readable validation error output (not raw JSON)
  • ✅ Stale JSDoc corrected (“four methods” → “6 methods”)
  • ✅ .prettierrc added — project-wide formatting config
  • ✅ as TReturn cast documented with safety notes

📁 File Structure

project-tango/
├── src/
│   ├── index.ts          # MCP server entry — 7 tools + reactive broker
│   ├── types.ts          # Shared TypeScript interfaces
│   ├── trie.ts           # Prefix trie data structure
│   ├── database.ts       # SQLite connection, schema, queries, seed
│   ├── engine.ts         # Hybrid engine (SQLite + Trie + Events + Saga)
│   ├── mcpHelpers.ts     # withSanitizedErrors, formatZodIssues
│   └── mockData.ts       # In-memory DataProvider (legacy)
├── test/
│   └── integration.test.ts  # 38-check MCP integration test
├── .prettierrc
├── .gitignore
├── package.json
├── tsconfig.json
└── README.md

📊 Performance

Operation v1.0.0 (in-memory) v2.0.0 (hybrid)
Product search (13 products) O(n) scan O(k) trie lookup
Order placement In-memory only Durable + atomic via SQLite WAL
Read isolation Clone on read Clone on read + primary source in SQLite
Crash recovery Lost on restart Full recovery from disk
Concurrent safety Module-level mutex Mutex + saga rollback

🚀 Getting Started

npm install
npm start        # Launch MCP server over stdio
npm test         # Run 38-check integration suite
npm run build    # Compile to dist/
npm run inspect  # Debug with MCP Inspector

No env vars required — runs entirely locally with SQLite.


Release prepared by the v2.0.0 hardening audit and full architectural rewrite.

Production-Ready MCP Overhaul

Pre-release

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 14 Jul 08:28
d64376c

🚀 Project Tango v1.0.0 — Production-Ready MCP Server

Welcome to the initial, stable release of Project Tango—an enterprise-grade Model Context Protocol (MCP) server designed for secure, high-performance e-commerce catalog and order management.

This release bypasses typical prototype limitations, delivering a production-ready system built with a highly testable modular architecture and bulletproof concurrency protections.

🛠️ Key Features & Architecture

Modular Domain Isolation:
Business operations (catalog search, order processing, and restocking algorithms) are isolated into pure, dependency-free functions under /logic. MCP network adapters live cleanly in /tools, enabling lightning-fast, isolated testing.

Single Source of Truth Types:
To prevent type drift, TypeScript interfaces are dynamically inferred (z.infer) directly from runtime Zod validation schemas.

Atomic Concurrency Protection:
Built-in protection against inventory overselling. The order placement flow (placeOrder) runs as an indivisible transaction secured by an asynchronous Mutex write-lock.

Rich MCP Ecosystem Surface:
Exposes 7 custom tools, including a highly optimized search_products tool utilizing multi-token partial matching (normalizes spaces, hyphens, and underscores).

Out-of-the-box support for 4 dynamic resources (catalog, orders, alerts) with autocomplete.
2 interactive prompts (inventory-briefing, sales-report) for LLM assistance.
All tool outputs deliver both natural text and validated structuredContent.

Fail-Fast Environment Configuration:
System thresholds and parameters are validated via Zod at server boot. If an environment variable is misconfigured, the server fails loudly at startup rather than corrupting data downstream.

CI/CD & Code Quality:
Protected by a suite of 43 unit and integration tests (94.5% logic coverage), a strict ESLint configuration, and a GitHub Actions workflow to run type-checks, lints, and tests on every push.