Releases: Formicaria/formicaria-releases
Release list
FORMICARIA v0.4.2.0
v0.4.2.0 - one file per module, and a split an operator runs
The colony's store stops being three data domains in one file (roadmap E-3; R-03 §13.2, F10, F12).
anthill.db keeps the colony; the Infrastructure module's 24 tables get infrastructure.db and the
Micromound module's 12 get micromound.db, each beside it, leased and hardened like it, and backed up
and restored with it. A new installation starts that way. An installation from before this release
keeps running exactly as it was until an operator runs anthill --migrate-stores.
Where a device belongs is the host's record now
Until now the host wrote a device's organization and project into two columns of the device
module's own table, micromound_mounds, and every access check on a device read them there. With
that table in a file the host does not open, a check that could not find it would have read "no
placement" -- which for the installation's organization means "allowed". So migration
0004_device_placements (automatic, additive) moves them into a table of the host's own,
device_placements in anthill.db, and every placement question is answered from there whether the
device module is loaded, split, or absent. A device mission finds its mound through the module, which
registers the lookup when it loads. A device enrolled before devices had an organization is asserted
into the installation's organization when the module starts, and the assertion is recorded beside the
one migration 0001 wrote. A purged device's placement is forgotten with it.
anthill --migrate-stores
Run by a person, with the colony stopped, by the owner's decision: nothing that moves a customer's
data runs unattended (F17's posture). Until it runs, each module stays on its tables inside
anthill.db, anthill --status says so, and the console log says so at every start. In order, and
stopping at the first thing that is wrong:
- The colony's store is opened once under its lease, so its schema is this build's and every
placement is already indevice_placements. - What would move is printed. Nothing to move ends here, exit 0.
- Every store's lease is taken and a backup of every store is made and rehearsed, exactly as
anthill --backupmakes one. - The split runs against a scratch copy of that backup. A failed rehearsal ends here; so does
--rehearse. - The split runs against the colony. For each module, through one connection holding
anthill.db
in SQLite's EXCLUSIVE mode with the module's file attached: every table is copied in one
transaction (its ownCREATE, every row in rowid order, its indexes, itsAUTOINCREMENTcounter);
every table's row count and a SHA-256 of every row's typed values are compared between the two
files, and the new file must passintegrity_check; only then are the tables dropped from
anthill.db, in a second transaction that records what moved inanthill_meta.
The two transactions are in two files and cannot be one. A split that stops between them leaves a
module's tables in both, and the colony then refuses to start (exit 13), naming the module and the
command. Running --migrate-stores again compares the two copies and finishes only if they are
identical; if they differ it refuses and changes nothing, and the backup it took is named in its
output. StoreSplitTests stops a split after its copy and finishes it, and refuses one whose two
copies were made to differ.
Backups take every store
anthill --backup takes every store that exists, each file's lease held and all of them in
EXCLUSIVE mode together while they are copied, checked and rehearsed; the manifest
(formicaria-backup-v2) lists them under stores. A v0.4.1.2 backup (formicaria-backup-v1,
anthill.db alone) is still verified and restored. A restore puts back every file the backup holds
and sets aside a module file the backup does not hold -- a backup taken before the split -- keeping
it as <file>.pre-restore-<time> and saying to run --migrate-stores again.
Also
anthill --inventoryreportsmodule_stores: each module's file, its state (own,legacy,
interrupted), its lease and its tables, and finds the controller identity in whichever file holds
it.- The module manifests declare
infrastructure.dbandmicromound.dbas their stores.
What this release does NOT do
- The tenancy retrofit of the Infrastructure module's tables. R-03 §13.2 decided the split
would ship inside that retrofit, so the tables migrated once. The module is frozen for 1.0 (§13.1)
and the retrofit has no date, so the split ships on its own; when the retrofit comes it is a
migration ofinfrastructure.db. - Split automatically. An operator runs it (above).
- Online backup (roadmap E-6), which now has to take every store.
- Size and maintenance across files. The dashboard's database size and the maintenance
VACUUMcoveranthill.dbonly, and the split does not compactanthill.db: the pages its
moved tables held stay in the file as free pages until the next maintenanceVACUUM. - The Forager store. Unchanged; it has its own lock and its own database.
- On an older binary,
--migrate-storesis not refused: v0.4.1.2 and earlier treat an unknown
flag as a mission goal. Run it with this release'santhill.
Every file has a .sha256 beside it, written from the bytes that were archived; formicaria-0.4.2.0.manifest.json lists them all with their sizes and the components this build agrees with. https://formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/formicaria stays at the last image an Actions run pushed.
FORMICARIA v0.4.1.2
v0.4.1.2 - rehearsed backups, and a suite that runs in a home it made
A maintenance release on v0.4.1.1 carrying two engine items the roadmap had planned for v0.4.2.0:
W3-09's third slice (E-1) and the test-isolation guard (E-2). The colony can now be backed up and
restored by a command, offline and under its lease, and a backup is not called usable until it has
been restored somewhere and checked. The suite stopped reading the machine it runs on.
The mission-path backup was a copy of half a database
Before a mission (at most once per backup_min_interval_minutes) the colony copied anthill.db
into backup_dir with File.Copy. The store runs in WAL mode, so everything written since the last
checkpoint lives in anthill.db-wal, and a copy of the main file alone is the store as it stood at
that checkpoint: missing the most recent history, and torn if a checkpoint landed mid-copy. Nothing
ever opened one of these files to find out.
It now goes through SQLite's online backup API, which reads through the WAL, makes the copy one
self-contained file, and runs PRAGMA quick_check on it; a copy that fails is deleted rather than
kept. TheMissionBackup_CarriesWritesStillInTheWal_WhichACopyOfTheFileDoesNot shows both halves on
one fixture: a hundred rows committed and not yet checkpointed, none of them in a File.Copy, all
of them in the backup.
anthill --backup and anthill --restore
Offline, by the owner's decision: both take the store's lease, so while the colony runs they are
refused like every other verb that opens the store (exit 11, holder named). Stop, back up, start.
A backup is written to a new formicaria-backup-<time>-<id> directory under backup_dir (or
--out), and in this order it is:
- quiesced -- the lease keeps out every lease-aware ANTHILL, and one from before v0.4.0 takes
none, so the copy is taken through a connection in SQLite's EXCLUSIVE locking mode. A WAL store
refuses that while any other process has it open, even idle; the verb exits 12 and says what to
look for. The lock is held until the copy is taken. - copied through the backup API into one file;
- checked --
integrity_check, a row count for every table, a SHA-256, and a one-way check
value of the field key it was sealed with; - rehearsed -- restored into a scratch directory and checked again.
manifest.json records all of it, and says usable: false (exit 1) if any check or the rehearsal
failed.
The field key is not in it unless --include-key is passed (owner's decision, 20 September).
It seals device seeds and the Micromound controller identity, so a directory holding both the store
and its key is a copy of everything. The check value lets a restore tell whether this workspace's
key is the one the backup was sealed with. A backup never creates a key where there was none.
A restore (anthill --restore <dir>) runs every check that reads only the backup and the key
file BEFORE it takes the lease -- taking the lease writes its holder into the live store, and a
refused restore must leave it byte-identical. It refuses a backup whose hash, integrity or counts
disagree with its manifest, one marked not usable, one sealed under a different key (every sealed
value would be unreadable after it), one whose key is missing unless the backup carries it, and a
store something else has open. Then it keeps the store it is replacing as
<db>.pre-restore-<time>, stages the backup beside it, checks the staged copy, and only then moves
it into place and checks again. Restoring onto a machine with no colony is the same command.
--rehearse restores into a scratch directory only, and can run beside a live colony.
The deliberately failed restore W3-09's brief asks for is a test:
ADeliberatelyDamagedBackup_IsRefused_AndTheLiveStoreIsUntouched damages a page in the middle of a
backup and re-hashes its manifest to match, so only SQLite's own check can catch it -- and the live
store is byte-identical afterwards, with nothing new beside it.
The same tests could grade differently on two machines, and now cannot
v0.4.1.0 found the same 4,495 tests green on the Linux box and red on the Windows box --
deterministic per machine. Six fixtures reached AnthillRuntime.Initialize(), which reads
<ANTHILL_HOME or the working directory>/.anthill/config.json, and graded missions with whatever
that file said. Those six were pinned by hand, and v0.4.1.0-findings.md said plainly that nothing
stopped the seventh.
Now nothing can reach one. Before anything in a test assembly touches the runtime, TestHome
(tests/Shared/TestHome.cs, compiled into both test projects) removes every ANTHILL_*,
FORMICARIA_* and FORAGER_* variable from the test process -- the families every config override
and every direct environment read in src/ belongs to -- and points ANTHILL_HOME at a directory
the run has just created, so the config the suite reads is the one it seeds from the shipped
defaults. A test that needs one of those variables sets it and puts it back, as the ones that need
them already did.
TestIsolationGuardTests holds it there: the runtime bootstrapped inside the run's own home from a
config it seeded; every variable src/ reads is one the scrub removes (collected from the source,
so a variable added under a new prefix fails the build rather than the next machine); nothing
configuration-bearing is set between tests; and every [ModuleInitializer] that touches the runtime
isolates first, because which of an assembly's initializers runs first is the compiler's choice.
Found on the way
FileSecurity.BackupDbIfDue's doc said migration and auto-apply calledBackupDbdirectly.
Neither did; the mission path is the only caller. Corrected.- A refused restore changed the store it refused. The first build took the lease before
checking the backup, and the lease records its holder in the store. Caught while writing the
pre-release end-to-end check, before it shipped; the checks now come first, and a test pins the
order.
What this release does NOT do
- Online backup. The colony has to be stopped (roadmap E-6).
- The Forager store. It has its own lock and its own database; this backs up ANTHILL's store,
which holds every ANTHILL module's tables until E-3 splits them. - A rollback-journal store's idle reader. The probe can only see a connection that is reading
or writing on a store that is not WAL. Every ANTHILL store is WAL. - Off-machine copies. A backup is written on the colony's own disk; the command says to copy it
elsewhere, and does not. RELEASE_MSG.txt.ReleaseNotesTestsstill read it from disk, so a release box that published
before carries the last release's notes there and those two tests fail until it is regenerated --
the same class of machine-dependent verdict, left alone because that file IS the release-time input
the tests exist to check.- The site.
site/apps/anthill/app/product.tsstill pins an older version (roadmap P-1).
Every file has a .sha256 beside it, written from the bytes that were archived; formicaria-0.4.1.2.manifest.json lists them all with their sizes and the components this build agrees with. https://formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/formicaria stays at the last image an Actions run pushed.
FORMICARIA v0.4.1.1
v0.4.1.1 - a switch where there was a file edit, and three calls made out loud
A maintenance release on top of v0.4.1.0. It closes what the end-to-end V&V left open: one
missing control, one sentence that claimed more than it knew, and one pane that showed the wrong
page. It also settles three items that were never bugs but product decisions, and this entry says
which way each one went and why.
Devices can be turned on from the console (D48)
The Devices door said "set micromound_enabled in config.json and restart", because nothing else
could turn the module on, and before v0.4.1.0 the next console save quietly put the old value back.
micromound_enabled is a switch now: Settings -> Modules -> Devices, Turn on / Turn off, for an
administrator on a build that carries the module. GET /settings reports it.
It takes effect at the next start. That is not hedging: the module registers, mints its controller
identity and maps its routes during boot, and a colony does not grow a device controller
mid-flight. So the door has two new states. Switched on since the colony started, it says the
module starts at the next restart and blames nothing. It used to report that the mound store did
not answer, which sent an administrator to a log with nothing in it. Switched off since start, it
says the module keeps running until then.
Smaller fixes
- Diagnostics stopped calling the colony healthy. "No recent failure events. The colony is
healthy." was printed off an empty failure table, directly under a Components rail that could be
showing a module in attention. A store that cannot open or an engine that never started records
no failure event at all. The line now says the count is a count, and where health is reported. - Settings shows one page at a time. Switching panes left the old pane's body on screen under
the new heading for as long as the new page's data took - one to four seconds on Modules. The old
body is replaced before the load starts. - Arming a dangerous switch asks with the console's own dialog. The confirmation v0.4.1.0 added
for Shell commands and the Operator shell used the browser's nativeconfirm(), which blocks the
whole page. - The release archive script runs under the PowerShell it is documented for.
build-archives.ps1used??, which only PowerShell 7 parses. Its own usage line and the runbook
run it withpowershell(5.1), where it failed before its first line ran.
Three product calls
- Automatic updates stay on by default, and now have a control.
auto_updatehas defaulted to
silentsince v0.3.8.149 by decision, and a changed default has to move in the class and the
migration plan together or existing colonies drift from new ones. What was actually wrong: the
documentation sent operators to Settings -> Colony, and nothing there rendered it. Settings ->
Colony -> Updates now carries it, with the trade stated where it is chosen. Automatic install
trusts the SHA-256 the release itself publishes, and release manifests are not signed yet
(W1-06). "Tell me, install nothing" is one click away for an operator who wants every installed
version to be a person's decision. - The files pane keeps its boundary, and says so up front. Every write the pane makes - a new
file or folder, a save, a commit,git init- passes the same capability as "Apply approved
changes", the one switch that decides whether this host writes into a project's directory at all.
That did not move. The pane used to offer those buttons with the switch off and answer each one
with a refusal. It now opens read-only with the reason and the switch named. - Projects are archived, never erased, and archived ones fold away. A project's conversations,
missions and audit rows stay on record. Erasing them is W1-10's ERASE scope, which has to be one
transaction with a certificate rather than a delete route that leaves half of it behind. What
operators actually hit was clutter, so archived projects collapse under one line with a count,
and a click brings them back.
What this release does NOT do
- It does not change how any installed colony updates. A colony that installs automatically
still does. Nothing is migrated. - Signing. Release manifests are still unsigned. That needs a key with an owner and a custody
procedure (W1-06), and it is the change that would make silent install a stronger default than it
is. - A Devices switch that acts without a restart. Nothing in the module is built to start or stop
mid-flight, and this release does not pretend otherwise. - Deleting a project. See above: archive is the operation, and erasure is designed, not built.
- Still open from the V&V: "Security issue" opens a plaintext
mailto:.
Every file has a .sha256 beside it, written from the bytes that were archived; formicaria-0.4.1.1.manifest.json lists them all with their sizes and the components this build agrees with. https://formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/formicaria stays at the last image an Actions run pushed.
FORMICARIA v0.4.1.0
v0.4.1.0 - a default that moved in one place only, and the name an operator reads
v0.4.0.0 turned objective verification on and, in the same release, made an unchecked deliverable
stop counting as verified. Those two changes are correct together and were shipped apart: the
default moved in the class, and every installation that had ever saved its settings carried the old
value on disk. This release closes that, pins the seam so it cannot reopen, and finishes the rename
the last release could not.
Every colony could stop verifying its own work, and only a new one would notice
WHAT WENT WRONG. objective_verification_enabled defaults on as of v0.4.0.0, and that default
lives in AnthillConfig. It is what a FRESH install serialises. It is not what an existing
installation gets: SaveConfig writes the whole document, so every colony that had ever opened
Settings carried "objective_verification_enabled": false -- the shipped default at the time, and
never an operator's answer, because until v0.4.0.0 the setting was reachable only by hand-editing
the file. GET /settings never returned it and no console page showed it.
Alone that would have meant "the old behaviour". It did not, because the same release made
deliverable = not_checked demote: a check that did not run is not a check that passed. So those
colonies could no longer reach completed_verified at all -- and auto-apply consumes that
grade, which means a patch mission could not apply its own patch. A colony that had been running
since before the upgrade quietly stopped being able to finish work, and nothing said so.
THE FIX IS A MIGRATION, on the argument ConfigSchema already makes for roster_profile: below
the version that introduced a default, a value on disk is a default nobody selected; at that version
it is a selection. ConfigSchema.Current moves to 3 and a roster-era file takes a new action,
AdoptedObjectiveVerification -- layer on, roster untouched, and the [config-migration] line an
operator reads says which setting moved and why. A false written at schema 3 is respected, because
after this release the setting is reachable and can only be an answer.
AND THE BUMP DID NOT RE-OPEN SCHEMA 2's QUESTION. The roster rule read "below Current, core
is a default nobody selected". Bumping Current to 3 would have made every schema-2 file's
deliberate core read as untouched and moved it to full, switching on six roles an operator had
chosen against -- the one thing ConfigSchema's own header says a migration must never do. The rule
now keys off RosterDefaultVersion, which is 2 and stays 2. A default belongs to the version that
introduced it, not to the newest one, and a test fails if that constant is ever collapsed back.
THE SEAM IS PINNED. TheShippedDefaults_MatchWhatAFreshInstallIsMigratedTo now asserts the
plan's answer against the class's for this key, and its comment states the rule for the next one:
every shipped default belongs in that assertion, because a default that exists in one place and not
the other is a divergence with a delay on it.
The suite's verdict depended on whose machine ran it
Six fixtures reached AnthillRuntime.Initialize(), which reads the developer's own config from the
data home, and then graded missions with whatever that file said. With not_checked demoting, the
same 4,495 tests were green on one box and red on another -- not flaky, deterministic per machine,
which is worse. Those fixtures now pin the switch to the shipped default and restore it in
Dispose. DeterministicBlockTests.NoBlock_StillReachesCompletedVerified was the odd one: it set
the layer OFF to isolate the deterministic block, and off is now itself a demotion, so it asserted
exactly the behaviour v0.4.0.0 removed.
Still open, and recorded rather than fixed: nothing stops the next fixture inheriting that
config again. The release's findings record -- v0.4.1.0-findings.md, in the repository's
transition/completed folder -- says what a guard would have to do.
The name an operator reads
--version answered ANTHILL Core v0.4.0.0. The archives, the installer, the service unit, the
process name and the tag namespace were all Formicaria; this line was not. RELEASE-v0.4.0.0.md §5
found it after that release's archives were built and digested, so it could not be corrected there.
It now answers Formicaria v0.4.1.0, and CliVersionTests pins it.
The command is still anthill, and so are ANTHILL_BIN, ANTHILL_*, /opt/anthill and the
service user. Those are the engine's names, kept deliberately by the rebrand. Both release scripts
match v{VERSION} and ignore the product prefix -- checked before the banner was changed.
One forward-looking list, and an archive for what is finished
Where the next piece of work was written down depended on which document you opened: a "what is
still not done" list in STATUS.md, an "open, not decided here" section in a handoff, a Next
block in a completed record, and the unbuilt half of the wave prompts. Four places, none of them
wrong on its own day, and no way to see the whole queue without reading all of them.
ROADMAP.md, at the top of the repository's docs/ tree, is now its only forward-looking list. It carries the engine
queue with target releases, the commercial chain in dependency order, the six answers owed by the
owner, the fourteen owed by counsel, and the standing constraints every release ships under. It is
updated as part of each release, and §8 says how. STATUS.md keeps every word it had and is
declared for what it now is -- the dated log of how the programme got here, appended and never
edited.
docs/archive/ takes the work that is finished: the monorepo import pipeline, the cutover and
push procedures, the tag maps, the wave 0 unblocking packages, the wave PR descriptions, the 51
work-package briefs, and the Z-01..Z-07 escalation record closed in September. Its README states
the rule that governs it -- an archived document's links and version numbers describe the day it
was written, and corrections go in the live document rather than into the record. Nothing under
docs/transition/completed/ moved: those records are standing evidence, several of them name work
that is still open, and the roadmap cites them.
What this release does NOT do
- It does not migrate a
falsethat an operator chose at schema 3. That is the point of the
version, not an oversight. - It does not stop a test inheriting the data-home config. Six fixtures were fixed by hand; the
seventh has not been written yet. - It changes nothing commercial. The live provider account still holds zero products and zero
prices, 69 of 74 declared enforcement points are still unimplemented, there is still no signing
key and nothing is deployed. Nothing can be sold, exactly as v0.4.0.0 said.
Every file has a .sha256 beside it, written from the bytes that were archived; formicaria-0.4.1.0.manifest.json lists them all with their sizes and the components this build agrees with. https://formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/formicaria stays at the last image an Actions run pushed.
FORMICARIA v0.4.0.0
v0.4.0.0 - the production release: the boot fix, a commerce system that exists, and one store with one writer
The first release cut since 17 September, and it carries four separate bodies of work. The boot fix
is the one customers need today. The commerce system is the one that had to exist before anyone
could be charged, and it is not finished - see the end of this entry, which says so plainly. The
knowledge feed closed, so a published revision now reaches a colony on its own. And the store
learned to refuse a second writer, which is the first piece of the migration work the releases
after this one are built on.
The boot fix (F81)
THE RELEASE NAMED FOR THE MODULE CONTRACT WAS THE ONE THAT BROKE IT. v0.3.20.0 shipped with
InitMicromound() called bare on the boot path -- #if MICROMOUND and an enable flag around it and
nothing else. SqliteMoundStore opens and extends its tables in its constructor, so a device store
with any schema conflict threw a SqliteException that walked straight out through EnsureColumns -> InitDb -> ctor -> InitMicromound -> Run, and the process exited before /health could answer.
No degraded mode, no fault record, no diagnosis. An optional module taking the whole colony down is
precisely the guarantee W3-10 exists to make, and .20.0's own tag message is "every module enters
through one contract".
Found by the first legitimate identified-build qualification run since .12.0, against the PUBLISHED
win-x64 archive with its sha256 verified against the sidecar before extraction. Not in a dev tree --
in the artifact a customer installs. Registered as F81.
THE GUARD IS NOT A TRY/CATCH AROUND THE CALL. StartMicromound() wraps the start, and on
failure returns every static the start touched back to unset: Mounds, MicromoundId,
MicromoundEnroll, the charter, config, mission, evidence, resolve and sync services, and
Queen.PhysicalActionReplay. A half-built module is worse than an absent one -- Mounds left
non-null on its own would make the Devices door claim the store answers while the services reading
it are null. MicromoundRunning gates route mapping, so a faulted module answers 404 rather than
500 and GET /modules says which one declined and why (A18).
Registration stays configuration only. That is the contract, and it is why a manifest's resolution
can be a plan rather than an exception; the work that can really fail moved to where it can be
caught.
Also in this release
The commerce lane closed, and then reopened twice. Base is free, the three module plans carry
price_refs, monthly only. Those refs have NEVER been resolved against a live provider account,
here or anywhere -- a ref that 404s at the provider passes every gate in this repository. D01 and
D03 were reversed on 18 September when the meter changed, D04 reopened because its basis was
"not applicable while D03 is no", and three infrastructure decisions have since been raised and
not made: which KMS holds the entitlement signing key, which managed database, which region.
Five rows are open, not zero. packages/commerce-provider/ is the provider half of W4-02: the CAT-023
publish gate that resolves each price_ref at the provider, webhook signature verification with a
90-day dedupe store (F18), the F31 billing-trail redactor, the section 6.4 one-subscription-per-
product refusal, and E04's quantity high-water mark. 96 checks over 30 fixtures, standard library
only. That package is still wired to nothing -- but the hosted service in services/commerce/ now
is: it ingests those webhooks in TypeScript, and it mints Ed25519-signed grants. What it cannot do
is sign one in production, because no KMS has been chosen, so a paid subscription is recorded
correctly and the customer receives nothing. That is the single largest hole in this release.
E03 was amended from 14 days to 15 in the process. Stripe's custom retry gaps are 1, 3, 5, 7 and 9
days, all odd, so three retries cannot sum to 14; 15 was chosen over 13 because 13 suspends a day
before D06's grace expires, and E09's whole argument is against cutting anyone off early when the
thing on the other end is physical automation.
The pre-commit hook was mode 100644, so git silently skipped it on every platform that honours the
exec bit and the secret scan never ran off Windows. pre-push beside it was already 100755.
The commerce system
FORAGER IS SOLD BY CUMULATIVE ALLOWANCE, NOT BY THE SIZE OF ONE IMPORT. The catalog modelled
size_tier - a ceiling on each import - while the prices configured at the provider sold capacity.
Those are different products. D01 and D03 are reversed, size_tier is gone from both enums so the
discarded model is unrepresentable, and the meter is quantity with consumption: consumable. GiB
is what is sold and displayed; bytes are what is enforced; one named catalog field owns the mapping
so no display layer invents its own. 1 GiB means "import as many times as you like until the
combined admitted bytes reach 1 GiB", unused allowance carries forward for twelve months and is
consumed oldest-first, and an exhausted allowance REFUSES rather than silently billing.
Re-importing content you had already paid for was charged twice. The duplicate disposition is
a registration verdict that fires after admission and the measurer never read source_documents;
measured against a pristine tree, the same file in two batches consumed 1008 bytes then 2016. Per
project, permanently, by content hash, it is now free - and still counts in full against the
RESOURCE budget, because the batch was still read, hashed and inflated. Those are two counters and
collapsing them is a billing dispute waiting to happen.
A failed or cancelled import costs nothing: bytes are reserved at admission, committed on success
and released otherwise, back into the buckets they came from so a twelve-month expiry keeps meaning
something.
FORAGER NO LONGER SHIPS AS A SEPARATE PRODUCT (F80). Its in-app updater polled a pre-monorepo
repository that nothing publishes to, which is private so an unauthenticated GET 404s, and whose
releases/latest returns whichever of three tag namespaces shipped last - and the 404 was swallowed
and rendered as "no update". Every standalone install has been silently never updating. The engine
has shipped inside every ANTHILL archive since v0.3.18.0 and is supervised by the host, so there is
nothing left to update independently. One installer, one version, one update mechanism.
A hosted commerce service exists for the first time: PostgreSQL, organizations and installations,
Ed25519-signed entitlement grants, provider webhooks with replay and card-data protection, the
15-day dunning window, integration-slot allocation that gives exactly one winner under 48-way
contention, and a hash-chained audit of every commercial event. It is not deployed anywhere.
The knowledge feed, finished (W3-05 part two)
W3-05 closed across five slices, and the through-line is that a published revision now reaches a
colony without anyone polling for it.
The feed is consumed rather than polled. Every envelope FORAGER publishes lands verbatim in
knowledge_feed_inbox before it is acknowledged, a watermark carries the position, and
knowledge_actions holds one action per revision, so a redelivery cannot cause a second import.
Polling remains the fallback for a producer that declares no change feed. GET /knowledge/feed and
POST /knowledge/feed/sync are the operator's view of it, and the console's Review section lists
published revisions with a Sync now.
The producer says how big an import is, before it starts. POST /knowledge/preflight returns
FORAGER's own measurement - after its exclusions, after expanding an archive it sees compressed, with
refused types named - and the console shows a count until that answer arrives rather than the
browser's guess, which is wrong in both directions at once. Two latent 500s, on the upload and
preflight handlers, were fixed in the same slice.
A package says which revision it is. The ANTHILL package version went 6 to 7:
anthill-package.json now carries the revision it was built from and that revision's content hash,
and both sides pin the number exactly. A package on disk is attributable, and a version mismatch is
reported rather than guessed at.
The inbox has a window, and it is derived. max(retry horizon, DLQ retention) x 2, floor 30 days
- 180 days today, read out of the 90-day dead-letter retention rather than typed beside it, so moving
one moves the other. Pruning cannot remove an entry that has not been acted on.
A revision gets a policy of its own. Missions created from a published revision run under their
own setting rather than under the poll schedule that happened to be nearby. That was a decision, not
a deduction - no document in the tree defined it - and it was the owner's.
One store, one writer (W3-09 release one)
The migration work starts with the two things that have to exist before customer data is moved.
anthill --inventory <path> reads an installation without touching it. Reading an installation
through the product's own types is a write: constructing SqliteMemory runs the schema pass, the
column check and the migration runner, and Initialize() writes a config file when there is none. A
tool that inventories an installation that way has already migrated it, before anyone decided to. So
the inventory opens the files as foreign files, and reports both what it read and what it could not.
A store has one writer, and the operating system enforces it. Every process that opens the
colony's store takes a lease first: an OS lock on <db>.owner - flock on Linux and macOS, a
byte-range lock on Windows - and a store_lease row recording pid, host, mode, purpose, version and
time. A second process is refused with exit code 11 and a sentence naming the holder, and it has
changed nothing in the store by the time it say...
ANTHILL v0.3.18.0
v0.3.18.0 - the engine ships in the box
MANAGED MODE HAD EVERYTHING BUT AN ENGINE. Since v0.3.9.11 the host could start, verify and
supervise a FORAGER of its own (W3-03): mint the credential, learn the port, check the identity, the
version floor and the one-writer lock, restart it when it died. What no release ever gave it was the
engine. A colony that wanted knowledge either attached to a FORAGER an operator installed and ran
themselves, or an engineer built FORAGER from source and wrote two paths into config.json — the
developer's arrangement, which is the only one there was. Formicaria is one application with the
engines inside it, and this is the release where that becomes literally true for the first engine.
The box
Every release archive and the Windows installer now carry FORAGER beside anthill, in a forager/
folder: server.mjs (the whole engine, bundled to one file by esbuild — no node_modules),
client/ (its interface), runtime/node[.exe] (a Node runtime for that platform) and
build-info.json (the engine's version, the platform, the Node version, the runtime's digest).
modules/forager/scripts/package-engine.mjs lays it out, for either platform from either platform:
the bundle is plain JavaScript, so the Windows release box stages the Linux engine and the tarball
carries it. The runtime it ships is not the box's: it is fetched from nodejs.org at the version
modules/forager/packaging/node-runtime.json pins, verified against nodejs.org's own
SHASUMS256.txt AND against the digest the pin file records, and refused on either mismatch — a
runtime that changed under its version number is not one to ship. deploy/release/stage-engine.ps1
is the step both build-archives.ps1 and build-installer.ps1 run; build-archives.sh does the
same on Linux. MakeTar.cs marks the runtime executable in the tarball beside anthill, and the
installer takes the folder as it takes everything under the publish directory. The release manifest
names what shipped: components.forager (the engine's version) and components.node_runtime.
The archives grow by the runtime — roughly forty megabytes compressed — and the archive is still the
whole product: nothing to install beside it, nothing downloaded at first run.
The host finds it
BundledEngine.Locate looks beside the binary for that layout — both halves, the entry and the
runtime; one without the other is not an engine and is not reported as one — and reads the record for
the version. BundledEngine.Apply folds it into the knowledge settings at the one place they are
projected: with nothing configured, managed mode is on and the entry and runtime are the bundle's;
an explicit knowledge_forager_entry_path outranks the bundle whatever knowledge_forager_managed
says, so a developer still points a colony at a source build; a named runtime is kept when only the
entry comes from the bundle. knowledge_forager_bundled (new, on by default, docs/CONFIGURATION.md)
is the switch that ignores a bundled engine entirely. knowledge_forager_managed: false — which
every config.json copied from the example carries — is "no engine named", not "ignore the one that
shipped": the switch is the switch. The supervisor is unchanged and verifies a bundled engine exactly
as it verifies a named one; what shipped is a candidate, not a fact.
An operator's steps are now: install, open Knowledge, press Enable knowledge. The engine runs
exactly while Knowledge is on. Managed mode used to start the engine with the colony whatever the
switch said, which was fine for an operator who had arranged it and wrong for every install that
now has an engine beside it: a process nobody asked for, holding memory on a machine that never
opens the Knowledge page. ApiHost.ReconcileForagerEngine starts the supervisor when the engine is
managed and Knowledge is on, and stops it otherwise — at boot with whatever the saved switch says,
and after every settings write, so Enable is what starts the engine and Disable is what stops it,
with no restart in either direction; an engine that had stopped at its restart ceiling is tried again
the next time Knowledge is turned on. The Knowledge door's installed axis says the engine shipped
with this colony and where; GET /knowledge/engine carries a bundled record — directory, version,
Node — when the engine it runs is the one from the box, null when an operator named the paths.
BundledEngineTests, nine, hold every branch of the decision.
What it is not, yet
The engine's interface is still its own: the Knowledge page reaches it through the host's proxy, and
the Sources, Knowledge and Review tabs inside the shell are W3-05. The Linux service unit needs no
change — the engine writes only under the colony's data directory — but a colony that upgrades into
this release by its own updater keeps knowledge_enabled as it was, so the engine starts when the
operator turns Knowledge on, not before. The Docker image builds from source and carries no engine
yet; a container attaches to a FORAGER it is pointed at, as before. Nothing about a colony that
attaches to its own FORAGER changes: knowledge_forager_endpoint with a credential is still attached
mode, and the bundle only steps in where no engine was named.
The harness
qualification/cases/M02.mjs, the engine that shipped in the box: the archive under test must carry
the engine beside the binary, its record must agree with the release manifest's components.forager
and components.node_runtime, the runtime must be a real binary; the host is started with
ANTHILL_KNOWLEDGE_ENABLED=1 and every ANTHILL_KNOWLEDGE_FORAGER_* variable cleared, so nothing
about the engine reaches it from the harness; it must run the engine in managed mode without being
told to, /knowledge/engine must name the bundle, the running engine must report the version the
record claims, the door must say the engine shipped with this colony, and stopping the host must stop
the engine. A binary with nothing beside it — a source run, or a build from before this release —
skips it with the reason in the record. M01 keeps proving managed mode against an engine named by
path; the two share their process helpers now.
Verified
package-engine.mjs run for linux-x64 against a stand-in for nodejs.org: the bundle built, the
runtime verified against the served SHASUMS256.txt, and the packaged engine started under its own
shipped runtime with a host credential from a file, answered on its loopback port, and served its
interface. Cross-building the Linux engine ON the Windows release box found the one thing a Linux
box never would: node-v*-linux-x64/bin/ carries symlinks (npm, npx, corepack), Windows
refuses to create them without privilege, and extracting the whole archive therefore failed the
build — for three files the engine never runs. The packager names the two members it wants, which
is faster and has no opinion about links at all. The same box found the second one: the Windows
archive was written with ZipFile::CreateFromDirectory, which named a nested entry
forager\server.mjs — harmless while every entry lived at the root, which was true until this
release put a directory in it, and wrong the moment it did. The zip is written entry by entry now,
with the forward slashes the format asks for, and a build refuses an archive that names anything
with a backslash. Every engine case in the harness — A02, A03, A04, A05, A06, A07 and A14: admission at the
limit, a bomb, a source that changes after preflight, a replayed publication, a crash with partial
results, direct requests — run against the bundled server.mjs in place of the compiled tree
(FORAGER_ENTRY), seven of seven; a bundle missing a file the engine reads at run time would have
failed there. M02 records the skip when no binary is under test. The release box's runs — the full
Anthill.Tests, and the harness against the published archives with M02 — are recorded in the
release notes on the channel.
Every file has a .sha256 beside it, written from the bytes that were archived; anthill-0.3.18.0.manifest.json lists them all with their sizes and the components this build agrees with. https://anthill.formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/anthill stays at the last image an Actions run pushed.
ANTHILL v0.3.17.0
v0.3.17.0 - the console switches organizations, and A08 runs
THE ENFORCEMENT WAS REAL AND THE CONSOLE COULD NOT USE IT. Since v0.3.15.0 an account standing in
two organizations gets 400 org_required from every route until it names one, and the console named
none: the moment an owner created a second organization, their own console stopped. And acceptance
case A08 — the same record id across organizations — had been blocked in the harness on W3-02 since
the harness existed. Slice 5 of the tenancy release (W3-02): the console half, and the case that
proves both processes end to end.
The console
settleOrganizations runs at every sign-in before the first panel polls: it reads
GET /organizations, keeps the remembered organization if the account still stands in it and
otherwise takes the first listed. Every API call carries X-Anthill-Org from ONE place — a wrapper
around fetch defined before the API layer — because the console reaches the host through three
shapes of fetch and forty-odd call sites, and the one that forgot the header would be the one that
failed; requests anywhere but this API never carry it. The switcher in the header appears only when
there is a choice, escapes the names it shows, and reloads the console on a change, since every
panel's data belongs to the organization it was fetched in. A console acting outside the installation's
organization opens on its projects rather than on Colony Live, which is the installation's. Signing
out forgets the organization. OrganizationSwitcherTests, three, hold that shape.
Checked in a real browser before it was written down: a Release build of this commit, a colony with two
organizations and a project in each, the console opened headless in Chromium — the switcher visible
with both, every API request carrying the acting organization, a switch reloading the console with the
other organization's header and its project list holding only its own project, and no page errors.
A08
qualification/cases/A08.mjs, automated, host and engine. On the host: a fresh colony, its first
administrator, a second organization owned by a coordinator, a project called Harbour and a
conversation in each; every read and the conversation export across the line 404, within 200; an owner
without a project role 404; a foreign header 403 and none from someone standing in two 400; the event
log, its live stream and the colony view from the other organization 403; a job queued in one
organization's Harbour 404 from the other and absent from its list; lists asked back to back; a service
identity minted in the second organization reaching only it; the static token reaching only the
installation's. On the engine: two organizations, Harbour in each, the same file in both, every project
route across 404 and within 200 with search and the export listing included, the operator in two
naming none 400, the host's credential bound to its organization. Tools are recorded as not exercised:
no model is configured in the harness.
qualification/README.md and cases.json: blocked is four of eighteen, all commerce.
Verified
Full Anthill.Tests: 4,013 of 4,013. The harness in the authoring sandbox against a Release build of
this tree and FORAGER 0.9.0: A01–A08, A14, A16, A18 and M01 pass.
Every file has a .sha256 beside it, written from the bytes that were archived; anthill-0.3.17.0.manifest.json lists them all with their sizes and the components this build agrees with. https://anthill.formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/anthill stays at the last image an Actions run pushed.
ANTHILL v0.3.13.0
v0.3.13.0 - a release cut by hand
THE MONTH'S ACTIONS MINUTES RAN OUT WITH .12.1 COMMITTED AND UNTAGGED. A private
repository meters every runner minute, Windows at twice the rate, and the first two days here --
nine releases and a CI run on every push -- spent the Team plan's allowance by the morning of the
16th. .12.1 was built and tested on the release box and the harness passed against it; the tag
that would have published it could not start a run until the cycle turned. A product whose only
way to ship is a runner somebody else meters is a product that cannot ship on a bad month. This
release is the other way: three scripts under deploy/release/ that do what the workflow's jobs
do, on the tagged commit, in a scratch worktree, on a Linux box and the Windows release box, and
put the same seven assets on both repositories with the same notes. It is also the first release
cut that way, and .12.1 rides in it.
The path
build-archives.sh runs on any Linux with the .NET 10 SDK -- the anthill LXC has one since its
first deploy from the tree -- and is build-binaries line for line: linux-x64 published
self-contained, win-x64 cross-published with the desktop shell beside the server, LICENSE,
README.md, CHANGELOG.md and config.example.json in each archive, the tarball and the zip
digested in sha256sum's shape. It refuses a tag whose AnthillRuntime.Version disagrees with
it, as verify-version does, and it asks the linux binary it just built for its version before
it will digest it. build-installer.ps1 is build-installer on the release box: the two win-x64
publishes, Inno Setup against them, the installer's sidecar. publish.ps1 is build-manifest,
publish-release and publish-public from wherever the six files have gathered: it checks every
sidecar against the bytes beside it, writes the manifest from those digests and sizes -- never a
second build -- and creates or refreshes the release under anthill/v<version> here and
v<version> on the channel over the REST API, with a fine-grained token that reads and writes
both repositories and nothing else. It will not create a release on a tag GitHub has not seen,
because GitHub would mint that tag at the default branch and call it the release.
What the path does not do, and says so in the notes it writes: build the Docker image. The
channel's consumers read seven assets, two sidecar shapes and one manifest, and those are the
same whichever way the release was cut, which is the point.
What rode along
.12.1, whole: the--host/--portflags that had never worked,CliApiFlagsTests, the
harness corrected by its first real run. Its entry below stands as written; it was never tagged.anthill --versionand--helpanswer before the runtime touches the disk. Initialising
materialised a workspace wherever a version was asked; the harness's build identification
asked from the repository root and left one there.CliVersionTestspins the order.- The LXC installer checks for the SDK the tree needs -- its test still grepped for a 9.x SDK
after the move to net10, passed on the box's 9.0.316, skipped the install and failed the
build with the service already stopped -- and a failed build no longer stops the colony: the
publish goes tobin.next, is verified there, and only then is the service stopped and the
directory renamed in, the previous binary kept beside it. - CI's Windows leg runs on demand, not on every push to
main: the release box runs the
suite on Windows before every tag, and a private repository bills that leg at twice the rate. - The harness, twice more: M01 expected a new engine generation after a crash-restart, and
the engine's contract is that a generation moves only when the store's history may have; A15
demanded equal row counts after a restoration a host had already written a startup event
into. Both cases now ask what the product promises, and both records are filed: eleven cases
green against a box-published.12.1, and A15 against the LXC's real.124workspace --
155 missions, 25,280 events, fivehomelab_*tables renamed toinfrastructure_*with every
row carried, restored byte-identical and reopened by the binary that wrote it. - The cutover is closed. The LXC deploys from the monorepo over a read-only deploy key; the
copyright lines name the two founders in every licence file;CUTOVER.mdhas every step dated.
Verified
In the authoring sandbox: the four changelog guards that read git, emulated with the monorepo
prefixes; both site suites; bash -n on the Linux script. The C# suite does not run there;
dotnet test Anthill.sln -c Release on the release box gates the tag -- green, or no tag. The
by-hand path's first run end to end is this release's own publication, by definition after this
entry is written: the archives from the LXC, the installer from the box, the manifest and both
releases from publish.ps1, releases/latest on the channel answering v0.3.13.0 with seven
assets. What that run found is recorded in the transition's STATUS at the repository root, and
the identified-build harness run against the published win-x64 archive is filed under
qualification/evidence/.
Every file has a .sha256 beside it, written from the bytes that were archived; anthill-0.3.13.0.manifest.json lists them all with their sizes and the components this build agrees with. https://anthill.formicaria.us
Cut by hand on the release box with modules/anthill/deploy/release/ (docs/DEPLOYMENT.md section 4, releases without Actions). No Docker image was built for this release; ghcr.io/formicaria/anthill stays at the last image an Actions run pushed.
ANTHILL v0.3.12.0
v0.3.12.0 - the acceptance harness: eighteen cases against an identified build, with evidence
A GREEN SUITE IS NOT EVIDENCE THAT THE PRODUCT, ASSEMBLED, DOES WHAT THE ACCEPTANCE MATRIX
REQUIRES. The roadmap says so in as many words and lists eighteen cross-module cases, A01--A18,
each demanding a record of the build, the environment, the inputs, the command, the observed
result and the supporting log. Nothing in any of the three modules produced one. This release is
the harness that does (W5-01), at the repository root -- qualification/ -- because it is
Formicaria's and not this module's: it runs the published anthill binary and the real FORAGER
engine as processes, the way an install runs them, and writes evidence/<run>/run.json with the
commit, the artifact digests (from --artifacts or the release manifest .11.0 added), and per
case what was real, what was simulated, every step with what was observed, and a verdict. A skip
is never a pass; a case whose surface does not exist yet is blocked and names the package; a
case that needs hardware is manual and has its procedure.
What runs, and against what
Eleven cases and M01 are automated. Against the engine, in the authoring sandbox and on the
release box: A02 (no model: upload, process, search), A03 (a batch measuring exactly the limit and
exactly one byte over, through preflight, upload and the worker's re-measurement), A04 (a 9 KB
archive expanding to 8 MiB against a 1 MiB allowance), A05 (a preflight replayed with different
bytes; the registered copy altered before processing), A06 (eight identical uploads in flight at
once, five rounds; eight concurrent process requests), A07 (cancel mid-job; the engine SIGKILLed
mid-job and restarted over the same store; a stage failure retained through the retry) and A14
(no credential, a read-only credential, a lapsed grant). Against the host, on the release box
(ANTHILL_BIN): A01 (knowledge and devices off, /modules honest, anthill --qualification),
A16 (an engine one patch below the managed floor refused in one sentence and not retried, one at
the floor accepted -- the engine there is lib/fake-engine.mjs, told which version to report,
and every record says so), A18 (knowledge managed with an entry that is not there: the workspace
serves, the door explains), and M01, the first end-to-end managed FORAGER start: the real engine
under the real supervisor, verified, read by /knowledge/status and the Knowledge door, killed
out from under the host and restarted with a new generation and the same instance id, gone when
the host is. A15 runs only against real legacy data and the binary that wrote it
(ANTHILL_LEGACY_DATA, ANTHILL_LEGACY_BIN): the legacy binary opens the copy, a backup is taken
with nothing running, the candidate migrates, the upgrade is declared failed, the backup goes
back whole and the legacy binary opens it with the counts it had -- the compatible restoration,
timed -- and the executable-only rollback is observed on a throwaway copy and labelled "not
relied on". Blocked: A08 (W3-02), A09 (W4-05), A12 (W4-06), A13 (W4-02), A17 (W4-01/02). Manual:
A10 and A11, hardware, with procedures under qualification/manual/ that end with what the
person files and in what shape; A16's device half and A15's mid-migration failures likewise.
What it found the first time it ran
Three things the unit suites had not, all in FORAGER 0.8.1 and all under real concurrency: the
losers of eight identical concurrent uploads answer 500 (UNIQUE constraint failed: source_documents.id) where they should answer duplicate; the losers of eight concurrent
process requests answer 500 (an admission cannot go from running to running) where they should
answer 409; and the upload route's per-member refusal sentence carries the member's path twice.
The invariants held in every round -- one admission, one source, one job -- and the losers
crashed saying so. A06 fails against 0.8.1 and the record says why. Forager 0.8.2 fixes all
three; the harness is what will show it.
This module
docs/QUALIFICATION.md §3a names the harness as the third thing with that name and says what it
is not: it never gates a merge and never substitutes for the deterministic or the live table.
README.md at the root lists qualification/. No product code changed in this release; the
version moves because the harness is part of the release's identity -- the build it runs against
is the one that carries it.
Verified
In the authoring sandbox, the full run against Forager 0.8.1: A02, A03, A04, A05, A07, A14 pass;
A06 fails on the three findings above; A01, A15, A16, A18, M01 skipped (no .NET SDK), five
blocked, two manual. The host cases are written against the /modules, /knowledge/engine and
/knowledge/status payloads as they stand and run on the release box with ANTHILL_BIN
pointing at this release's own linux or windows archive's binary; that run is the record. The C#
suite does not run in the sandbox; dotnet test on the release box gates the tag.
Every file has a .sha256 beside it, written from the bytes that were archived; anthill-0.3.12.0.manifest.json lists them all with their sizes and the components this build agrees with. https://anthill.formicaria.us
ANTHILL v0.3.11.0
v0.3.11.0 - one manifest per release, and the stager reads it
A RELEASE SAYS WHAT IT IS MADE OF. .10.2 gave the product a public channel and six assets
per release, each with a .sha256 beside it. Six sidecars are six separate answers to six
separate questions, and nothing ties one to another or to a version: six correct-looking sidecars
from one release uploaded beside archives from another verify perfectly. This release adds the
seventh asset, anthill-<version>.manifest.json -- one document naming the version, the source
tag, the commit, every asset with its size and SHA-256, and the component versions the build
agrees with -- and teaches the headless stager to read it. W2-06's first piece; the sidecars do
not change, so nothing shipped earlier reads a release differently.
The manifest
build-manifest runs after the three build legs and writes the manifest from the digests THEY
attached to the draft and the sizes the release reports -- never from a second build, which is the
only way the manifest and the sidecars cannot disagree on the day they are written. It carries
components: anthill, forager_engine_min (grepped from MinManagedEngineVersion, the floor
the supervisor enforces) and micromound_protocol (in-tree). publish-release publishes only
when exactly the seven expected assets are on the draft, and publish-public copies all seven to
the channel. signature is null and signing says why: there is no release-signing key yet, and
a manifest that pretended otherwise would be the more dangerous document. The field is there so
signing becomes a value, not a schema change.
The stager reads it, and the rule is pure
ReleaseManifest (Anthill.Core.Updates) parses the document and refuses it whole when it is not
exactly the shape the workflow writes -- another manifest_version, no version, no tag, an asset
without a name or without a 64-hex digest. Dropping a bad asset and returning the rest would let
a download go unverified because one field was missing. ReleaseManifest.Choose is the whole
rule for which digest a download is judged by: a release with a manifest is judged by the
manifest -- unreadable, for another version, or silent about the asset is a refusal the sidecar
does not rescue, and a manifest and sidecar that disagree refuse too; a release without a manifest
is judged by its sidecar exactly as every release before this one was. UpdateStager fetches
both when both are there, hands them to Choose, and logs which one verified the download.
UpdateChecker reports manifest_url beside release_url. The desktop updater keeps reading the
sidecar; the manifest is additive by design and the desktop is not the shape that updates
unattended without a person nearby.
What this release does not say
The manifest is not signed, and W2-06's remainder is not here: the packaged install that bundles
FORAGER with a pinned engine version (the supervisor's floor and restart policy are still
constants, and their comments now say so instead of promising the manifest will supply them), the
device update staging, the update sequence and the data rollback. Those are the qualification
gates' business (W5-06) and the owner's key decision (W1-06's custody design), in that order.
Tests
ReleaseManifestTests: the asset name, the parse of what the workflow writes (digests answered
case-insensitively, lower-cased), thirteen refused shapes, the empty-asset manifest, and the seven
cases of Choose -- manifest of record, agreeing sidecar, disagreeing sidecar, wrong version not
rescued, unreadable is not absent, silent about the asset, sidecar alone, and nothing at all. The
manifest program in the workflow was dry-run against three sidecars in the sha256sum shape,
including the installer's newline-less one, and produced the document Parse accepts.
Verified
node --test tests/ui/*.test.js and the site's suite in the authoring sandbox; the C# suite does
not run there. dotnet test on the release box gates the tag -- green, or no tag -- and the tag's
release run, with the seventh asset on it, is the identified build.
Every file has a .sha256 beside it, written from the bytes that were archived; anthill-0.3.11.0.manifest.json lists them all with their sizes and the components this build agrees with. https://anthill.formicaria.us