Skip to content

SIA v1.8.0 — the receipts survive the move

Choose a tag to compare

@AnubisQuantumCipher AnubisQuantumCipher released this 19 Sep 21:36
· 19 commits to main since this release
2a5d7c3

Four reporters and one migrated maintainer machine hit this release where
1.7.8 had never been tested: a 2015 dual-core with no discrete GPU, an Arch
desktop with 1,130 packages, a btrfs box whose subvolume moved, a home
directory carried to a new VM by rsync, a GitHub Actions runner refusing
unprivileged namespaces, a corpus outrunning nine journal shards. Each fix
here is named against the value the report carried, and each refusal that
stays now says which value it refused.

First light and install

Issue #10 (Enor75) reported first light unable
to finish on a CPU-only 2015 Broadwell i5 with integrated Iris 6100: three
nested deadlines (60s per-embedding gbrain, 300s subprocess, the installer's
120s sia ready join) all sat below what a one-time backfill needs there,
surfacing only as an unattributed command exceeded its 120-second runtime deadline. The reporter's own workaround measurement — 52.4s CPU-only vs
22.5s with OLLAMA_IGPU_ENABLE=1 for four ~1500-word inputs — is roughly a
2.3x difference, by their own description, since Ollama silently drops the
integrated GPU unless told. First light now gets a finite, larger completion
ceiling separate from steady-state limits, CPU-only stages emit a
content-free progress heartbeat instead of going silent, and deadline labels
name the command that timed out. A maintainer install against a real
2,191-page corpus completed without being killed — not reproduction on the
reporter's own hardware.

The same issue's item 4 reported that the installer's exact-match
DropInPaths check on ollama.service left no way to set
OLLAMA_IGPU_ENABLE=1 without failing the install. One documented drop-in,
$SYSTEMD_USER_DIR/ollama.service.d/sia-operator.conf, is now accepted — a
regular, owned, 0644/0600, ≤4096-byte file of only
Environment=OLLAMA_<NAME>=<value> lines (OLLAMA_HOST/OLLAMA_MODELS
refused by name), which SIA itself never writes. A read-only notice reads
the unit's recent journal and warns when Ollama runs CPU-only, without
echoing journal content or touching hardware.

Issue #9 (Enor75) reported every fresh install
landing in state degraded: the shipped config.example.json carries a
_comment key inside retrieval, which the validator rejected — the
installer's own example failed its own loader. _comment is now accepted
there like other config blocks, with a regression loading the shipped
example through the real loader.

Issue #8 (joniler) reported omarchy plugin remove deleting uninstall.sh — the only documented teardown — while
sia-brainstem.service, ollama.service, and both backup timers kept
running; llama-server sat at ~172% CPU for hours on the reporting machine.
sia uninstall and sia uninstall --purge now survive checkout removal via
the stable launcher, and the brainstem checks the plugin manifest before
every pulse, taking its existing non-restart exit and pointing at
sia uninstall if registration is missing or unsafe.

An update whose gbrain overlay pin moved (this one) used to refuse every
existing install with "existing private gbrain tree lacks an exact current
release receipt; explicit replacement requires SIA_REPLACE_TOOLCHAIN=1". A
genuine SIA receipt for an earlier pin — the managed-by header and the
digest of exactly the binary beside it — is now an ordinary upgrade: the
installer says it is rebuilding for this release and retains the prior
tree. Unreceipted, foreign or torn trees still require the explicit
consent. When the installer cannot acquire its lifecycle lease it now lists
the processes still using the installed runtime (an hourly continuity run
finishes on its own; an agent's sia MCP connection must be closed).

Continuity

Issue #12 (m10ust) reported continuity failing
every hourly run on an 1,818-page corpus, none of its three stacked errors
naming the value that caused them. The capsule directory entry bound had
been aliased to a 1,024-record limit meant for tailing sources, not a
whole-corpus freeze — issue #7 (ArdonisLLC)
hit the same aliasing independently at 1,130 package pages. The bound is now
independent of source-tail sampling, still governed by capsule's own
record/depth/path/link envelopes. A shard-key defect inspecting only the
first digit of -part-N — rejecting part-10–part-19 and part-100+ —
is fixed across the parser, validator, and shard/benchmark readers. The
corpus receipt's device-number binding, also reported here, is addressed
under storage identity below.

The resident pulse

Issue #13 (m10ust) reported the pulse loop
saturating a core: once a pulse's own work exceeds PULSE_SEC, the loop's
max(5.0, PULSE_SEC - elapsed) wait collapses toward a 5-second floor. The
reporter's own measurement — load average 2.44 and llama-server at 60.5%
CPU for hours at the 60s default, settling to 0.40 load and ~10% CPU at a
locally overridden 900s, for a derived per-pulse cost of roughly 145s
(their figure, derived rather than measured) — is why an overrun cycle now
waits the full configured interval, logging its own monotonic duration and
any overrun wait.

Two related fixes: the last pulse failure is retained in
~/.local/state/sia/pulse-failure.json (redacted, 240 characters) and
shown by sia status/sia ready — a pulse failing every four minutes for
a week was previously visible only in journalctl. Continuity details now
append a closed, named reason code for SIA's own capsule refusals
(corpus-receipt-root-mismatch, capsule-entry-bound, others) instead of
the unattributed message issue #12 described.

Storage identity after a move

Two receipts bind device and inode: the installer's corpus receipt and the
delivery epoch's adoption. A btrfs subvolume change, an rsync, or a
restore by copy changes those numbers — issue #12's exact case — after which
every pulse refused unattributed and reinstalling refused outright.
Refusals now name both identities and the remedy. sia readmit reports the
drift; sia readmit --yes (daemon stopped) rewrites the corpus receipt's
root and publishes a sealed readmission.json beside the unchanged
adoption. install.sh re-binds a moved v2 receipt through the existing CAS
journal only under explicit consent
(SIA_READMIT_MOVED_STORAGE=1 ./install.sh); without it, a drifted epoch
still fails with the remedy named. A tailed log with matching fingerprints
but a changed device/inode now continues at its saved offset instead of
replaying from byte zero.

Updating from 1.7.8: every gate the first light hit, named and fixed

The maintainer machine's update was run through the installer thirty-odd
times until first light completed, and each stop was a gate that would have
met every 1.7.8 user with a corpus older than a few weeks:

  • A retained status.json from the previous release refused admission
    ("resident status cannot be admitted"); the integrity rule now admits an
    earlier canonical release and still refuses a newer one, and the
    live-publication rejoin and controller status admission rely on it.
  • Weekly epochs written by 1.7.x declare a source manifest but no event-id
    roster; the completeness lookup refused every pulse on the first one.
    The roster is reconstructed from the exact retained sources by lineage
    digest (live page or corpus git history) and an unretained source
    refuses by name.
  • The event page plan reserved raw bytes plus two base64 projections for
    every day page the cross-day occurrence scan read, exhausting the 16 MiB
    plan ceiling on an organ a few weeks old; scanned pages are bound by
    digest and their bytes released after use.
  • The live policy admits 1 MiB of candidate content but a 64 KiB payload;
    one day page past ~60 KB refused every pulse. Such a candidate is now
    ineligible for a slot and the cycle proceeds.
  • Capacity admission counted non-ASCII strings character by character in
    Python on every consistency check of a multi-megabyte retained batch,
    which left first light at 96% CPU for half an hour before it reached
    the engine; the count is now arithmetic over C-speed primitives with
    identical results, proven by a property test against the old loops.
  • sia pulse and the brainstem rendered state and events_pulse from
    the cycle result; the compact lane returns the completed reader's view,
    so both raised KeyError('state') after memory was already published and
    first light was reported as failed. The compact completion is now
    rendered from the status it published. The live view's post-projection
    rejoin used the legacy reader on that lane and refused the checkpoint
    capture; it uses the checkpoint reader like the first read.
  • The compact lane carried every predecessor status error forward forever:
    the maintainer machine stayed degraded on sense_skills and
    corpus_write strings from a 1.7.8 pulse ten days after every later
    capture had admitted that sense and every corpus stage had committed. A
    pulse now resolves exactly the errors it re-attempted (a declared source
    settles its sense_* error, a committed corpus stage settles
    corpus_write) and keeps the rest.
  • The compact lane never ran the legacy prelude's provenance convergence,
    so after the filesystem move sia ready refused every memory surface
    with "legacy model-grade provenance migration is pending" and no pulse
    could ever clear it. A fresh compact capture now converges interrupted
    natural-history and grade transactions and legacy take/intent provenance
    first, never inside a captured package's window.
  • The installer refused to replace an existing user-editable plugin tree
    only at step 8, after first light, and left the brainstem disabled. A
    read-only preflight names that gate (SIA_REPLACE_PLUGIN=1, or update
    through omarchy plugin update khephri.sia) before step 1.
  • The opt-in controller-source lane (mind.controller_source, off by
    default) has no rollover: every capture carries every page version since
    adoption and its ceilings are final. The maintainer machine refused
    complete-byte-capacity ten days after adoption, with a 16.7 MB capture
    growing about 360 KB per pulse, and every later pulse would have refused
    the same way. A capture refused for capacity now retires the lane under a
    receipt (controller-source-superseded/retired-<digest>.json), releases
    only the memo's lane authority and moves the retired live generation
    beside the receipt, deletes nothing, and hands the pulse back; sia controller retire [--yes] and
    SIA_RETIRE_CONTROLLER_SOURCE=1 ./install.sh are the operator forms.
    A bounded segment design is the maintainer's follow-up; the bound and
    its cost are now documented in the manual.
  • The controller-source lane never materialized queued agent notes; only
    the legacy pulse did. On the maintainer machine 56 sia note / MCP
    note requests from nine days sat in the inbox unmaterialized while the
    README promised the relay. A compact pulse now materializes queued notes
    before its capture, commits them, and acknowledges them after it
    completes; a refused pulse leaves them queued without duplication.
  • sia note --help queued a note whose body was "--help" (three such
    pages exist in the maintainer corpus); an option-shaped first token now
    refuses with the usage line, as sia take and sia intend already did.
  • A sense refusal and a corpus-write refusal log their refusal chain
    (file:function:line) beside the 160-byte status string.
  • The lazily bound live-publication helpers were reached through the owner
    dict before any attribute access had bound them; a moved gbrain overlay
    pin refused the update unless SIA_REPLACE_TOOLCHAIN=1 was passed; the
    gbrain self-upgrade check compared coloured stderr; the isolation probe
    rebound library globals inside a checkpoint transaction. Each is fixed
    and each refusal now names its clause.

Portability (namespaces, CI)

Bounded helper processes launched under unshare --user --map-root-user --pid unconditionally. Ubuntu 24.04's AppArmor default and other hardened
kernels refuse unprivileged user namespaces, which errored 1,100 tests on
the GitHub Actions runner while the same suite passed on Arch. The
namespace shape is now probed once per process; where refused, a
process-group fallback is announced once on stderr, and a new test proves
the fallback launches without unshare.

The controller-source and delivery-epoch runtime lane

Most of this release's ~250 commits are component and recovery-boundary
progress on the durable controller-source construction in ROADMAP.md's
current mission amendment: a local transaction from an immutable retained
batch through sealed page effects, a clean Git generation, receipt-bound
gbrain sync, and graph/status/live publication and acknowledgment. This is
component and recovery-boundary progress only — not a claim a resident
pulse used the complete path, and not a cognitive-capability claim, which
needs a front-door run with witnesses and a held-out measurement against a
dense-retrieval baseline (ROADMAP.md §P1.0). Neither exists; no mechanism
here carries a neurocognitive name on a measured win.

Docs

docs/MANUAL.md gains the storage-identity section (sia readmit, the
moved receipt state, the retained pulse failure), the operator drop-in
contract, and two troubleshooting entries; README.md's requirements name
the drop-in and the namespace fallback; docs/ARCHITECTURE.md describes
the controller-source lane that landed on this branch. The ROADMAP's
marketplace freeze declaration is closed (state=none): verify issue #4078
listed the bound commit on 2026-09-04, so the reason for the freeze ended
then.

Delivery boundary

This release does not reproduce issue #10's failure or fix on the
reporter's own Broadwell hardware, and contains no held-out
cognitive-measurement win for the controller-source lane. The Omarchy marketplace
listing stays bound to the verified commit
8a624efc911457ae393a72758ade8729de5ba45d (v1.7.8) until a new verification
cycle binds this release; omarchy plugin add with the git URL installs
current main regardless of that snapshot.