ITISYOU OS

Story

Development journal — narrative, not evidence. Technical truth lives in the evidence bundles and the git history; this is the story of how the system is being built, in the order it happened.

ChapterDate rangeCovers
CHAPTER-001 — Before the first line6 September 2026, morningThe frozen-input chain and its hash checks, the specification gap and its hold, the repository's creation, and the site's first (blocked) and second (published) deployment attempts.
CHAPTER-002 — The flood, and the machinery that says no6 September 2026The alert-daemon bug, the 31-message flood, the incident ruling and the protected send ceilings that followed; Wave 0's fourteen packets and the negative-control test that proved the pipeline refuses what it should.
CHAPTER-003 — The phone6 September 2026The first device install, the Download-mode lesson, the week-long secrets-scan CI failure over a hardcoded device serial, the AOSP source sync and the disk-cap ruling, the product naming, and the multi-branch preparation fan-out.
CHAPTER-004 — The build fights the disk, and the core fails review6 September 2026, afternoonThe disk-cap ruling settled, two failed build launches and the third that ran, a repeat sync ended mid-flight by a VM restart, HDD contention from eight parallel Rust builds and the ruling that moved them off the shared drive, the adversarial review that found four blockers in the Wave 2 core, and the SSD migration plan waiting on hardware.
CHAPTER-005 — Two more reviews, and a long night for the build6 September 2026 evening — 7 September 2026 early hoursThe second review's dark law cases and surviving mutations, the fixes, and the third review's four new survivors; the evening rulings on Ident-only constructors, the single metering wire, the trailer/grant ledger and the chain hash; the recurring ADR-numbering collisions with the Plan table; the build's 17→19 GB memory saga and the forced yield that stopped it; the alert daemon killed twice and moved to a scheduled task; the Drive backup held on a missing tool; and the usage-pacing rule for counters the session cannot read.
CHAPTER-006 — The SSD, the vanishing builds, and a clean review7 September 2026A parcel-watcher false alert, the 24-minute SSD migration, three build launches that vanished until a session-keepalive fix, an out-of-memory kill answered with more swap and a gentler garbage collector, a memory ceiling hand-tuned against a busy desktop and an old daemon that fought it, the fourth and fifth core reviews (the fifth finding no blockers and freezing a baseline), and the day's new rules for asking and standing permissions.
CHAPTER-007 — The build finishes, and the phone comes alive8 September 2026The overnight build's memory ceiling held against a busy desktop, the finished receipt and its own counting bug kept honest rather than rewritten, the flash runbook's dry run, verifying a second Telegram channel by phrase and terminal despite an inbox the session cannot read, the owner's own sideload and first boot of the project's build, a touch-probe failure traced to a permission boundary, the device probe chain (network path, secure key store, one listener, an exposed call-audio path), four hand-built test apps, and an unprovisioned SIM left for the owner.
CHAPTER-008 — M1, signed with conditions8 September 2026Milestone M1 sealed: the device egress inventory's two owner reviews, the single question about whether the phone should be able to call at all and the careful line drawn around it, the owner's conditional signature (baseline build, boot and inventory only), and what stays open by name — shared-identity isolation, a listener still to be blocked, and every SIM-dependent test.
CHAPTER-009 — A daemon with its own name, and a drive that ran thin8 September 2026, eveningWave 2's harness finds no system principal to test and the decision not to borrow one; a dedicated-identity daemon built for three and a half hours to fail on two lines of platform policy it contradicts; the system drive sliding under reserve as the pagefile grew; the owner's two rulings within an hour (hold, then a lower line and resume); the memory-cap daemon restoring a stale number instead of the day's actual limit; and the cheap-models-first rule.
CHAPTER-010 — Proof over assurance, and policy that would not bend9 September 2026The rebuilt daemon flashed and booted, its shell-unreadable file proven present by the device's own denial record; a task refusing a relayed assurance and verifying on-device before the harness passed all three principal classes; three watchdog daemons found dead for three hours; a forked tamper-evident journal preserved rather than stitched; the network default-deny narrowed to one honest mechanism after platform policy refused the other, and a revocation-safe firewall choice made against an earlier sketch; and the L2 service skeleton built and failed on a stable-versus-unstable interface contradiction, fixed by keeping the stable contract.
CHAPTER-011 — What a stable contract costs, and a reserve that came due9 September 2026, afternoonThe owner's batch answers, one reversing the night's lowered disk reserve back to 30 GB and one drawing a hard no-touch line around the phone; the L2 skeleton failing twice — stable-vs-unstable interface, then the API snapshot a stable contract demands — each fix revealing the next; the restored reserve colliding with the rebuild it blocked; the collision surfaced to the owner rather than worked around; and the owner's precise "clear diag" freeing 15.5 GB of Remote Desktop trace logs and nothing else, so build 3 could start.

Standing duty — the 360 review (owner ruling 2026-09-06)

From milestone M4 onward, each milestone's chapter carries a section listing the problems that push phone users toward third-party apps (recording, vault, gaming, cleaner, blocker, tracker, backup, launcher, and the like) and states, for each one, whether ITISYOU OS closes it natively or leaves it open. The project has reached M1 (Chapter 8). That section does not apply yet; it starts at M4 and will appear here from that milestone's chapter onward.

Chapter 1 — Before the first line

6 September 2026, morning

Development journal — narrative, not evidence.

The build did not open with code. It opened with a stack of documents and a rule about what to do if they disagreed with what was on disk.

The frozen inputs are meant to chain: a specification, an architecture baseline derived only from that specification, an implementation plan derived only from the baseline, an owner action schedule that pre-rules the decisions the plan leaves open, an autonomy charter that governs how far the executor may go without waiting, and a runbook that operationalises all of it into 152 packets. Each document is supposed to carry the hash of the one below it. Before any of the fourteen Wave 0 packets could start, that chain had to be checked link by link, because a plan derived from the wrong baseline, or a runbook quoting the wrong packet identifiers, would have been a bad foundation for everything after it.

The check found a real gap. The specification present on disk at the start of the day was an old draft — later work identifies it as v0.1 — while the runbook demanded the frozen v0.3.1 FINAL. The plan and baseline binaries themselves were not present on the host at all; only their expected hashes were. Rather than proceed on a partial match, or quietly substitute a summary for a missing source, the state was written down as an evidence hold: verified inputs, missing inputs, and nothing else attempted until the owner supplied the rest. This is consistent with the source-of-truth manifest's own historical record, which shows the pre-freeze specification recorded as SPEC_v0.1.md, marked non-authoritative, with a note that it "was replaced in place by v0.3.1 on 2026-09-06, hash retained, no copy exists" [commit 36e3b97].

The owner then supplied the frozen specification and one instruction: hash it, and if the hash does not match, stop and do nothing further. It matched: 135edc24a3ca…26b975 for docs/SPEC.md, version "0.3.1 FINAL / FROZEN (2026-09-05)" [commit 36e3b97]. The baseline and plan binaries arrived and matched their expected hashes too, and the owner action schedule and autonomy charter matched theirs. The source-of-truth manifest that resulted records all seven governance documents by hash, records the runbook's five constituent parts by hash under a provenance_not_in_repo section (they stay outside the repository; only their fingerprints are kept), and explicitly marks the old draft and an even older answers file as historical — present in hash only, never to be read as authority [commit 36e3b97]. The owner's next instruction was simply to wait for the goal prompt before doing anything else, which is the shape the whole day would keep: the owner sets a rule, the executor checks the world against it, and the transition between the two gets written down before it is acted on.

With the goal prompt given, packet W0-01 — freeze normative inputs — ran and passed on the first attempt: six of six tests, evidence sealed, commit 36e3b97 [bundle ddd51fb966d8…, migrated at W0-08 into the versioned schema; see Chapter 2]. The canonical repository was created on the external drive as the autonomy charter requires, with the governance documents copied in and their hashes carried forward into the manifest above.

Ahead of W0-01, though, came a packet outside the numbered 152: PRE-00, a public website. The autonomy charter asks for a truthful public window onto the project from day one — every milestone shown grey, nothing claimed that is not backed by evidence, updating only from validated state. The design is deliberately plain: a generator (site/generate.mjs) reads two data files — the site's own content and status/milestones.json — and writes static pages; it is run twice and the outputs are compared byte for byte, because a site that cannot reproduce itself is not a site whose claims can be trusted. A checker (site/check.mjs) refuses to publish a milestone as passed unless it carries an evidence hash and a target label, and separately scans every page for anything resembling a path, a serial, an email address, or a token before it is allowed out the door.

The first publication attempt got as far as a complete, checked, screenshotted build and then stopped: the local generation passed, the reproducibility check passed, and twelve page loads under a headless browser showed zero console errors and no accessibility regressions — but the wrangler deploy --env staging command itself was refused by the coding tool's own permission classifier, twice, before any Cloudflare account was even reached [bundle d54da1b91f17]. The runbook's own rule 22/31 anticipated exactly this shape of stall: keep the built artefact, record the refusal honestly as PENDING-PUBLICATION rather than force it or quietly skip it, and let operating-system work continue regardless, because site publication must never block Wave 0. Two smaller decisions were made in the same attempt and later accepted by the owner permanently: Playwright (via playwright-core, Chrome channel) stood in for the usual browser-extension visual check, since the extension was not connected that morning, and a Workers static-assets deployment with a custom domain was used in place of the Pages product named in the charter, matching the account's existing convention for a sibling site [bundle d54da1b91f17, d54da1b91f17→5bf61d6cffdb].

Later the same day, once the owner lifted the deployment restriction, the second attempt ran the same generator output through staging and then production, compared every served byte against the local build across seven sampled paths — the homepage, status, roadmap, runtime and proofs pages, the app bundle and the vendor three.js bundle — and got an exact match on all seven, over TLS, with a strict content-security policy and no analytics or external hosts anywhere in the page set [bundle 5bf61d6cffdb]. ai.itisyou.app went live carrying Phase 0: nothing claimed as done, one milestone gate defined and coloured grey, waiting for the first real evidence to turn it green.


References: git commit 36e3b97 (freeze normative inputs, W0-01); evidence bundles ddd51fb966d8… (W0-01, migrated), d54da1b91f17… (PRE-00 attempt 1, pending publication), 5bf61d6cffdb… (PRE-00 attempt 2, PASS).

Chapter 2 — The flood, and the machinery that says no

6 September 2026

Development journal — narrative, not evidence.

The autonomy charter specifies a loud alert cadence for genuine blockers, because the owner wanted to be reliably found without being buried: ten messages two seconds apart, then sixty seconds of silence, repeating for roughly half an hour, then slowing further. The first version of the alert daemon (tools/alert_daemon.py, commit 1810640) implemented that cadence in the direction it read, but not in the direction it wrote.

At 08:57:59Z the daemon sent the first ACTION REQUIRED alert for ALERT-0001, a genuine W0-01 owner-blocked state. alerts.json had initialised the alert's first_sent_at field to an explicit null. The send path used dict.setdefault to fill in fields — a function that only fills in a key that is missing, and an existing null is not missing, so the field stayed null. The scheduler then called datetime.fromisoformat(None) to compute the next send time and raised, and the exception escaped after the message had gone out but before the daemon's state was saved to disk. Every second thereafter the daemon woke, found no record of having sent anything, and sent again. Thirty-one identical messages reached the owner's phone between 08:57:59Z and 08:58:41Z — one every 1.4 seconds — before the daemon was stopped 42 seconds after its first send [dispatch log, 31 records tagged ALERT-0001; incident report INC-0001].

The owner's response, recorded the same day, was specific rather than punitive: this was an operational bug in execution scaffolding, not a violation of any of the eight Laws, and it should be logged as an incident on that basis [INC-0001]. But the fix could not simply patch the one crash. The owner ruled a ceiling that does not depend on the daemon remembering anything at all: never more than ten sends in any rolling sixty-second window, never more than forty sends for one alert, both counted by re-reading the append-only dispatch log itself on every tick rather than trusting in-memory state — and made the two constants that encode this protected, so that raising them later requires an explicit OWNER-REVIEWED trailer rather than a routine edit [INC-0001; ADR RUL-2026-09-06-01]. The corrected daemon now writes its intent to send before it sends, reconciles history from the dispatch log rather than its own memory, and stops cold at the ceiling with the hold state still visible to the owner [commit b17d858]. An offline test suite and an eight-hour virtual-clock dry run against a sender that delivers nothing were required and produced before the daemon was allowed to run live again; the dry-run schedule is attached to the incident record and shows exactly forty sends, never more than ten in any minute [INC-0001-dryrun-8h-schedule.json]. The fix held up against a second real alert later the same day — recounted in Chapter 3 — which hit its ceiling of forty sends and stopped exactly on cadence [dispatch log, ALERT-0002].

With the incident closed, Wave 0 continued. Its fourteen packets build no part of a phone; they build the apparatus meant to refuse unsafe work before any privileged code exists, and each one earned its own evidence bundle rather than a shared assumption of correctness.

W0-02 laid out ten empty Rust crates with a tree checker that rejects any stray directory or dependency outside the declared set [commit 0267546]. W0-03, the first genuinely adversarial packet, defines the protected-path policy and a guard that inspects every commit touching it; the guard's own first version had a hole its own tests caught immediately — it read the protection policy from the commit being checked rather than from the base it was checked against, so a commit that deleted the policy would have approved itself against its own absence. It was corrected to read policy and register from the base ref, with a bootstrap rule for when the base predates any policy at all [commits 549df1b, 34f4a48, 1e18276]. W0-04 through W0-07 added private build provenance, the Binder/stable-AIDL decision proved with the real Android compiler rather than assumed (ADR-IMP-001, commit bd208f0), and the two typed records — CapabilityRequest and Decision/Meter — that carry the system's audit trail: the request schema keeps identifiers to a small closed grammar, closed enumerations, and a prompt that only ever travels as a hash, verified against twenty thousand random mutations that never produced an accepted non-canonical message [commits 0ecbfde, a38e5f2].

W0-08 defined the evidence bundle format itself and immediately put it to a harder test than any later packet would face: the nine bundles written before the format existed had to be migrated and re-validated under the new, stricter validator, and one of them — the PRE-00 site preflight — needed its checks rewritten as an explicit test list before it would pass [commits b0f2cf0, a6220ed]. W0-09 and W0-10 built the fakes the rest of the project tests against — a deterministic registrar, policy table and hash-chained audit log, and a scripted model provider that can be told to behave, misbehave, lie, stall, disappear, or rate-limit on command, all offline. W0-11 built the Law registry: negative tests for every one of the Laws, pinned by hash, with a guard that watches for removal, renaming, skipping, or any quiet softening — reads confirm the guard catches #[ignore], removed tests, renamed tests, and uncovered Laws, and that the protected-diff check will not auto-approve any of them [commit 28b24af, law registry hash 01b30823cc47…]. W0-12 added ten synthetic prompt-injection attempts mapped to the exact denial each should provoke, and W0-13 checked that every subsystem in the No-AI fallback matrix is either tested under five model-failure modes now or explicitly named for the packet that will make it so.

W0-14 turned all of it into one pipeline — static checks, build, unit and Law tests, an honestly-absent device-evidence stage, and a bundle gate — and proved it meant what it said: a branch carrying one Law test marked #[ignore], pushed through as a negative control, was caught on two independent fronts in the same run, the registry-hash pin and the protected-diff weakening check, and the branch was discarded rather than merged [commit dad05f1, f43b964; bundle f224d530fca9…]. With the fourteenth bundle sealed — 171 of 171 tests passing across the wave, zero skipped — M0 was generated deterministically from the validated evidence alone, and the public site turned its first milestone gate green [commit ea02b5a; bundle f224d530fca9…].


References: incident report INC-0001-alert-flood.md and its dry-run schedule; dispatch log entries for ALERT-0001/ALERT-0002; ADR RUL-2026-09-06-01; git commits 1810640, b17d858, 0267546, 549df1b, 34f4a48, 1e18276, bd208f0, 0ecbfde, a38e5f2, b0f2cf0, a6220ed, 28b24af, dad05f1, f43b964, ea02b5a; evidence bundle f224d530fca9… (W0-14 / M0 gate, 171/171 tests, law registry 01b30823cc47…).

Chapter 3 — The phone

6 September 2026

Development journal — narrative, not evidence.

Wave 1 opens with a question the plan will not let anyone answer from memory: which exact source tree boots this phone. The owner's schedule is explicit that only a boot log taken from the physical device — not a document, not an assumption — qualifies a source set as proven.

The device is a Samsung Galaxy S20 FE (codename r8q), and LineageOS maintains it under that codename with a published branch, kernel tree and firmware precondition. Its build service also publishes, for every nightly, the exact manifest used to build it — every one of roughly 1,169 sub-projects pinned to a commit — which is the fastest honest way to obtain a genuine boot log for a known revision set before committing days to a from-source build. The flashing method itself was a discovery of its own kind: the LineageOS wiki's current instructions point to samloader-rs, a LineageOS-affiliated tool, rather than the Heimdall or Odin path the runbook had assumed, and it worked on the laptop with the vendor driver already present and no administrator elevation — removing a physical touchpoint the plan had budgeted for [ADR DEC-2026-09-06-02].

The wave's first real mistake followed almost immediately. A read-only probe of the device's partition table was issued with samloader's --no-reboot flag, on the reasoning that a read should leave the device alone. This device does not support a second Odin-protocol handshake inside the same download-mode session: the next command failed with an unexpected handshake response, adb had nothing to talk to, and the phone sat in Download mode, unusable by any tool on the laptop [state journal, seq 54–55, kind: device-hold]. The alert daemon — now running under its corrected ceiling from Chapter 2 — raised ALERT-0002 and, this time, stopped itself cleanly at forty sends on the proper ten-per-minute cadence rather than flooding [dispatch log, 40 records tagged ALERT-0002, 2026-09-06T10:59:15Z–11:03:53Z]. The device came back only when the owner physically held Volume Down and Power for about eight seconds; the runbook gained a line the same day saying never to issue --no-reboot on this device again, and print-pit — which reboots by design — became the standing read-only probe instead [seq 55–56].

The install itself, once the owner returned, ran as a short duet rather than a fully unattended operation. The agent flashed the recovery and vbmeta images, confirmed the device's stock fingerprint first, then pushed a signed 1.0 GB-class Lineage 23.2 nightly package over USB sideload; the owner formatted the data partition, rebooted, skipped the setup wizard, and re-enabled USB debugging — steps that need a hand on the glass and cannot be scripted around [state journal, seq 58–61]. Minutes later adb reported sys.boot_completed=1 against a Lineage 23.2 (2026-09-05 nightly) fingerprint with verified-boot state orange, and W1-01 passed on physical-device evidence: the first packet in the register accepted against something other than a host [seq 62; commit 5e0fa31; bundle 293c007e5254…, target device].

The next seven pushes to main all came back red. The install tool's serial-identification helper had shipped with a literal fallback device serial as its default value — meant only to save typing during the session — and the CI pipeline's own secrets scanner is written to catch exactly that shape of string in any tracked file. Once the pattern landed in a tracked file, every subsequent push failed the same STATIC gate regardless of what else that push changed, because the gate does not care what a commit is about; it fails the whole pipeline until the offending line is gone. Seven consecutive runs on main — spanning about an hour, from the W1-01 acceptance itself through unrelated story and job-reconciliation commits to a sync-ceiling change — came back failure before the fix landed: the serial is now read from an environment variable or a private, untracked state file, and the tool raises rather than falls back to anything printable if neither is set [CI runs 34030749492 through 34034071080, all failure; fix at commit 100eb23, run 34035090130, success]. Whatever number this chapter's brief expected here, the traceable count from the run history is seven, not three; it is recorded as measured, not adjusted to fit.

Meanwhile, on the external drive, the pinned manifest from the official build had begun a full repository sync inside the Linux build environment, launched from a Windows scheduled task so it does not depend on any agent's session staying alive [seq 57]. An interim 250 GB watchdog ceiling, raised by the executor without a ruling behind it, was explicitly withdrawn once the owner reviewed it [seq 69, 73]. The ruling that replaced it capped the checked-out tree (excluding the sync's own .repo metadata) at 90 GB and left the question of decimal or binary gigabytes open until it mattered [ADR RUL-2026-09-06-04]. It mattered immediately: the finished sync — 1,171 projects checked out, zero missing, zero mismatched against the pinned revisions [seq 78, inventory hash b5f1149ce58c…] — measured at 93,328,020,422 bytes, which is 93.33 GB by the decimal reading and 86.92 GiB by the binary one: over the cap one way, under it the other. The agent did not pick the reading that let it proceed; it held the build, kept a second sync running for reproducibility (which adds nothing, since every project was already at its pinned revision), and sent the owner a top-20-by-size report to rule on [seq 79]. The owner ruled the binary reading: 86.92 GiB is under a 90 GB cap read as GiB, and W1-03's detached build was started the same hour [ADR RUL-2026-09-06-07, seq 80–81].

Two more decisions landed the same afternoon. The product was named — ITISYOU OS, short form AIOS, applied to the site, the milestone files and the Telegram labels — with one loose end recorded honestly rather than quietly dropped: the owner referred to an updated AUTONOMY.md with a new hash that no copy on either drive actually carries yet, so the manifest refresh for that document stays held until the real file turns up [ADR RUL-2026-09-06-05; commit 8cf0572]. And because nothing in Wave 2 or beyond can be accepted until the Wave 1 device packets clear, the remaining budget went into preparation rather than idling: seven branches, each its own worktree, each forbidden from touching another's protected paths, drafting the flash-and-recovery runbook with a stock-firmware rollback path, a battery of offline device probes, the Wave 2 authority core (registrar, audit chain, epoch counter, key-handle table, ten add-only Law negatives), the evidence-tooling re-verification runner, a network-enforcement workbench, the L2.5 inference-runtime seam with its call meter, and an Agent City skeleton [seq 70–72, 75–76; branches prep/w1-04-runbook (4d4999b), prep/w1-probes, prep/w2-authority-core (b9303c2), prep/evidence-tooling (cdb01c0), prep/w2-a77-harness (3e0a3f5), prep/w25-inference-core (88d0ff3), prep/w4-agent-city (c577b3d)]. Every file out of these branches carries the same header: prepared, not accepted. Each will still be reviewed on its own evidence when its packet's turn comes.


References: git commits 5e0fa31, 100eb23, 8cf0572, 4d4999b, b9303c2, cdb01c0, 3e0a3f5, 88d0ff3, c577b3d; evidence bundle 293c007e5254… (W1-01, device target); GitHub Actions runs 34030749492–34034071080 (failure) and 34035090130 (success); state journal seq 54–83; dispatch log entries for ALERT-0002; ADRs RUL-2026-09-06-04, -05, -07, decision DEC-2026-09-06-02.

Chapter 4 — The build fights the disk, and the core fails review

6 September 2026, afternoon

Development journal — narrative, not evidence.

By mid-afternoon the day had split into three simultaneous problems: get a from-source build running at all, find out whether the Wave 2 security core being prepared in parallel was actually sound, and keep a shared external drive from choking every agent working on it at once. None of the three produced an accepted packet this chapter — everything below is PREPARED, held, or ruled, not PASS — and that distinction is itself part of the story.

The disk-cap question from the sync (Chapter 3) reached its owner exactly once more before it was settled for good. The checked-out tree, excluding the sync's own metadata, measured 93,328,020,422 bytes: 93.33 GB by the decimal reading, 86.92 GiB by the binary one, against a 90 GB cap that did not yet say which GB it meant. The build stayed held rather than start on a convenient reading [state journal seq 78–79]. The owner ruled binary: 86.92 GiB is under a 90 GB cap read as GiB, and raised the parallel-agent ceiling to eight in the same ruling [ADR RUL-2026-09-06-07; seq 81].

The detached build itself needed three attempts to leave the gate. The launcher calls into the tree's own envsetup.sh, and the first two launches exited immediately: the script reads an environment variable the launcher's strict shell mode (set -u) treats as fatal when unset, and it is unset until envsetup.sh itself sets it. The fix was to relax strict mode around that one call rather than around the whole script, and the third launch is the one that actually started compiling [state journal seq 90]. It has not finished; as of this chapter it is still building the host-side Go toolchain the rest of Android's build system depends on, not Android itself [build log checkpoints].

That third launch shared the same physical drive with a second full repository sync, running again purely to prove the first sync was reproducible. It never got to prove it. The second sync reached its "finalizing" stage and then stalled behind three concurrent directory-size scans competing for the same disk; before its receipt could be written, the WSL virtual machine was restarted to apply a memory-configuration ruling, and the restart ended the sync mid-flight. The reproducibility test this was meant to satisfy is still open, deferred until after the build finishes so the tree is not touched twice at once [state journal seq 91].

The contention showed up directly in the build's own checkpoints. For six checks in a row, roughly every five minutes between 15:03 and 15:39, the build's output directory barely grew — from about 104.0 to 104.02 megabytes — while system load sat near 24 to 25 on a twelve-processor host; one checkpoint a few minutes later recorded a load of just over 102. Eight parallel Rust builds from the Wave 2 preparation agents were writing to the same HDD the AOSP build was reading from, and none of them were winning [build log checkpoints]. The owner's fix was structural rather than a temporary throttle: Rust build output no longer touches the shared drive at all. Compilation output for every Wave 2 preparation branch moves to a dedicated location on the host's other drive, run at reduced process priority, with the agent ceiling cut to three until that redirection exists and restored to eight once it does — and the AOSP build keeps I/O priority throughout [ADR RUL-2026-09-06-14]. The next two checkpoints show the difference: output jumped from about 150 megabytes to 1.26 gigabytes between 15:49 and 16:01, and load eased to the high teens [build log checkpoints].

The same afternoon, a dedicated review branch (prep/w2-review, commit 62e08ba) was pointed at everything the Wave 2 authority-core preparation had produced, and it did not pass. Four blockers, fifteen major findings, ten minor and seven notes — and, more pointedly, three mutations deliberately planted in the code (a free-text trait parameter, a rank-based authorisation branch, an inverted admin-tier fold) all survived the project's own protected Law test suite untouched. The protection boundary and the actual coverage boundary are not the same thing yet. Seven of the branch's own candidate decisions were marked disputed rather than accepted on the reviewer's say-so [ADR w2-review entry; seq 95]. The response was dispatched inside the hour rather than left for later: the key-handle blocker went to its own branch and was closed the same afternoon — private fields, no Copy/Clone, a sealed constructor, four compile-failure proofs that the old bypasses no longer compile [commit 3792375] — and one of the two Tier-3 authorisation blockers landed on the token-format branch alongside it [commit 39d5b1b]. The policy-encoding fix and two more of the l2 blockers were still queued, not landed, as this chapter was written.

Two loose ends from earlier chapters closed. The owner's promised updated AUTONOMY.md, held since the naming ruling, never actually arrived — the only change in it had been the naming decision itself, already applied by message — so the file's hash stays exactly what it was and the hold was simply released rather than chased further [ADR RUL-2026-09-06-12]. And the network-enforcement branch's open question — whether a hybrid of eBPF identity matching and iptables destination rules counts as an acceptable "selected mechanism" — was ruled yes, under three conditions, and filed as a formal decision; the owner's own requested number for it collided with a number the Plan had already reserved for something else, so the conflict was written down rather than silently resolved [ADR RUL-2026-09-06-13, docs/adr/ADR-IMP-010-network-enforcement-mechanism.md].

Underneath all of it, a migration plan waits on hardware that has not arrived yet. A drive is due the next day, and the instruction was to prepare, not to wait: a dry-run-only tool now exists that can export the whole build environment, move it, verify document and evidence hashes before and after, and re-point every path that depends on the old location — with the old drive's copy renamed rather than deleted, so a failed migration is recoverable [ADR RUL-2026-09-06-10; prep/ssd-migration]. It stays unexecuted by rule until the owner confirms the drive is physically connected.


References: state journal seq 78–101; git commits 3792375, 39d5b1b, 62e08ba; build log checkpoints (2026-09-06, 15:03–16:06); ADRs RUL-2026-09-06-07, -10, -12, -13, -14; docs/adr/ADR-IMP-010-network-enforcement-mechanism.md.

Chapter 5 — Two more reviews, and a long night for the build

6 September 2026, evening — 7 September 2026, early hours

Development journal — narrative, not evidence.

The first adversarial review of the Wave 2 core (Chapter 4) closed its four blockers as code within the hour. A second, independent pass did not accept the fix. Rerunning the project's baseline confirmed the integration report's own number — 677 passed, 2 failed — then replanted the original three mutations alongside four new ones and ran all seven against the protected tests/law/** suite. Two were killed by name-shaped assertions a rename would have slipped past; five survived, three of them outright: a Tier-3 confirmation that skips its epoch re-check, a remote command that closes an already-open intent it should never touch, and a metering failure that should count against the session's call cap but does not. More pointedly, two of the project's own law registry cases turned out to be dark — the scanner backing them panics on the first offending item rather than reporting every one, so a red case had quietly stopped being a gate for anything past its first hit [docs/design/review-w2-core-2.md; commit 58de8be; ADR "Re-review at 2a7dac9"; state journal seq 124].

The fixes went out fast, to named branches, each closing one finding rather than the review as a whole: the policy epoch is now compared against the state epoch before any grant lookup; the Registrar's identity and caller-state constructors take a complete, pinned argument list instead of trusting field order; the chain hasher gained a self-test with known-answer vectors; the two dark registry cases now report every offender in one pass instead of stopping at the first [commits 11da139, 6a51650, 3e9c30b, b5e3945 on prep/l2-fix2; prep/ident-sites; prep/law-fix2 commit 32cd778; state journal seq 128, 133–135]. A third, independent review confirmed the fix: all seven mutations from the second review are now killed by protected cases. It also found four new ones, and every one survived — the new pins guard the declaration a value arrives in, not the logic underneath it, so a hasher stays honest only on the constant it was tested with, a constructor's body can still swap two arguments behind a correctly pinned field list, and an identifier grammar enforced in one crate is invisible to a law case that never reads that crate [docs/design/review-w2-core-3.md; commit 020ec4f; ADR "Review round 3 at f4fb966"; state journal seq 137].

The owner ruled on the open questions from both reviews in one sitting that evening. Constructors across the authority core take a parsed identifier type, never a raw string, closing the free-text hole for good rather than exempting it by directory; the two competing metering interfaces collapse to one wire, declared once under the L2 side because L2 owns every trusted interface; a hand-picked list of exactly three constructors is allowed to take a real string at all, with every other diagnostic label moved into an ordinary table outside law's reach; and a trailer granting an exception to the protected-test rule was issued for exactly one named commit, not as a standing permission [ADR RUL-2026-09-06-15; state journal seq 125]. The trailer's own machinery got a second look the next morning: the gate that checks for an OWNER-REVIEWED trailer now also checks that its exact wording is recorded in a protected grants ledger, closing the possibility of an agent writing its own approval and the gate believing it [ADR RUL-2026-09-07-17; docs/adr/ADR-IMP-011-protected-path-approval.md; state journal seq 142]. The chain-hash question — what actually seals the audit log — was answered the same morning: SHA-256 with standard known-answer vectors, unverified until a later packet proves it against the real toolchain, written that night but left ungated when the build's own troubles cut the session short [ADR RUL-2026-09-07-17; docs/adr/ADR-IMP-012-chain-hash.md; prep/fix3 commit 37b85da]. A disagreement between the Plan's own numbering and the numbers the owner asked for kept recurring rather than being quietly resolved either way: the governance, chain-hash, Drive-backup and host-priority ADRs were each requested under a number the Plan table had already reserved for something else, and each was filed one number further along with the collision written into the record instead of silently taking the owner's number or silently renumbering without saying so [docs/adr/ADR-IMP-011 through -014].

Underneath all of this, the detached build was fighting the host for memory. Its analysis phase — a single process -j cannot split — outgrew the 17 GB WSL ceiling and spent roughly four and a half hours thrashing against swap on the same drive it was trying to read, alive but making no visible progress; the fix was to raise the ceiling to 19 GB for analysis only, restoring 17 GB once real compilation began [state journal seq 109, 126; ADR RUL-2026-09-06-15 item 5]. The second attempt started clean and outgrew 19 GB within twelve minutes, swapping again — the analysis is one process, so more memory only postpones the same wall [state journal seq 127, 129]. The overnight plan was to let it keep swapping until the next day's SSD moved the whole environment off the contended drive, with cargo builds isolated to the other drive at low priority meanwhile, since the sturdier fix — a dedicated virtual disk — needed permissions the session did not have [ADR RUL-2026-09-06-16; state journal seq 132]. That plan did not run its course: an owner override after midnight demanded an immediate yield regardless of what the build was doing, and the daemon obeyed literally — the second attempt was killed about four hours into analysis, the WSL ceiling was cut to 12 GB and held there, and the lost work was accepted as the cost of answering promptly [ADR RUL-2026-09-07-20; state journal seq 143, 145].

The alert daemon itself became a casualty of the same pressure, twice: the host's own low-memory guard killed it once in the evening and again a couple of hours later while WSL held 17 to 19 GB — the ceiling-protected code was unaffected each time, only the process running it was gone. It now runs as a Windows scheduled task outside the session's own task system, so neither a session ending nor the next memory sweep can take it down with it [state journal seq 123, 131]. A planned nightly backup to Google Drive could not run the same night: neither the sync client nor its command-line tool was present on the host, so the mirror stayed a rehearsed, tested plan rather than a real one, held for the owner to install the missing piece [ADR RUL-2026-09-07-18; docs/adr/ADR-IMP-013-drive-backup-mirror.md; state journal seq 139, 141]. When an instruction to skip that night's run arrived secondhand rather than directly from the owner, the branch preparing the backup tool treated it as an unverifiable claim and declined to act on its own authority; the executor applied the skip itself, directly, because it held the owner's actual instruction [state journal seq 144]. And a new pacing rule arrived for a resource the session cannot see the meter of: usage is to be spread across the week rather than spent in one sitting, but no tool inside the session can read the counters it is meant to pace against, so the conservative reading is applied by hand — a smaller model roster and a lower concurrency ceiling — until the owner supplies the real numbers [ADR RUL-2026-09-07-21; state journal seq 147].


References: state journal seq 109, 123–147; commits 11da139, 6a51650, 3e9c30b, b5e3945, 32cd778, 020ec4f, 58de8be, 37b85da; docs/design/review-w2-core-2.md, docs/design/review-w2-core-3.md; ADRs RUL-2026-09-06-15, -16, RUL-2026-09-07-17, -18, -20, -21; docs/adr/ADR-IMP-011 through ADR-IMP-014.

Chapter 6 — The SSD, the vanishing builds, and a clean review

7 September 2026

Development journal — narrative, not evidence.

The SSD arrived, and the first alarm of the day had nothing to do with it directly. A parcel-tracking watcher read a courier's "will be delivered today, between two hours" as the literal word "delivered" and raised its alert; the daemon burst forty messages before the same ceiling from the first flood (Chapter 2) stopped it on schedule. The fix was to classify the literal past tense before anything else and treat a time slot as exactly that — a slot, not an arrival — checked against nine real courier messages before the watcher restarted [INC-0002]. A second, unrelated incident that morning found every scheduled task set to refuse to start on battery power, silently queuing a restart until it was noticed [INC-0003].

Once the drive was actually connected, the migration itself was unremarkable in the best way: twenty-four minutes to copy the build environment across, hashes of the checked-out documents and evidence verified equal before and after, the old drive's copy kept rather than deleted [state journal seq 200]. What followed it was not unremarkable. Three build launches in a row simply vanished — no error, no crash record, just gone within a minute or two of starting. The cause took until early afternoon to pin down: the guest environment shuts itself down roughly a minute after the last remote session touching it closes, and a build launched and then left alone counts as closed. One earlier attempt had only survived because a log-watching session happened to be left open the whole time by accident. The fix keeps a session open deliberately for as long as the build runs [INC-0004]. Fixing it exposed a second problem immediately: an automated cap manager mistook the vanished build for a normal finish and raised the memory ceiling on the strength of that false reading; it was disarmed and the ceiling put back [INC-0005].

With the build actually staying up, it hit a real wall instead of a phantom one. The compiler's own build-planning step needs far more memory than expected on this tree, and it was killed by the guest's own out-of-memory protection while writing its plan file, asking for close to double the memory and swap it had been given. The response was to let the drive carry a much larger swap file — forty-eight gigabytes instead of sixteen — and to tell the compiler's own garbage collector to work harder for less memory rather than simply throwing more RAM at a hunger that had already proven it would keep growing [adjustment log, 2026-09-07 ~12:55Z].

Underneath that, the memory ceiling itself was tuned by hand most of the day against a desktop that was not free to give it everything: a browser and an editor running on the same machine were quietly worth several gigabytes on their own, and the ceiling that left the build enough room without starving the host kept moving — twenty, then eighteen, then further down still. One automated tool made this worse before it made it better: an older version of the memory daemon kept restoring the ceiling to a value from an earlier rule that no longer matched what the day's cap actually was, and the two disagreed with each other on every cycle, restarting the build each time. It was put on hold by hand until a corrected version could replace it [adjustment log, 2026-09-07 14:48Z–15:28Z].

The Wave 2 core kept being reviewed and kept being fixed in the same rhythm as the day before. A fourth review found three new blockers, all the same shape as before — a check that pins how a value is declared without pinning what it actually does — and a fix cycle closed them behaviourally, with named test cases rather than declarations, before the next merge [ADR "Review round 4 at eb00170"]. A sixth and seventh merge of every finished branch both came back green on every technical gate; the fifth review that followed found no blockers left at all, only three fixable majors, and rated the reviewed state fit to freeze as the project's baseline going forward [ADR "Review round 5"; commit fdcd8e9]. A fifth, smaller fix cycle closed those in turn, and a sixth review began the same evening, scoped only to confirming the closure [ADR "Fix cycle 5"].

Two rules changed how the day itself was run. Ordinary decisions — naming, style, ordering — stop being asked about at all and get decided and logged under the existing conservative rule instead; genuine questions for the owner are saved up and sent twice a day rather than one at a time, except for anything that stops the whole line [ADR RUL-2026-09-07-24]. And while the owner was away, a standing set of permissions took over rather than leaving everything waiting: the new drive's full space, a memory ceiling chosen by a fixed formula rather than asked about each time, and a plain priority order — the build first, then the next device packets, then everything else [ADR RUL-2026-09-07-26].


References: incidents INC-0002–0005; state journal seq 187, 195, 198–219; ADR rulings RUL-2026-09-07-22 through -28; commit fdcd8e9.

Chapter 7 — The build finishes, and the phone comes alive

8 September 2026

Development journal — narrative, not evidence.

Overnight the compiler ran at a higher parallelism than before, and the memory ceiling that governs it stopped moving on its own. An automatic tuner kept recommending a new number every few minutes — thirteen gigabytes one moment, sixteen the next — chasing a desktop that was never going to sit still: a browser and an editor running alongside the build were worth several gigabytes on their own, so the "correct" ceiling shifted with whatever else happened to be open. Rather than let the tuner win that argument all night, two specific, dated rulings — raise parallelism, hold the ceiling — were left in force over the tuner's general one, with the conflict logged rather than quietly resolved either way [ADR RUL-2026-09-07-30 items 7–8; state journal seq 270–302].

The build finished at 02:41Z: exit code zero, a signed flashable package built, thirteen hours forty-five minutes from launch to end, a hundred and twenty-six gigabytes of build output sitting on the new drive [state journal seq 305]. Sealing it surfaced its own small honesty problem: the build's own completion receipt had a counting bug in it — one figure duplicated — found only after the attempt had already been sealed. The fix went into the tooling, but the flawed receipt was not quietly rewritten in place; a later packet's bundle had the identical shape of problem (an enumeration that did not verbatim match what was required) and was handled the same way — the wrong bundle stays in the record with a correction entry pointing to a validated replacement, rather than disappearing [ADR "W1-03 PASS" section; state journal seq 350].

A flashing runbook for the device was finished against the real build artefacts and rehearsed as a dry run — every step simulated, nothing written to a phone — before anyone went near the hardware [ADR "W1-03 PASS, W1-04 PASS" section].

A second Telegram channel was added the same morning for the owner to reach the project from, and verifying it turned out to be harder than sending to it: the automation system that already reads that bot's messages consumes them before anything else can, so a shared secret phrase sent to the new account could not simply be read back out of its inbox to confirm the match. The owner supplied the account's own numeric identifier directly in a terminal instead, a labelled message carrying a four-word verification phrase was sent to it, and the owner confirmed the phrase's contents back in the terminal — proof that did not depend on trusting the channel it was verifying [ADR RUL-2026-09-08-31].

Then the owner sat down at the phone itself. No unlock screen was needed — the device already ran an unlocked custom build from Chapter 3 — so the path was a sideload straight into recovery: the expected "signature verification failed" warning appeared and was accepted on screen, the install reported success, the data partition was wiped to change the phone's signing identity over, and it rebooted. Minutes later it was running the project's own build, not somebody else's, for the first time [ADR "W1-05 PASS" section].

The device checks that followed were read-only and mostly clean. The first hardware pass failed exactly one row — touch — and only because the ordinary shell it ran under is not allowed to read the raw input device files; switching that one check to ask the system's own diagnostic service for the same answer turned every row green on the second attempt [ADR "W1-06 PASS" section]. A chain of further probes then walked the device from several directions at once: the actual network-filtering mechanism was traced in the shipped source itself, matching what the security-core work had already assumed rather than merely hoping; the secure hardware exposed a dedicated high-security key store; exactly one network listener was found at all, and it was flagged for blocking under the project's own default rules; and the audio system does expose a path for capturing a live phone call, which settles a previously open question about what a later privacy feature can promise on this hardware [ADR "W1-07, W1-08, W1-10, W1-11, W1-12, W1-13 PASS" section].

Four small test applications were built by hand with the Android developer tools and installed to prove the device would run the project's own signed software at all — a deliberately low bar, cleared. One thing stayed unresolved rather than forced: the phone's second SIM slot is not registered with a network, which blocks only the one probe that needs an active call and nothing else, and it waits for the owner rather than for a workaround [ADR "W1-07 PASS" section; "W1-06 PASS" section].


References: ADR RUL-2026-09-07-30, RUL-2026-09-08-31; ADR-QUEUE "W1-03" through "W1-13" sections (2026-09-08); state journal seq 270–350.

Chapter 8 — M1, signed with conditions

8 September 2026

Development journal — narrative, not evidence.

Milestone M1 sealed the same day the phone first booted the project's own build: twenty-eight packets, every dependency bundle passing, gate bundle 1fbd9d7a. It did not seal on the first attempt at the one packet that mattered most.

The device's outbound-traffic inventory went through two owner reviews before it was accepted. The first sent back holds, not an approval: a proposed captive-portal host was rejected as invented rather than proposed with its implications; two system services stayed denied pending an explanation; WebView's security-update path needed its own explanation, separate from everything else; and eight proposed allow-rows were refused as a group, each needing its own destination, protocol and evidence, observed traffic kept distinct from what the source merely implied [ADR RUL-2026-09-08-32]. The rerun used a live connection rather than a simulated one and came back thinner: two allowed principals, thirty-six denied. A second review accepted the mechanism behind it — enforcement by an app's shared identity rather than the individual app — but not as a blanket permission: every package let in under a shared identity still needed its own written justification, or the gap became a named finding rather than a quiet exception [ADR RUL-2026-09-08-34].

One question ran ahead of either review: whether the phone should be able to call at all. The owner's answer drew a careful line — modern calling matters and should be supported where the device and network allow it, but that is a requirement later work must satisfy and prove, not a claim to make now, and not permission to reach further than the inventory already justified. Everything wanted beyond the frozen plan's scope went into a register for later review instead of being quietly added [ADR RUL-2026-09-08-36].

With that, the inventory sealed as what it was — a record of what the device does, not proof of what blocks it — and the milestone's own signature carried the same restraint: accepted for a baseline build, boot and inventory only, with a validation check attached rather than taken on trust [state journal seq 365]. Three things stayed open by name rather than waived along with the rest: the shared-identity isolation gap, a Bluetooth-facing listener still waiting to be blocked, and every calling and carrier test only a working SIM can settle [state journal seq 365].


References: ADR RUL-2026-09-08-32, -34, -36; docs/milestones/M1-decision-review.md; state journal seq 353–366.

Chapter 9 — A daemon with its own name, and a drive that ran thin

8 September 2026, evening

Development journal — narrative, not evidence.

The first Wave 2 packet to touch the phone directly is a harness meant to prove that three different kinds of software — an ordinary app, an agent-controlled one, and something running with the system's own authority — get treated differently by the device, not just by policy documents. Two of the three ran cleanly the first time: fresh, disposable identities were installed, driven, and their results matched exactly what was expected. The third could not run at all, because nothing on the phone actually spoke with the system's own voice yet — the build had never needed one before [ADR "W2-01 attempt 1 BLOCKED-DEVICE"].

The obvious shortcut was rejected on sight. Borrowing the platform's own system identity for the harness would have worked, but it would have quietly recreated the exact shared-identity gap that Milestone M1 had just been signed with open — the harness would have been testing a shortcut instead of the thing it exists to catch [ADR "W2-01 attempt 1"]. The alternative was slower and more honest: build a small daemon of its own, with its own name and its own reserved identity number, living under its own security policy rather than anyone else's [ADR "W2-01 task 6"].

That daemon compiled cleanly, installed its startup entry and its identity mapping without incident, and then failed — not on anything it had written itself, but on two lines of the security policy that name what the new identity is never allowed to do. The platform's own baseline policy turned out to already grant every process on the device a broad permission that the new domain's own rule flatly forbids, so the two could never both be satisfied at once. Roughly three and a half hours of build time went into reaching that single, precise contradiction, which is now fixed by removing exactly the grant that conflicted and nothing else the domain still forbids [ADR "W2-01 task 6"].

While that build ran, the same host that has been fighting for memory all week found a second, quieter constraint. The machine's system drive is small on purpose, kept clear for the operating system rather than project data — and while the guest environment worked its way through the compiler's memory-hungry planning phase, the paging file backing that memory grew to more than twenty gigabytes on the very drive meant to stay untouched. The free space on it slid under a line the owner had set without anyone changing a setting that would explain why [state journal seq 373].

The owner caught it and answered twice within the hour, and the two answers pulled in different directions on purpose. The first was a full stop: treat the current free space as already below the line, touch nothing that could make it worse — no deleting files, no changing how memory is paged — while the running build finished on its own, and start nothing new until the drive had real room again [ADR RUL-2026-09-08-37]. Less than an hour later, having looked again, the owner lowered the line itself rather than waiting on it, and told the work to continue: the free space that had been a violation minutes earlier was now comfortably above the new one [ADR RUL-2026-09-08-38].

One of the reasons that drive had been short in the first place was a small machine of its own making things worse. The daemon that manages the memory ceiling had a rule from days earlier still built into it — restore to seventeen gigabytes once a certain kind of pause ends — and it followed that rule literally even though the day's actual standing limit was fourteen. The build launched at the daemon's old number rather than the current one, with less than a gigabyte of the host's own memory left to spare, before anyone caught the mismatch [ADR "W2-01 task 6"; state journal seq 371]. The fix on record is not a one-off correction but a change to what the daemon reads: the number it restores to should come from wherever the current ruling actually lives, not from a value written into its own code once and never revisited.

The owner's second ruling that evening reached further than the drive. Alongside lowering the reserve, it reset which models do the day's work at all: the cheaper, faster ones by default for everything, the more expensive ones kept back for security-critical code or genuinely hard problems, and the most capable reserved strictly for milestone decisions and the findings serious enough to need them [ADR RUL-2026-09-08-38]. Nothing about the standards changed — only what gets asked to meet them, and when.


References: ADR "W2-01 attempt 1 BLOCKED-DEVICE", "W2-01 task 6"; ADR RUL-2026-09-08-37, -38; state journal seq 365–380 (INC-0008 at seq 371).

Chapter 10 — Proof over assurance, and policy that would not bend

9 September 2026

Development journal — narrative, not evidence.

The daemon that had failed the evening before on two lines of platform policy was rebuilt overnight with the one conflicting grant removed, and in the morning the owner flashed it onto the phone. It booted on the first try, the new build identifiable by its own fingerprint, and with it came the system-voiced component the harness had been missing. There was one oddity: the ordinary shell on the phone could not so much as read the file's attributes — every ls of it returned a flat refusal. That refusal was not a failure. It was the tight security policy working exactly as designed, and the device itself proved the file was present and correctly labelled by recording, in its own audit log, precisely what it had denied the shell and why [state journal seq 389].

What happened next is worth keeping. The task driving the harness had been told, by a message that presented itself as coming from the coordinating session, to treat the gate as already satisfied and to read the shell's refusal as proof of presence. It declined. A message is not evidence, and the task went and checked the device for itself — the kernel's own denial record, a new build fingerprint, and a single driven run in which the daemon executed under its reserved identity and answered on the same channel the two app-level probes use. Only once its own reads agreed did it proceed [state journal seq 389]. The same reflex had appeared a turn earlier against a different relayed assurance that did not hold up; the habit of trusting nothing that cannot be re-derived is the point, not the exception.

With all three kinds of software now provable on the device — an ordinary app, an agent-controlled one, and the system-voiced daemon — the harness packet passed. Each reached its reference destination and its results matched; the only finding was the expected one, that the device still has no default-deny of its own to enforce, which is the work the next packets exist to build rather than a fault in this one [state journal seq 393].

The day's progress was shadowed by two faults the project had inflicted on itself. The first was quiet and serious: the three small daemons that watch memory, send alerts, and raise emergencies had all died when the session process exited the night before, and nobody noticed for about three hours. For that window the project had no way to escalate an emergency to the owner at all. They were found and restarted, and the gap was written down as what it was rather than smoothed over [state journal INC-0010].

The second fault was subtler and, in a system built on a tamper-evident record, the more alarming. The journal of everything that happens is a hash chain: each entry seals the one before it, so the whole history can be checked and nothing can be quietly altered. But two of the daemons had been writing their own entries into a second, stale copy of the repository while every deliberate entry was being committed from a clean one — and the two had forked. There were now two incompatible continuations of the same sealed history. The temptation in such a moment is to pick one and move on, or to stitch the two together; either would have falsified the chain. Instead the six diverged entries were preserved, exactly as written, in a file of their own, the committed chain was left untouched as the authoritative one, and the daemons were pointed at the correct copy so it could not happen again [state journal INC-0011]. The fork was the kind of thing the hash chain exists to make visible, and it worked.

Then the work turned to teaching the device to say no. The plan had been to enforce a default-deny two ways at once — a fast in-kernel filter keyed on identity, and a rule-based firewall keyed on destination. Reading the platform's own security policy closed that off before a single line was written: a new component simply cannot be granted the right to write the kernel's network maps — one line of the platform baseline reserves that to a fixed handful of system processes, and weakening the baseline to make room was never on the table [state journal seq 395]. The honest answer was the narrower one. The rule-based firewall alone can carry the whole job, because the tool that installs those rules is an ordinary system binary the new daemon is allowed to run, and a chain it fully owns can refuse by default and permit only named destinations — never widen what the system already allows [state journal seq 396]. The sanctioned in-kernel route was examined and set aside for a concrete reason: the chains it offers are permissive by default and carry no notion of a destination, so they could not express the rule at all.

One design choice in that firewall is worth stating because it contradicts an earlier sketch. An earlier note had asked for a blanket acceptance of already-established connections in the outbound chain. That was dropped deliberately: it would let a principal whose permission has just been withdrawn keep using the connections it already had open, which is the exact thing the revocation path exists to stop. Replies to permitted traffic are still accepted where they belong; nothing an honest flow needs is lost [state journal seq 396]. The question was recorded for the owner rather than settled by fiat, along with the one genuinely physical prerequisite — the first live change to the phone's firewall waits for the owner to be watching, and for a developer setting that the build keeps off by default to be switched on [state owner batch 2026-09-09].

Because that enforcement work now waits on the owner, a second track opened in parallel, one that depends on nothing but the baseline already proven: the skeleton of the project's own privileged services. Two of them were written — one that will eventually register capabilities, one that will read the tamper-evident audit log — each with its own name, its own reserved identity, its own security domain, and, by explicit rule, no network privilege whatsoever. They speak only through typed, checked interfaces with no free-text way in, and they refuse any caller not on a fixed roster [state journal seq 400]. They built, and then the build failed — on a contradiction of the same family as the day before. The interface contracts had been written as stable, frozen-ABI types, the kind meant to outlast many versions, but the module that compiles them had been declared the opposite. The fix keeps the stable contract rather than quietly downgrading it to make the error go away; the contracts are meant to be stable, so the build is being taught to treat them that way [state journal seq 405].

Twice in two days the project has walked into a wall made of platform policy, and twice the resolution has been the same: find the narrower honest path, or keep the stronger guarantee and do the harder work, rather than file down the thing that said no. That is slower. It is also the whole point of the exercise.


References: state journal seq 389 (W2-01 reflash and on-device verification), seq 393 (W2-01 PASS), INC-0010 (daemon outage), INC-0011 (journal-chain fork preserved), seq 395–396 (W2-02 policy refusal and the iptables-only resolution), seq 400 (W2-07 plan), seq 405 (W2-07 build failure on interface stability); owner batch 2026-09-09 08:00.

Chapter 11 — What a stable contract costs, and a reserve that came due

9 September 2026, afternoon

Development journal — narrative, not evidence.

The owner's answers to the morning's questions arrived together, and one of them reversed a decision from the night before. The system drive's safety margin, lowered to twenty gigabytes the previous evening so work could continue, was put back to thirty. The rule for such collisions is already written down: when a newer instruction contradicts an older one, the newer wins and the conflict is logged rather than raised as a question [ADR RUL-2026-09-09-39]. So the margin became thirty again, with a standing note that the drive was to be left alone — no clearing of caches, no touching the paging file. The other answers drew the hardest possible line around the phone: the network-enforcement packet could have its code and its rebuild, but nothing would be written to the device, and no developer switch would be flipped, until the owner was physically present and said, in so many words, that the session was starting. Not "present." The words [ADR RUL-2026-09-09-41].

Meanwhile the other track — the skeleton of the project's own privileged services — went back to the build, and failed, and failed again, each failure teaching the next. The first failure was a contradiction between two halves of the same intent: the service contracts had been written as stable, long-lived interfaces, but the module that compiles them had been declared the opposite. Keeping the stable contract, rather than quietly downgrading it to make the error disappear, meant making the module stable to match [state journal seq 405]. That fix worked — and revealed the next requirement. A stable contract, it turns out, has a price: the build demands a recorded snapshot of its shape, a frozen record of exactly what the interface looks like today, so that any future change to it is visible as a change. There was no such snapshot, because the interface had never been built as stable before [state journal seq 413].

That snapshot could be generated two ways. The heavy way was to ask the build system to do it, which would have dragged in the same three-hour, memory-starving analysis the full build runs. The light way was to call the interface-description tool directly, by hand, with exactly the arguments the build system would have used — read out of the build's own generated rules rather than guessed — and commit the result. The light way was taken, the snapshot produced and checked against a real example in the platform's own source to be sure its shape was right [state journal seq 413]. The rebuild it unblocks, though, could not start — because of the margin the owner had just restored that morning.

This was the tension made concrete, and it was worth being honest about rather than working around. The build, to run, needed the drive above thirty gigabytes. The drive sat at twenty-five. The single biggest reclaimable thing on it was the Windows paging file, nineteen gigabytes reserved but only three in use — and that was exactly what the owner had said not to touch. The next biggest was a folder of Windows diagnostic logs. Every lever that would free space was something the owner had just restricted. Rather than pick one and proceed, the situation was put to the owner as a decision only they could make, with the options laid out and a recommendation, and the work stopped there [state journal seq 414].

The owner's answer was precise, and it is worth quoting the shape of it: clear only the confirmed Windows diagnostic folder — not project data, not the rest of the temporary files, not the paging file, not anything belonging to the build — record its exact location and size first, then recheck, and proceed only if the drive genuinely cleared thirty gigabytes; if it did not, stop and report, and do not use the one-time exception that had been offered. The folder turned out to hold fifteen and a half gigabytes of trace logs from the Windows Remote Desktop client — the very channel the owner uses to reach this machine — and nothing of the project at all. It was removed, and only it; the drive went from twenty-five gigabytes free to forty [state journal seq 415].

With the margin restored and the interface snapshot committed, the skeleton's build started for the third time, now carrying fixes for both of the failures that came before it [state journal seq 416]. As this is written it is still running, deep in the same slow analysis phase that leaves the host starved of memory — an accepted condition, not an emergency, and one the project is explicitly forbidden from relieving by the one lever that would work, since changing the memory ceiling mid-build is itself against the rules.

Two things recur across the afternoon and are worth naming. The first is that a stable contract is not free: declaring an interface stable commits the project to recording and defending its shape, and the build enforces that commitment one requirement at a time. The second is that a safety margin, once set, can quietly come due at the worst moment — and when it did, the answer was not to route around the owner's rule but to surface the collision and let the owner spend a precise, minimal amount of what they had reserved. The drive is clear, the contract is stable, and nothing on the phone has moved.


References: ADR RUL-2026-09-09-39, -40, -41 (the morning's batch answers); state journal seq 405 (build-1 stability failure), seq 413 (build-2 API-snapshot failure and the light-path fix), seq 414 (the storage block raised to the owner), seq 415 (the owner-approved diagnostic-folder deletion), seq 416 (build 3, in progress).