Skip to content

Project Tango v3.1.1

Choose a tag to compare

@CoderGamerUnknow CoderGamerUnknow released this 04 Oct 15:18
· 5 commits to main since this release

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.