rules_sha must be recomputed, not recalled
TASK-IMP-122: rules_sha must be recomputed, not recalled
Summary
CyberOS already ships a rule-content fingerprint. rules_sha (TASK-IMP-074) is computed at build time over the payload and written into manifest.yaml. Three components compare it against an installed machine, and every one of them answers the installed side by grepping the stored token out of .cyberos/manifest.yaml rather than by re-hashing the installed files. Two tokens from one build always agree, whatever happens to those files afterward. So the check answers "did these manifests come from the same build?" and is read as "do these bytes still match?".
Problem
Measured on this repo at HEAD, 2026-07-18. Every number below was re-measured by this author.
Defect 1 - the fingerprint is recalled, not recomputed. build.sh:354 computes rules_sha over the assembled output. install.sh:188 vendors the manifest containing it. Then:
| component | what it does |
|---|---|
version.sh:59-63, :89-93 | _rs() greps ^rules_sha: from each manifest; verdict="rules_drift" on mismatch |
lib/update-check.sh:8-14, :82-97 | _cyberos_rules_sha() greps a manifest; :101-105 emits RULE DRIFT ... (same version, different rules) |
audit-fleet.sh:13, :36-37 | _rs() greps $cy/manifest.yaml; compares each fleet repo's token to an expected one |
grep -nE 'shasum|sha256sum' across all three returns empty. Nothing recomputes. (check-version-sync.sh reads rules_sha too, at :56, but only asserts it is 64-hex (:57-58); it is not a drift comparator and is out of scope: grep -c '\.cyberos' on it returns 0 - it compares payload stamps to the root VERSION and has no installed side at all.) update-check.sh:76 states the correct thesis - "VERSION is a promise; rules_sha is the evidence" - and then greps a token that is a promise for exactly the same reason VERSION is: it was written once, at build, by the thing being checked.
The sharpest form of this is measurable today. Run as bash .cyberos/version.sh, $here resolves to $CY, so :64 reads $root/.cyberos/manifest.yaml and :65 reads $here/manifest.yaml - the same file. :66-68 cannot rescue it, because CYBEROS_PAYLOAD is consulted only when $here/manifest.yaml yields nothing, and it always yields something on an installed machine. So :89's [ "$inst_sha" != "$pay_sha" ] is unreachable: that invocation compares a file to itself and can never report rules_drift. Verified by running it - both sides print 66bb0459..., verdict=up_to_date.
The consequence is not theoretical. On 2026-07-18 this repo's own .cyberos differed from dist/ in six vendored artefacts while VERSION read 1.0.0 and rules_sha matched on both sides. The installed batch-select.mjs was the pre-PR#53 build carrying the undeclared-cone bug, and returned a different batch than source. Every check reported current.
Defect 2 - the cone is the wrong set. build.sh:354 hashes find cuo plugin mcp cli memory. Measured against the installed tree:
cone today (build.sh:354) : cuo plugin mcp cli memory
vendored set (install.sh) : cuo plugin mcp memory docs-tools lib + 6 root scripts
in cone, NEVER installed : cli -> guarantees false drift
installed, NOT in cone : docs-tools lib -> the blind spot (4 of the 6 measured drifts)
never in cone at all : the 6 root scripts (:190-195)
Four of the six artefacts that actually drifted (batch-select.mjs, render-status-hub.mjs, verify-goals.mjs, workflow-improve.mjs) live in docs-tools/. So even a recomputing check would miss them. And cli/ is in the cone and is never installed, so a recomputing check with today's cone would report drift on a perfect install. The two defects are independent and both must close, or the fix either misses the evidence that motivated it or cries wolf on every machine.
Why REPAIR and not a second mechanism. TASK-IMP-104 §1.2 forbids install carrying a second implementation, and 104 explicitly rejected content hashing for ITS question: "Compare a manifest hash rather than a version. Rejected: overkill for a monotonic version line, and it answers 'different' rather than 'older', which is not the question." 104 guards ORDER and is correct as shipped; "different" is precisely this task's question. rules_sha is the right mechanism, in the right place, doing the wrong thing. This task repairs it.
Proposed Solution
Split the two sides of the comparison and treat them differently, because they are not symmetric.
The installed side is ALWAYS recomputed - hashed from the files on disk at comparison time, never read from .cyberos/manifest.yaml. That is the whole of Defect 1.
The reference side is a token that build.sh wrote over a payload tree. A stored token is trustworthy as a digest of the build that wrote it, because build computed it from that payload's bytes; it is untrustworthy as a digest of any tree that merely carries it, because nothing recomputed it after the copy. Where a payload tree is also reachable, the check additionally diffs that tree to name the differing paths; where only a token is reachable, it reports drift without naming and says so. This makes bash .cyberos/version.sh useful for the first time: recomputing the installed tree against the token its own manifest carries catches post-install mutation, and manifest.yaml's exclusion from the cone is what keeps that from being circular. The asymmetry is the best idea here and it survives, but it is narrower than it first reads: a reference token names a BUILD. version.sh's [repo] argument (§1.9's eighth arm) makes that concrete - there the reference is read from this machine's install manifest, so the verdict means "the target differs from the build this machine claims to come from", not "these two machines differ". The check must say which of those it is doing.
Fix the cone to the vendored set - what install.sh installs, not what the payload ships - declared once in a shared file that build.sh and every comparator read, with a build check that reconciles it against a real install in both directions. Move _rsha() into that same shared file, because build.sh is never vendored and the two installed comparators cannot reach it. Report the differing paths where a tree allows it. Keep each component's existing exit contract.
Alternatives Considered
- Add a per-file manifest beside
rules_sha. Rejected: a second comparator for the same question, which TASK-IMP-104 §1.2 forbids by name, and the first draft of this spec proposed it only because it had not foundrules_sha. - Bump VERSION on every payload change. Rejected: conflates release identity with build identity, forces a bump for a comment fix, and still cannot see a vendor step that drops a file.
- Compare mtimes. Rejected: not content; survives no copy or checkout faithfully; would have reported the 2026-07-18 drift as fine.
- Re-vendor on every
.cyberosuse. Rejected: install is not free, and a guard that silently repairs drift teaches nobody that the channel leaked. - Widen the cone only, leaving the token stored. Rejected: it fixes which files are covered and leaves the check comparing two copies of one build-time answer. Defect 1 survives untouched.
- Derive the cone by static analysis of
install.sh. Rejected by the operator, and the code says why: the copies are conditionally guarded (:187-198), one iterates a loop variable (:431-432), and one branch is env-gated (memory/only whenCYBEROS_NO_MEMORY != 1). No static read of that file yields the set. - NEW3-004, the CONE's element grammar:
dir:/file:/prune:, with memory asdir:memory+prune:memory/store/(the exclusions' fourth kind is the next bullet). Chosen over the file-granular reading (file:memory/AGENTS.mdand its two siblings). Both hash identically today - each resolves to the same 3 files per side - so the tie breaks on what happens when they diverge. Underfile:× 3, a fourth file added to the payload'smemory/that:431-432's hardcoded loop does not copy is invisible to every check, forever. Underdir:memory, the cone resolves to 4 while the install has 3, and §1.6's second direction fails the build - the divergence surfaces at build time, on the machine of the person who caused it, instead of becoming permanent drift on every install that no re-install can clear. The file-granular reading also makesprune:memory/store/dead text for §1.4, since nothing then enumerates it - which was the audit's charge; under the chosen grammar it is load-bearing in both §1.4 and §1.6. Three kinds and not two, becauseinstall.shhas exactly three copy shapes:cp -Ron a directory,cpon a named file, and install-generated content nested inside a coned directory. - NEW4-002, a FOURTH kind
exempt:, and the exclusions' home. The three kinds above are a grammar for the CONE; the nine exclusions of §1.5 had no declared kind at all, and §1.5 put them "alongside" the shared file - which is not a location. Both halves were defects. Eight of the nine sit at$CYroot beneath no coned dir: they are notdir:, notfile:(that would INCLUDE them), andprune:was vacuous on them under §1.3's own wording, since nothing is beneathmanifest.yamland it was never in the resolved set to be removed from. Considered and rejected: widenprune:to cover both jobs by rewording it to "at or beneath, whether or not resolved". One kind fewer, but it destroys a checkable distinction - an author who writesprune:foomeaning "install-generated" whenfoois in fact vendored and coned gets silence, and Direction 2 will not catch it because a pruned path is not in the resolved set. Two kinds let the build check INTENT: aprune:that removes nothing fails UNLESS the path is absent from the tree (defensive prune for install-generated content — NEW5-002); anexempt:that removes something overlaps the cone and fails. That pair of invariants is the direct answer to the standing "dead text" charge, and it is enforceable rather than promised. The home is §1.2's file, as one list of kinded entries - §1.6 Direction 1 must READ the exclusions to classify against them, so they cannot live in prose. Measured: the four kinds classify this repo's real$CYwith zero unclassified paths. - NEW3-005,
_rsha(): move it into the shared cone file rather than leave it inline atbuild.sh:353.build.shis never vendored - measured absent from bothdist/cyberos/and.cyberos/- so.cyberos/version.shand.cyberos/lib/update-check.shcannot reach it, and "usebuild.sh's own_rsha()" was unsatisfiable for two of the three comparators. The alternative, letting each comparator define its own, is the exact duplication §1.2 forbids for the cone and would let the two platform branches drift apart silently. The shared file goes inlib/, whichinstall.sh:197already vendors wholesale, followinglib/version-compare.sh- TASK-IMP-104's "ONE comparator, sourced", already resolved two ways byversion.sh:78andupdate-check.sh:62. The file lands inside the cone, so it fingerprints itself; it contains no digest, so nothing is circular. - Effort: 6 -> 20 hours, and WHY the breakdown wins. 6 was carried unchanged across four revisions and was sized for "widen a
findand add a re-hash". Rewrite 4 re-sized to 16 but published a breakdown summing to 17.5 - two numbers, one document, neither derived from the other. The breakdown is the estimate andeffort_hoursis its sum, so the breakdown wins and 16 was simply wrong: it was a round number written beside an itemisation nobody added up. The arithmetic is now stated so it can be checked rather than trusted. Rewrite 5 also adds scope, and the added scope is priced rather than absorbed: shared lib 2h -> 3h (+1h: the grammar is now four kinds with two enforced invariants, NEW4-002);build.shrewire 1h; reconciler 3h;version.sh2h -> 2.5h (+0.5h: the eighth arm and its disclaimer, NEW4-003);update-check.sh2h;audit-fleet.sh2h;install.sh0.5h; suite 5h -> 6h (+1h: AC 9 goes from seven arms to eight, AC 5 from a spot-check to nine deletion arms, AC 4 to set equality). Sum: 3 + 1 + 3 + 2.5 + 2 + 2 + 0.5 + 6 = 20.0, which iseffort_hours. Re-added by this author rather than carried.
Success Metrics
- Primary: a vendored file mutated by one byte after install, with both VERSIONs and both stored tokens equal, is reported as drift and named. Baseline: reported
up_to_date- reproduced synthetically 2026-07-18; the original six-artefact instance was repaired bye2504cf3and is no longer live evidence. - Guardrail: a freshly installed, unmodified machine reports current from every component. The expected fingerprint is DERIVED at check time via a fresh temp-install of the payload (§1.7 pattern), not pinned as a hardcoded digest or file count in this document. Historical measured digests (e.g.
102dc507/ 1534 files on 2026-07-18) may appear in Problem/evidence prose only and are NOT normative success criteria. - Guardrail: every path
install.shVENDORS is either inside the cone or inside a named exclusion class, enforced at build. (Not "every directory the payload ships": that formulation is retracted by the ADDENDUM and is what forcedci/,cli/andtemplate/into the cone and guaranteed self-drift.)
Scope
In scope: the cone and _rsha() at build.sh:353-355, relocated to a new shared vendored library; recomputation and path-naming in version.sh, lib/update-check.sh, audit-fleet.sh; the build reconciler; install.sh vendoring the new library; a suite. check-version-sync.sh is deliberately NOT in scope: it has no installed side (grep -c '\.cyberos' = 0) and only shape-checks the token.
Out of scope / Non-Goals
- TASK-IMP-104's ordering guard. Correct as shipped; untouched.
- Install-generated and operator-owned paths - the NINE of §1.5 (
memory/store/,gates.env,config.yaml,.update-check-cache,AGENT-ENTRY.md,gates.env.bak.*,.install.lock,manifest.yaml,VERSION). Normatively excluded by §1.5 as kinded entries, not merely noted. - Auto-repairing drift. Reporting is the deliverable;
install.shalready re-vendors. - Tamper-evidence. §1.14 makes the prohibition normative rather than a hope in prose.
- Build-side conditional copies that silently drop a file from the payload (
build.sh:198). See §3 - a recorded, uncovered gap, not a promise this task can keep.
Dependencies
None. TASK-IMP-104's guard runs before the lock and is untouched, and the new shared library sits beside lib/version-compare.sh without altering it.
AI Authorship Disclosure
- Tools used: Claude (Opus 4.8) running the CyberOS task-author skill inside Cowork.
- Scope: rewrite 5, 2026-07-18, after FIVE independent audits (4/10, 6/10, 6/10, 6/10, 8/10). Rounds 1-3 patched only what each audit named. Round 4 fixed that and broke the flat line, but shipped a false number of its own: it paired the corrected cone's digest
102dc507with 1525, the file count of the cone §1.4 REJECTS, normatively, in AC 10 and Success Metrics - so a test written faithfully to its own AC would have failed a correct implementation. That number was published beneath THIS disclosure's predecessor, which asserted that "every numeric and line-number claim was re-measured": the claim was true of everything round 4 INHERITED and false of what it ORIGINATED. This disclosure is therefore scoped deliberately: every number in this document was re-derived from source at HEAD by this author during rewrite 5, including the ones this author invented and including the ones the round-4 audit supplied - the audit's own figures were treated as claims to verify, not facts to copy. Re-derived and CONFIRMED:102dc507= 1534 files per side (and86cafee8= 1525, which is what 1525 actually counts); all four AC-10 combinations with their file counts; the memory 3/8 and store 0/5 splits. Re-derived and CORRECTED: 1525 -> 1534 (AC 10, Success Metrics);install.sh:636cited as a temp-repo write when it writes to$HOME(§1.7);effort_hours: 16against a breakdown summing to 17.5 (now 20.0, re-added). Measured and ADDED:version.sh's eighth invocation arm, executed against a fixture rather than reasoned about. Claims that could not be measured are marked as gaps in §3 rather than asserted. - Human review: scope approved at the 2026-07-18 PLAN gate; both HITL gates are recorded human verdicts. The comparable-set, maintained-list and report-promise decisions are the operator's, recorded in
source_decisions. The cone grammar, theexempt:kind,_rsha()'s relocation, the eighth arm's treatment and the effort figure are authors' decisions, each with rationale in Alternatives and attributed by rewrite number insource_decisions.
1. Description (normative)
- 1.1 Every component that reports rule drift between an installed machine and a reference (
version.sh,lib/update-check.sh,audit-fleet.sh) MUST derive the INSTALLED side - the side the verdict asserts about - by RECOMPUTING the fingerprint over that tree at comparison time. The prohibition is per ROLE, not per FILE: no component may derive the INSTALLED side by reading a stored token, from.cyberos/manifest.yamlor anywhere else, even though the same file may legitimately supply the REFERENCE side (version.sh's eighth arm, §1.9, does exactly that). The REFERENCE side MAY be a stored token, becausebuild.shcomputed it over a payload tree andinstall.sh:188copies it verbatim: a token is a faithful digest of the BUILD it was written by, and never of any tree that merely carries it. That premise is sound but licenses less than it appears to, and every component MUST honour the limit: a reference token names a build, not a reachable payload and not the bytes of the machine it was read from. Where the reference token is read out of an INSTALL's manifest (§1.9's eighth arm), the verdict MUST be understood and reported as "the installed side differs from the build the reference machine claims to come from" - NOT as a comparison of the two machines' bytes, because the reference machine's own tree was never recomputed. §1.9 governs what such an arm may name. - 1.2 The cone, the EXCLUSION LIST (§1.5) and
_rsha()MUST each be declared exactly ONCE, in a single shared file (lib/rules-cone.sh) thatbuild.sh,version.sh,lib/update-check.shandaudit-fleet.shall read by sourcing, and whichinstall.shMUST vendor so the two installed comparators can reach it. The cone and the exclusions are ONE list of kinded entries (§1.3), not two files and not a file plus a convention: "alongside it" is not a location, and §1.6 cannot classify a path against a list it cannot read. No component may carry its own copy of the list or its own definition of the digest function. The list is MAINTAINED, not derived: no static read ofinstall.shyields the vendored set, because its copies are conditionally guarded (:187-198), one iterates a loop variable (:431-432), andmemory/is env-gated onCYBEROS_NO_MEMORY. - 1.3 Every entry in the shared file MUST carry exactly one of FOUR kinds. Two ADD to the resolved set:
dir:<path>(every file beneath it, recursively) andfile:<path>(exactly that path). Two DECLARE A PATH DELIBERATELY UNHASHED, and both SATISFY §1.6's Direction 1 - a path either kind covers is CLASSIFIED and MUST NOT be reported as unclassified:prune:<path>removes from the resolved set every file AT OR beneath<path>, and is for paths that adir:entry would otherwise pull in;exempt:<glob>declares a path that nodir:/file:entry reaches and that therefore needs no removal - it exists solely so that a path present under$CYis classified BY NAME rather than by omission, and it MAY match a glob (gates.env.bak.*) and MAY match nothing at a given moment (.install.lockis transient). An entry with no kind, or with an unrecognised kind, MUST fail the build rather than be silently skipped. Each removing kind carries an invariant the build MUST enforce, so that neither can rot into dead text nor be used for the other's job: aprune:entry that removes NOTHING from the resolved set MUST fail the build UNLESS<path>is absent from the tree being resolved (a defensive prune for install-generated content that the payload never carries — e.g.prune:memory/store/overdist/cyberoswherememory/store/does not exist). Aprune:that removes nothing STILL fails when misspelt under an existing parent that WOULD have matched files (e.g.prune:memory/stor/whilememory/exists and has files). Anexempt:entry that WOULD remove something from the resolved set MUST fail the build (it overlaps the cone and is aprune:in disguise). - 1.4 The cone MUST be exactly the vendored set OF A DEFAULT INSTALL -
CYBEROS_NO_MEMORYunset, the same environment §1.7 pins the reconciler to:dir:cuo,dir:plugin,dir:mcp,dir:lib,dir:docs-tools,dir:ci(vendored when present —install.shvendor_swap ci),dir:memory(:185-198,:430-433,:255), the six root scripts asfile:entries -install.sh uninstall.sh version.sh status.sh help.sh check-latest.sh(:190-195) - andprune:memory/store/. The qualifier is load-bearing and MUST NOT be dropped:install.sh:427gatesmemory/onCYBEROS_NO_MEMORY, so there are TWO vendored sets, and unqualified this clause is FALSE underCYBEROS_NO_MEMORY=1- it would make the cone both "exactly the vendored set" and a strict superset of it, on a documented install mode. The default is the cone's referent; the env-gated variant is a documented mode this task does not cover (§3). The root scripts ARE in the cone, per the ADDENDUM: they are vendored, and they are byte-identical after a faithful install (measured: all six present on both sides). "They change on every payload edit" is true of the entire cone and is not a reason to exclude anything. - 1.5 The cone MUST exclude three classes. A "declaration BY NAME" is a kinded ENTRY in the shared file of §1.2 -
prune:where adir:entry would otherwise reach the path,exempt:where none does - and nothing else counts: a path left out of the list is excluded BY OMISSION, which §1.6 MUST reject. The nine exclusions and their kinds: (a) install-generated or operator-owned paths that appear under.cyberos/and are never copied from the payload -prune:memory/store/(scaffolded at:441-447, while:431-432's loop copies only three NAMED files from the payload and never the store - so nothing under it is ever vendored; the ONLY one of the nine beneath a coned dir, hence the onlyprune:), andexempt:gates.env(:282-290),exempt:config.yaml(:320-335),exempt:.update-check-cache(update-check.sh:99),exempt:AGENT-ENTRY.md(heredoc-generated at:484),exempt:gates.env.bak.*(created atinstall.sh:369-370when regenerating an existinggates.env;:267is the REMOVAL site for stale backups, not creation),exempt:.install.lock(:105); (b)exempt:manifest.yaml, which IS copied (:188) but MUST be excluded because it CONTAINS the value -build.shcomputesrules_shaand writes the file holding it, so covering it would make the value depend on itself; (c)exempt:VERSION, which IS copied (:189) but is TASK-IMP-104's axis, not this one. Eightexempt:plus oneprune:= nine. The eight sit at$CYroot beneath no coned dir, so they are reachable by neitherdir:norfile:(which would INCLUDE them) and aprune:on them would remove nothing and MUST fail §1.3's prune invariant -exempt:is the kind that fits, and §1.3 gives it the same Direction-1 standing asprune:. Separately from the nine named exclusions, the hash enumeration (_rules_cone_list/_rules_sha_of) MUST skip__pycache__/directories and*.pycfiles wherever they appear under a coneddir:— stale bytecode is install/runtime noise, never vendored content, and must not affect the fingerprint. - 1.6 A build check MUST reconcile the declared list against what
install.shactually installs, in BOTH directions, and MUST fail the build on either. Direction 1: a path present under$CYafter an install that is covered by NO entry in the shared list - neither adir:/file:entry nor aprune:/exempt:one - MUST fail the build, naming that path. This is what §1.5's "by name" buys: the reconciler classifies against declared entries it can read, so a path nobody thought about is loud, while a path someone decided to exclude is silent for a stated reason. Measured against this repo's real$CYunder §1.4's cone and §1.5's nine exclusions: ZERO unclassified paths. Direction 2: a path the cone resolves against the payload that is ABSENT from$CYafter an install MUST fail the build - this is the direction that catchescli, which is in today's cone and is never vendored, is the measured cause of the66bb0459vsae756045false drift, and which nothing else catches structurally. - 1.7 The reconciler MUST obtain
install.sh's vendored set by EXECUTING a real install of the freshly built payload into a temporary root and enumerating the resulting$CY, never by parsinginstall.sh. This is what §1.2 means by reconciling a maintained list against reality: running the loop at:431-432resolves its three names without the reconciler hardcoding them, and running the guards at:187-198resolves them without interpreting them. The reconciler MUST run the install in a PINNED environment, and MUST NOT rely on enumeration for isolation - declining to look at a path does not prevent the write. It MUST run withCYBEROS_NO_MEMORYunset (the default, so the install produces §1.4's referent set) and withCYBEROS_GLOBAL_SKILLSunset or0andHOMEredirected inside the temporary root, becauseinstall.sh:634-636copies skills into$HOME/.claude/skillsand three sibling dirs whenCYBEROS_GLOBAL_SKILLS=1- a write OUTSIDE the temporary root, on the machine running the build, which no amount of careful enumeration undoes. The reconciler MUST NOT write outside the temporary root, and the build MUST fail rather than proceed if the pinned environment cannot be established. Separately from isolation, the reconciler MUST enumerate$CYONLY and not the wider temporary repo thatinstall.shalso writes to (:611and:666, both under the install root - the earlier:636citation was wrong: that line writes to$HOME, not the temp repo, which is precisely why enumeration was never the control that mattered). The reconciler MUST NOT be written so that it derives its expected set from the same list it validates. - 1.8 A recomputed installed fingerprint differing from the reference MUST be reported as drift, INCLUDING when both VERSION strings and both stored manifest tokens are equal.
- 1.9 Path-naming MUST be decided per INVOCATION, never per component, because reachability of a payload TREE is a property of how a tool is called. Where a payload tree IS reachable, the report MUST name every differing path. Where only a token is reachable, the report MUST state that it cannot name paths, rather than implying a complete report. The arms, measured - EIGHT, not seven:
bash <payload>/version.sh <repo>has a tree ($hereis the payload);bash .cyberos/version.shwith NO argument has NONE ($here == $CY, andCYBEROS_PAYLOADat:44/:66is a fallback that a present installed manifest pre-empts);bash .cyberos/version.sh <other-repo>- the EIGHTH arm, whichversion.sh:7-8documents and which the no-argument wording above silently swallowed - has none either, but for a DIFFERENT reason that MUST NOT be conflated with it::13setsherefrom$0while:26-30setsrootfrom the argument, so$here != $root/.cyberos,:89's comparison is LIVE, and it DOES reportrules_drift(measured: against a fixture manifest carrying a different token it printsverdict=rules_drift, where the no-argument control printsup_to_date). Its reference is$here/manifest.yaml- THIS machine's INSTALL manifest, not a payload - so per §1.1 it MUST report drift WITHOUT naming paths, and MUST state that its reference is a build token read from an install rather than a payload, so that the report cannot be read as "these two machines differ" when the reference machine's own bytes were never recomputed;lib/update-check.shhas a tree whenCYBEROS_PAYLOADis set (:84takes PRECEDENCE overself_root) or when sourced from a payload'slib/(:86), and has none when sourced from.cyberos/lib/withCYBEROS_PAYLOADunset (self_root == $CY);audit-fleet.shhas a tree in its DEFAULT mode (:16-17resolve$_self/dist/cyberos) and only a token underCYBEROS_EXPECT_RULES_SHA(:14, which short-circuits:15's resolution entirely). - 1.10 An installed tree byte-identical to the payload ACROSS THE CONE MUST be reported as current by every component. "Byte-identical across the cone" is the whole test: paths outside the cone MUST NOT affect the verdict - neither
ci/,cli/andtemplate/, which ship and are never installed, normemory/store/, which installs and never ships. - 1.11 Recomputation MUST use the shared
_rsha()(sha256sumon Linux,shasum -a 256on macOS) and itsLC_ALL=Csort, so that a byte-identical tree yields a byte-identical fingerprint on both platforms and on both sides of every comparison. - 1.12 A comparison that cannot be computed (the reference manifest absent or unreadable, the installed tree unreadable, or the shared cone file unreadable) MUST yield the verdict
unknown. No component may yield a current verdict on a comparison it could not perform. - 1.13 Exit contracts:
lib/update-check.shremains soft-by-default (:18) and MUST NOT change its exit semantics in any mode it binds.audit-fleet.shMUST NOT retain its present fail-open behaviour (:19, "rule-drift check DISABLED"); with no expected token it MUST yieldunknownper §1.12 rather than warning and silently passing. - 1.14 No component's output may describe the fingerprint as detecting tampering, since anything able to rewrite a vendored file can rewrite the manifest beside it.
- 1.15 A comparison MUST NOT modify the installed machine except that
lib/update-check.shalone MAY continue writing its existing$cy/.update-check-cache(:99, reached only when none of the three early returns at:19,:28and:39fires).version.shsourcesupdate-check.shwithCYBEROS_UPDATE_CHECK=always(version.sh:33-37), so that cache write is expected on a manual version check; AC 15 therefore permits ONLY.update-check-cacheto differ. No other component may write anything.
2. Acceptance criteria
- [ ] AC 1 (traces_to: #1.1) - for EACH of the three comparators, mutating one byte of a vendored file while leaving BOTH stored manifest tokens untouched is RECOMPUTED to a differing digest and reported as drift; the test MUST exercise all three by name and MUST FAIL if any one still answers the installed side from the stored token - test:
tools/install/tests/test_rules_sha_recompute.sh::t01_installed_side_recomputed_not_recalled - [ ] AC 2 (traces_to: #1.2) -
lib/rules-cone.shis the ONLY in-tree definition of THREE things §1.2 requires: (1) the cone list, (2) the exclusion list, and (3)_rsha(); all three live as kinded entries / functions in that one file; it is sourced bybuild.sh,version.sh,lib/update-check.shandaudit-fleet.sh, and is present at.cyberos/lib/rules-cone.shafter an install; the test MUST FAIL if any caller carries a second copy of the cone, the exclusions, OR_rsha(), MUST FAIL against today'sbuild.shwhich inlinesfind cuo plugin mcp cli memory, and MUST FAIL ifinstall.shdoes not vendor it - test:tools/install/tests/test_rules_sha_recompute.sh::t02_one_shared_vendored_declaration - [ ] AC 3 (traces_to: #1.3) - an entry with no kind prefix, and separately one with an unrecognised kind, each FAIL the build rather than being skipped; each of the FOUR kinds resolves as specified -
dir:pulls in a nested file,file:pulls in exactly one path and not its siblings,prune:removes a file beneath a coned dir,exempt:removes nothing yet classifies a$CYpath for §1.6 Direction 1 (asserted via a glob entry AND via an entry matching nothing); and both invariants fire - aprune:removing nothing FAILS the build when the path is misspelt under an existing parent that would have matched files, BUT aprune:whose path is ABSENT from the tree (defensive install-generated prune) PASSES; anexempt:overlapping the cone FAILS the build - test:tools/install/tests/test_rules_sha_recompute.sh::t03_element_grammar_four_kinds_and_invariants - [ ] AC 4 (traces_to: #1.4) - SET EQUALITY, §1.4's verb, asserted directly: the cone resolved over the payload EQUALS §1.7's enumerated
$CYof a DEFAULT install minus the §1.5 exclusions, as sets of paths compared element-wise with BOTH difference directions asserted empty; plus 12 separately-asserted mutation arms (one file under EACH ofcuo plugin mcp lib docs-tools memory, and EACH of the six root scripts) yielding drift; the test MUST FAIL on today's cone, which omitslib,docs-toolsand all six root scripts, MUST FAIL ifcliis present in the cone, and MUST FAIL if either difference direction is non-empty even when all 12 arms pass - test:tools/install/tests/test_rules_sha_recompute.sh::t04_cone_is_exactly_the_vendored_set - [ ] AC 5 (traces_to: #1.5) - all NINE exclusions are DECLARED entries carrying a kind, asserted by reading the shared list and matching it element-wise against §1.5's nine (one
prune:memory/store/, eightexempt:), and "by name" is tested by DELETION: removing any one of the nine from the list makes §1.6 Direction 1 fail the build naming that path (nine separately-asserted arms), which is what distinguishes a named exclusion from an omitted one and MUST FAIL if any of the nine can be dropped silently; for the.install.lockarm specifically: if that path is absent under$CY, the fixture MUST create it under$CYBEFORE asserting the deletion arm so the arm is producible (NEW5-003); plus each class still yields NO drift when its member changes, via a member requiring an ACTIVE prune and not only trivial ones - class (a) viamemory/store/(adding a file INSIDE the coneddir:memory) AND viagates.env,config.yaml,.update-check-cache,AGENT-ENTRY.md,gates.env.bak.*and.install.lock; class (b) via mutatingmanifest.yaml's ownrules_sha:line; class (c) viaVERSION- test:tools/install/tests/test_rules_sha_recompute.sh::t05_exclusions_named_and_pruned - [ ] AC 6 (traces_to: #1.6) - BOTH directions fail the build, each asserted separately: direction 1, adding a
cpof a NEW path intoinstall.shthat is in neither cone nor exclusions fails the build naming that path; direction 2, a cone entry the install does not produce fails the build, exercised with the REALclifixture (adddir:clito the cone, build, assert non-zero exit namingcli), and the test MUST FAIL if the build passes withcliconed - test:tools/install/tests/test_rules_sha_recompute.sh::t06_reconciler_fails_both_directions - [ ] AC 7 (traces_to: #1.7) - the reconciler obtains its expected set by EXECUTING install.sh into a temp root: the test asserts a temp
$CYwas created and enumerated, asserts the:431-432memory loop resolved to its three files with no memory filename hardcoded in the reconciler, and MUST FAIL if the reconciler is rewritten to parseinstall.shtextually, if it derives its expected set from the list it validates, or if it enumerates any path outside$CY; and the ENVIRONMENT is pinned, asserted by running the reconciler withCYBEROS_GLOBAL_SKILLS=1exported andHOMEset to a canary outside the temp root, then asserting the canary is byte-identical afterwards and that NO path outside the temporary root was written - which MUST FAIL if the reconciler merely declines to enumerate those writes instead of preventing them - test:tools/install/tests/test_rules_sha_recompute.sh::t07_reconciler_runs_install_does_not_parse_it - [ ] AC 8 (traces_to: #1.8) - drift is reported with both VERSION strings AND both stored tokens equal - the exact 2026-07-18 shape; the test MUST FAIL if any component reports current - test:
tools/install/tests/test_rules_sha_recompute.sh::t08_equal_tokens_still_drift - [ ] AC 9 (traces_to: #1.9) - per INVOCATION and not per component, all EIGHT measured arms asserted separately:
bash <payload>/version.sh <repo>names all THREE mutated files and MUST FAIL if only the first is named;bash .cyberos/version.shwith no argument states it cannot name paths AND still reports the drift AND MUST FAIL if settingCYBEROS_PAYLOADchanges either (it is a fallback, pre-empted at:66);bash .cyberos/version.sh <other-repo>REPORTSrules_driftagainst a fixture whose token differs, states it cannot name paths, states its reference is a build token read from an install rather than a payload, and MUST FAIL if it names paths, if it reports current, or if the suite asserts this arm is unreachable;update-check.shwithCYBEROS_PAYLOADset names paths, sourced from a payload'slib/names paths, and sourced from.cyberos/lib/without it states it cannot;audit-fleet.shon its DEFAULT names them, and underCYBEROS_EXPECT_RULES_SHAstates it cannot - test:tools/install/tests/test_rules_sha_recompute.sh::t09_naming_follows_invocation_not_component - [ ] AC 10 (traces_to: #1.10) - a freshly installed unmodified machine is reported CURRENT by every component; the expected fingerprint is DERIVED via a fresh temp-install of the same payload (§1.7 pattern): build payload, install into a temp root, recompute the installed side with
_rules_sha_of, and assert every component reports current against that derived value — NO hardcoded digest or file count is a normative assertion; the historical four-combination table (66bb0459/ae756045etc.) remains in Problem/evidence prose only as non-normative motivation for why today's cone fails; the test MUST FAIL on today's cone (which yields false drift on a byte-identical vendored pair due tocli/andmemory/store/) - test:tools/install/tests/test_rules_sha_recompute.sh::t10_clean_install_is_current - [ ] AC 11 (traces_to: #1.11) - every comparator RESOLVES
_rsha()from the shared file and carries no second definition (identity of implementation, not merely a matching digest), the recomputed fingerprint EQUALSbuild.sh's for the same tree, and a fixture forcing theshasum -a 256branch yields the same digest as one forcingsha256sum; and theLC_ALL=Csort is pinned, asserted by a fixture containing filenames whose order differs betweenLC_ALL=Cand a locale that collates differently (e.g.en_US.UTF-8) yielding the SAME digest under both - the clause's own stated mechanism, previously untested; the test MUST FAIL if either platform branch diverges, if the locale changes the digest, or if any comparator defines its own_rsha- test:tools/install/tests/test_rules_sha_recompute.sh::t11_shared_rsha_identity_and_cross_platform - [ ] AC 12 (traces_to: #1.12) - with the reference manifest removed, separately with it unreadable, separately with the installed tree unreadable, and separately with
lib/rules-cone.shunreadable, every component emits the verdictunknownand none emits a current verdict; the assertion is on the emitted VERDICT (§1.12's verb) - test:tools/install/tests/test_rules_sha_recompute.sh::t12_uncomputable_is_unknown_not_current - [ ] AC 13 (traces_to: #1.13) -
update-check.shkeeps its exit semantics in EVERY mode it binds (softreturns 0 on drift,strictreturns non-zero,alwaysignores the throttle,0/off/falsereturns 0 immediately) - a regression guardrail, stated as such; andaudit-fleet.shwith no expected token emitsunknownand does NOT pass, which MUST FAIL against today's:19warning-and-continue - test:tools/install/tests/test_rules_sha_recompute.sh::t13_exit_contracts - [ ] AC 14 (traces_to: #1.14) - no component's output matches tamper/integrity/authenticity wording on a drift run, an
unknownrun, OR a current run - test:tools/install/tests/test_rules_sha_recompute.sh::t14_no_tamper_claims - [ ] AC 15 (traces_to: #1.15) - after a comparison from EACH component, the installed tree may differ from its pre-check snapshot ONLY by
.update-check-cache, whichlib/update-check.shMAY write (including whenversion.shsources it withCYBEROS_UPDATE_CHECK=always); every other path MUST be byte-identical; the test MUST FAIL ifversion.shoraudit-fleet.shwrites any path other than that cache (or ifupdate-check.shwrites anything else) - test:tools/install/tests/test_rules_sha_recompute.sh::t15_check_is_read_only
3. Edge cases
- Payload NEWER than installed with VERSION differing: TASK-IMP-104's ordering guard owns the refusal; this check reports drift and does not duplicate it.
- Operator hand-edited a vendored file: reported as drift and named. The report says what differs, never who differed it (§1.14 covers the wording).
- A vendored file that is legitimately empty: hashed like any other. Empty is a content.
- First install, no installed tree: §1.12's
unknown, not drift and not current. - A BUILD-side conditional copy that silently drops a file from the payload (
build.sh:198's[ -f "$here/docs-tools/workflow-improve.mjs" ] && cp ...- the measuredworkflow-improve.mjscase): the file never reaches the payload, so it is absent from the payload fingerprint AND from the install, and both sides agree. Nothing in this task catches that. §1.6's reconciler cannot either: it resolves the cone against the payload, and a file missing from the payload is missing from that resolution too. Recorded as an uncovered gap, not handed to a clause that cannot honour it. It is the sibling defect and wants its own task. - A payload file under a coned dir that
install.shdoes not vendor is caught at BUILD by §1.6's direction 2, not at comparison time - deliberately. The build fails for the person who caused the divergence, instead of every installed machine reporting a drift that no re-install can clear. This is thedir:memorygrammar decision doing its work. audit-fleet.shwith a reachable payload rather than a bare token: it MAY name paths per §1.9's first arm; the clause requires the disclaimer only when no tree is reachable.CYBEROS_NO_MEMORY=1installs:memory/is absent from$CYby design, so §1.6's direction 2 would fail the build if the reconciler ran under it. §1.7 pins the reconciler to the default environment AND §1.4 now pins its "exactly the vendored set" claim to that same default (there are two vendored sets; unqualified, §1.4 was false under this mode - the clause and the reconciler now agree on their referent instead of one carrying a qualifier the other contradicted). The env-gated variant is a documented install mode, not a cone violation, and this task does not extend the reconciler to cover it. A machine installed withCYBEROS_NO_MEMORY=1will report drift against a memory-carrying payload, correctly and unhelpfully - out of scope here.- macOS vs Linux: §1.11 pins the shared
_rsha()andLC_ALL=C. This is thestat -c/-fclass of defect TASK-IMP-103 already paid for once. - Security-class: the fingerprint is a staleness signal, not an integrity guarantee. §1.14 makes that normative and AC 14 tests it across all three verdicts.
Audit
TASK-IMP-122 - audit record
§0 - Provenance, and why this file had to be reconstructed
This page was rebuilt on 2026-07-18. Read this section before trusting any finding id on it.
The audits for rounds 4, 5 and 6 were written into COMMIT MESSAGES and never into this file. The findings were then handed author-to-author through prompts. Three authors cited, closed and argued against findings they could not open. That defect was found independently by two agents, recorded as NEW5-007, and is quoted in §5.5. This file is the remedy: every id cited anywhere in the task now resolves to a section here, and every section states where it came from.
What that means for a reader. There are two kinds of section on this page and they are not interchangeable:
| kind | sections | what you are reading |
|---|---|---|
| written at the time | §1 (round 3) | the auditor's own audit file, committed at b37b795a, preserved verbatim |
| reconstructed from commit | §2, §3, §4, §5 | the orchestrator's summary of an audit. The audit's own text does not exist. |
A reconstructed section is weaker evidence than a written-at-the-time one, in a specific way: it is one author's account of what an auditor said, written after the fact, with no artefact behind it to check the account against. Where the commit message is the only source, the section says so.
The rounds, mapped. The naming is inherited from the commits and is not self-explanatory - audit n+1 audits rewrite n from round 4 on:
| section | round | what it is | source | persisted at the time? |
|---|---|---|---|---|
| §1 | round 3 | audit of rewrite 3 - FAIL 6/10 | b37b795a (this file) | YES |
| §2 | round 4 | audit of rewrite 4 - FAIL 8/10, NEW4-001..004 | 7309cd80 message | no |
| §3 | round 4? | NEW4-005 / NEW4-006 - provenance unverifiable | nothing | no audit ever existed for these |
| §4 | round 5 | rewrite 5's closure record - the author's claims, not an audit | 15894b1e message | no |
| §5 | round 6 | audit 6, of rewrite 5 - FAIL 8/10, NEW5-001..004/006/007 | 1f8143cf message | no |
Ids cited by spec.md that resolve here: NEW3-004 (§1.4), NEW3-005 (§1.4), NEW4-002 (§2.3), NEW4-003 (§2.4), NEW4-005 (§3), NEW4-006 (§3).
Ids that do NOT fully resolve, stated plainly:
- NEW4-005, NEW4-006 - cited in
spec.mdas "audit rated LOW". No audit raising them survives, and the round-4 audit that would have raised them enumerates NEW4-001..004 only. The attribution cannot be checked. See §3 - this is recorded rather than reconstructed, deliberately. - NEW5-005 - no record of this id exists anywhere: not in any commit message, not in any file, not in either spec. See §5.4.
§1 - ROUND 3: audit of rewrite 3 - FAIL 6/10
Provenance: WRITTEN AT THE TIME. This is the audit file as committed at
b37b795a(2026-07-18). It is the only section of this page that is an auditor's own artefact. Preserved verbatim; nothing below this line in §1 has been edited.Two things in it are now out of date, and are preserved rather than corrected (the corrections live in this file's frontmatter, and the reasoning in
FLAT_LINE_statusandSTOP_SIGNAL_status):
- "FLAT for four rounds" / "flat for a fourth round" - true when written, false now (rounds 5-6 scored 8/10).
- the STOP_SIGNAL - a real judgement, acted on, now superseded: a different author scored 8.
Round 3's own header block, as written:
task_id: TASK-IMP-122
audited: 2026-07-18 (rewrite 3; supersedes the rewrite-2 audit)
verdict: FAIL
score: 6/10
score_history: "4/10 -> 6/10 -> 6/10 -> 6/10 (FLAT for four rounds)"
issues_closed: 4
issues_partially_closed: 3
issues_open: 4 (survived VERBATIM) + 8 new
template: task@1
audit_rubric_version: audit_rubric@2.0
machine_floor: task-lint clean, four rounds running. TRACE-001/002/003 pass every time.
auditor: independent subagent; diffed 2d478393..f8899d64 and measured all four cone combinations
STOP_SIGNAL: >
The author has failed to raise this score across three rewrites. The failure mode is now
legible and is recorded in §2. A fourth rewrite by the same author, patching the findings
below, will likely reproduce it. Read §2 before attempting one.
§1.1 - Verdict summary
FAIL at 6/10, flat for a fourth round. The operator's maintained-list decision IS honoured and rewrite 2's two CRITICALs ARE genuinely closed. It fails because the diff proves the hypothesis it was given: rewrite 3 edited ONLY §1.2, §1.3, §1.4, §1.6 and AC 2/3/4/6/7/10 - the exact block the prior audit named. Everything outside that block survived VERBATIM, and two of the edits are REGRESSIONS that deleted working normative text.
§1.2 - THE FAILURE MODE (read this before rewriting)
The author patches what the audit NAMES and does not re-read the document. Consequences, all measured this round:
- Four findings survived verbatim because they sat outside the named block: NEW2-005 (the Proposed Solution still says "token"), NEW2-009 (Summary duplicates a proposition), NEW2-010 (":99 on every run" - THIRD round unedited), NEW2-011 (AC 1's "BOTH stored manifest tokens").
- A fix DELETED the clause that catches the live bug (NEW3-001, below).
- A repaired clause now contradicts two unrepaired sections (NEW3-002, below).
- A false number was copied from the evidence file's parenthetical without re-measuring (AC 7's memory counts), while the AI-authorship disclosure claims "every claim here was re-measured against source that day". It was not.
The pattern across four rounds: close the named finding, introduce the same defect class one layer deeper. Rewrite 1 conflated payload/installed cones. Rewrite 2 cited a line range that excluded the blind spot. Rewrite 3 deleted the direction that catches cli. Each is "the check does not cover the thing it exists to check", relocated.
§1.3 - Prior findings
CLOSED: NEW2-001 (cone now covers lib/docs-tools/memory; :185-198 is BETTER than the audit's :184-198 - :184 is rm -rf, not a vendor), NEW2-002 (all 18 vendored paths land in cone ∪ exclusions - the build no longer always-fails), NEW2-007, NEW2-008 (auditor measured all four combinations: prune cli only -> 1f05a84f/ae756045 MISMATCH; prune store only -> 66bb0459/1f05a84f MISMATCH; prune both -> MATCH. The independence claim is EXACTLY right). PARTIALLY: NEW2-003, NEW2-004, NEW2-006. NOT CLOSED (verbatim survivors): NEW2-005, NEW2-009, NEW2-010, NEW2-011.
§1.4 - New findings
NEW3-001 (CRITICAL, REGRESSION) - §1.4's second direction was DELETED; the check can no longer catch the live defect.
Author verified by diff: rewrite 2: "A path the cone covers that install.sh does not vendor MUST fail the build." rewrite 3: [deleted] The prior audit called that direction a tautology - true ONLY while §1.2 defined cone == vendored set. §1.2 no longer says that (it now says "a single explicit list"), so the tautology is gone and the direction is LOAD-BEARING again. And today's live defect IS exactly that direction: cli is IN the cone and NEVER vendored - the measured cause of 66bb0459 vs ae756045, named by §1.7, and half of AC 7's own reasoning. Nothing in §1.3 forbids cli in the cone; §1.4 now fires only on vendored-but-unclassified. The build check the rewrite was built around CANNOT FAIL on the defect that motivated it.
NEW3-002 (CRITICAL) - the Proposed Solution and Success Metrics still mandate the RETRACTED cone.
Author verified, unedited at :102-103 and :128: ":102 ... compare that against the payload's manifest token. Widen the cone" ":103 to every directory the payload ships." ":128 - Guardrail: every directory present in the payload is inside the cone, enforced at build." The evidence file RETRACTS that formulation by name: "'the cone MUST cover every directory the payload SHIPS' is wrong and is what forced ci/, cli/, template/ in and guaranteed self-drift". §1.3 was repaired; the identical retracted wording survives in two other sections, where it now contradicts §1.3, §1.7, AC 7 and the operator decision - and mandates precisely the cone AC 7 exists to fail on.
NEW3-003 (MAJOR) - AC 3 tests class (a) by its trivial member.
gates.env sits OUTSIDE every coned dir - excluding it requires nothing. memory/store/ sits INSIDE a coned dir - excluding it requires an ACTIVE PRUNE, and is a measured co-equal cause of the false drift. AC 3 tests the exclusion that cannot break and skips the only one that can. 6 of the 7 paths in class (a) untested.
NEW3-004 (MAJOR) - the cone's element grammar is undefined; memory is the proof.
§1.2 mandates "a single explicit list" and never says what an entry IS. build.sh:354 is dir-granular. §1.3 needs three kinds: dirs (cuo), files (the three under memory/), prunes (memory/store/). "cover the vendored FILES under memory/" is file-granular - under which class (a)'s memory/store/ entry is DEAD TEXT. Listing memory/store/ as an exclusion implies dir-minus-prune - under which AC 3 never tests it. Either reading carries a defect.
NEW3-005 (MODERATE) - §1.8 has §1.2's disease and did not get §1.2's cure.
§1.8 requires "build.sh's OWN _rsha()". _rsha() is defined INLINE at build.sh:353, and build.sh is NEVER VENDORED (absent from dist/cyberos/). So .cyberos/version.sh and .cyberos/lib/update-check.sh cannot reach it - §1.8 is unsatisfiable for two of three comparators. It needs exactly what §1.2 gave the cone (one shared, vendored definition). AC 8 tests EQUALITY of digest, not IDENTITY of implementation - so AC 8 PERMITS the duplicated second implementation that AC 2 forbids for the cone.
NEW3-006 (MODERATE) - §1.6's invocation cut is incomplete; AC 6 dropped a capability.
update-check.sh:84 gives CYBEROS_PAYLOAD PRECEDENCE over self_root - so reachability there is decided by the env var, not by where it was sourced. §1.6 hedges ("in its PRIMARY mode") and never says what the non-primary mode owes. And AC 6 DROPPED update-check.sh entirely - rewrite 2's AC 6 tested it. Regression.
NEW3-007 (MINOR) - §1.2's deliverable is in neither new_files nor modified_files.
The shared cone file appears nowhere; no such file exists in-tree; install.sh (which must vendor it for the two installed comparators to read it) is absent from modified_files. effort_hours: 6 is UNCHANGED across all four revisions despite the prior audit's explicit "re-size effort_hours".
NEW3-008 (LOW) - three citation errors the author inherited and did not re-measure.
build.sh:357cited as the manifest write. Author verified: :357 is a BLANK LINE; the write iscat > "$out/manifest.yaml" <<EOFat :358. This is the load-bearing rationale for exclusion class (b).- AC 7: "
memory/store/3 payload files vs 8 installed" is FALSE. Author measured: 0 and 5. The 3-vs-8 ismemory/'s tree total, misattributed. It also CONTRADICTS the spec's own §1.7 ("installs and never ships"). Two clauses, one document, opposite counts. - §1.2 says "three separate places" and cites TWO ranges (
:185-198and:432).
§1.5 - Clause-verb table: 4 of 12 weaker (identical count to rewrite 2)
The SET moved: AC 2/7/10 CLOSED; AC 4/6/8 NEWLY weaker; AC 3 weaker for a new reason. Three of the four weak ACs are ones the author rewrote this round. The rewrite relocated the weakness. AC 4 restates §1.4's prohibition with no fixture and no observable - the identical defect the prior audit already flagged once ("the AC never says WHAT to mutate"), recurring at a new AC.
§1.6 - Required before re-audit
- RESTORE §1.4's second direction and AC 4's matching half. Rewrite 2 had it right.
- Rewrite the Proposed Solution AND Success Metrics - never edited, still retracted wording.
- Name the mechanism by which §1.4 reads install.sh's vendored set, given §1.2 says no static read yields it, and say how it resolves the
memory/$floop without hardcoding. - Give §1.2's list an element grammar (dir / file / prune); settle
memory. - Give
_rsha()§1.2's treatment; make AC 8 test identity, not equality. - AC 3 must test memory/store/. AC 6 must test update-check.sh + CYBEROS_PAYLOAD. AC 4 needs a fixture.
- Fix the four verbatim survivors and the three citation errors.
- Add the shared cone file to new_files, install.sh to modified_files, re-size effort_hours.
§2 - ROUND 4: audit of rewrite 4 - FAIL 8/10
Provenance: RECONSTRUCTED FROM COMMIT
7309cd80(2026-07-18); no contemporaneous audit file exists. What follows is the orchestrator's summary of an independent audit. The auditor's own text is gone. The commit message enumerates NEW4-001 through NEW4-004 and no others - which is the fact §3 turns on.
§2.1 - Verdict summary
FAIL 8/10. History 4 -> 6 -> 6 -> 6 -> 8. The flat line broke on the first round the original author did not hold the pen - rewrite 4 was delegated to an author who had written none of the prior drafts, on round 3's STOP_SIGNAL.
Credited by the round-4 auditor:
- Both CRITICALs closed with REAL fixtures (the
clifixture is live: 1 file in payload, 0 in$CY). - Weaker-AC count 3/15, all minor - the first round in five with no STRUCTURAL weakness (was 5/7, 3/10, 4/12, 4/12).
- All three novel claims verified independently. The reconciler survived every feasibility test the auditor could construct: 2s runtime, deterministic across all 11
CYBEROS_*branches, CI-safe, non-recursive, zero side effects outside the temp root. Direction 1 classifies a real$CYwith ZERO unclassified paths.
Note, added at reconstruction: that last credited property - "zero side effects outside the temp root" - is the one rewrite 5 turned back on this auditor. See §3 (NEW4-006) and §5.1.
§2.2 - NEW4-001 (MAJOR) - AC 10 pairs a correct digest with the WRONG count, normatively
The orchestrator's note records this as independently verified: "I verified this myself, it is exact."
1525 files -> 86cafee8 (cone WITHOUT memory + root scripts - the cone §1.4 REJECTS)
1534 files -> 102dc507 (the corrected cone §1.4 mandates)
The spec pairs 102dc507's digest with 1525's count, and asserts the pair NORMATIVELY in AC 10
- the guardrail AC, the headline metric, the number the previous commit message brags is new. A test written faithfully to AC 10 asserts 1525 and FAILS ON A CORRECT IMPLEMENTATION.
§2.3 - NEW4-002 (MAJOR) - the grammar governs the cone and NOT the exclusion list
§1.3's grammar governs the cone and NOT the exclusion list - which §1.6 Direction 1 and AC 5 both must read. Nine root-level exclusions have no valid kind. Either reading carries a defect. NEW3-004's exact shape, one layer deeper.
(Cited by spec.md source_decisions: rewrite 5 closed this with a fourth kind, exempt:<glob> - see §4.2.)
§2.4 - NEW4-003 (MODERATE) - §1.9 enumerates seven arms and misses the eighth
§1.9 enumerates seven arms and misses the eighth - version.sh [repo], where $here != $CY and drift IS reported. That arm holes Claim 3: the reference is another install's manifest, not a payload, so §1.1's licence to trust a stored token rests on a false premise there.
(Cited by spec.md source_decisions: rewrite 5 added the eighth arm and QUALIFIED §1.1's premise rather than deleting it - see §4.3.)
§2.5 - NEW4-004 (MINOR) - the effort breakdown does not sum to the field
The itemised breakdown added to close NEW3-007 sums to 17.5; the field says 16.
§2.6 - THE PATTERN, FIFTH ROUND RUNNING
A false number in a load-bearing metric. But it MOVED. Round 3's came from trusting the evidence file; round 4's from trusting themselves. The auditor's diagnosis, quoted:
"They re-measured everything they INHERITED and did not re-measure what they ORIGINATED."
Every inherited citation in rewrite 4 was genuinely re-measured and correct. The one number the author invented was not. That is a rule worth having: an author's own new numbers are the least-checked thing in any document, because nothing flags them as needing a check. (This became TASK-IMP-124.)
§3 - NEW4-005 and NEW4-006: FINDINGS WITH NO SURVIVING AUDIT
Provenance: UNVERIFIABLE. This section is deliberately NOT a reconstruction.
There is no audit text for these two findings, and this section does not invent one. What is recorded below is (a) the finding as it was acted on, which does survive, and (b) an explicit statement of what cannot be established. That is less satisfying than a plausible round-4 finding would be, and it is the more valuable artefact: a reader can tell the difference between what is known and what is not.
§3.1 - What is verifiable
Exhaustive search of every commit message on every ref, every tracked file, the working tree and the stash. NEW4-005 and NEW4-006 appear in exactly three places, all of them downstream of the audit that supposedly raised them:
| where | what it says | is it the audit? |
|---|---|---|
15894b1e message (rewrite 5's author notes) | "NEW4-005/006 fixed though the audit rated them LOW. 006 rated higher on review..." | no - the author's account of an audit |
1f8143cf message (audit 6's notes) | "NEW4-006: the author OUT-AUDITED the auditor..." | no - a later auditor's remark about it |
spec.md source_decisions:67-68 | "(rewrite 5, NEW4-005 - audit rated LOW, taken anyway)" and the same for NEW4-006 | no - the spec citing the audit |
And the audit that would have raised them does not contain them. 7309cd80 - the round-4 audit, reproduced in §2 - enumerates NEW4-001, NEW4-002, NEW4-003, NEW4-004, and stops. There is no NEW4-005 and no NEW4-006 in it.
§3.2 - What therefore CANNOT be checked
spec.md attributes both findings to an audit that rated them LOW. That attribution cannot be verified, and this file does not endorse it.
The possibilities are not distinguishable from the surviving record:
- an audit raised them at LOW and was delivered in a prompt and never persisted - the attribution is true and simply unprovable;
- an audit raised them at some other severity and the LOW is misremembered;
- no audit raised them - they are the author's own findings, later attributed to an audit.
Nothing on disk or in history discriminates between these. The one weak signal is that both 15894b1e and 1f8143cf dispute the LOW rating ("006 rated higher on review"; "the author OUT-AUDITED the auditor") - which is consistent with a LOW having been given and argued against, but is equally consistent with a LOW that was never given. It is not evidence.
This is exactly the failure NEW5-007 names (§5.5): an audit that is not persisted cannot be checked, and a finding id that is misremembered or invented is indistinguishable from a real one. NEW4-005 and NEW4-006 are the class's own worked example. They are preserved as ids so that spec.md's citations resolve to this statement of the problem rather than to nothing - which is the honest destination for them.
§3.3 - NEW4-005, as acted on
Source:
15894b1e(rewrite 5's author) andspec.mdsource_decisions:67. The finding as RAISED does not survive; this is the finding as FIXED.
The fix: §1.4 is qualified to the DEFAULT install. Unqualified, §1.4 is FALSE under CYBEROS_NO_MEMORY=1, which §1.2 itself names - it would make the cone both "exactly the vendored set" and a strict superset of it, on a documented install mode. §1.7 already carried the qualifier; §1.4 did not. Cost: one clause.
Severity: unknown. spec.md says the audit rated it LOW and was overridden ("taken anyway"). Unverifiable per §3.2. On the substance the fix stands on its own reasoning and needs no audit to justify it: the clause was false under a mode the document itself names.
§3.4 - NEW4-006, as acted on
Source:
15894b1e(rewrite 5's author) and1f8143cf(audit 6). The finding as RAISED does not survive; this is the finding as FIXED, plus a later auditor's remark on it.
The fix: §1.7 now pins the install ENVIRONMENT for ISOLATION, not only enumeration. "Declining to look at a path does not prevent the write." install.sh:634-636 copies skills into $HOME/.claude/skills and three sibling dirs when CYBEROS_GLOBAL_SKILLS=1 - a write OUTSIDE the temporary root, on the machine running the build, which no amount of careful enumeration undoes. A $HOME canary was added to AC 7.
The substance, which IS corroborated by a later audit. Per 15894b1e and confirmed by audit 6 (§5.1): the "zero side effects outside the temp root" property that the round-4 auditor VERIFIED and CREDITED (§2.1) was held by no clause - it was true of the CI environment as it happened to be, not of anything the spec required. Audit 6's own words: "the author OUT-AUDITED the auditor."
Severity: unknown, and the LOW rating is doubly doubtful here. spec.md says "audit rated LOW"; 15894b1e says "006 rated higher on review"; audit 6 credits the author with beating the auditor on it. All three of those are post-hoc accounts of a rating no artefact records. Unverifiable per §3.2.
§4 - ROUND 5: rewrite 5's closure record
Provenance: RECONSTRUCTED FROM COMMIT
15894b1e(2026-07-18); no contemporaneous file exists.This is not an audit. It is the rewrite-5 author's record of closing round 4's findings. The independent check of these claims is audit 6 (§5), which re-derived them and confirmed them - so they are corroborated, but by §5 and not by anything in this section. Read the claims here as claims.
§4.1 - NEW4-001 - CLOSED (author's claim; confirmed by audit 6 §5.1)
1525 -> 1534 at both normative sites, re-derived twice by different methods (whole-cone, and component-wise 1525 + 3 + 6). AC 10 now names the trap explicitly so it cannot silently return.
§4.2 - NEW4-002 - CLOSED (author's claim; confirmed by audit 6 §5.1)
Added a FOURTH kind, exempt:<glob>, for paths no dir:/file: reaches. Both removing kinds now carry an enforced invariant - a prune: that removes NOTHING fails the build; an exempt: that WOULD remove something fails the build (it is a prune: in disguise). "That kills the dead-text charge structurally instead of by promise." Home settled: cone + exclusions + _rsha() in ONE file, because "alongside it is not a location and §1.6 cannot classify against a list it cannot read." Verified by the author: four kinds classify a real $CY with ZERO unclassified paths.
This closure is where NEW5-002 came from (§5.2): the
prune:invariant this fix introduced collides with theprune:memory/store/entry §1.5 mandates.
§4.3 - NEW4-003 - CLOSED (author's claim; confirmed by audit 6 §5.1)
Confirmed empirically, not reasoned - version.sh /tmp/otherrepo prints rules_drift where the no-arg control prints up_to_date. Eighth arm added. §1.1's premise QUALIFIED not deleted: "a token is a faithful digest of the BUILD that wrote it, never of a tree that merely carries it."
§4.4 - NEW4-004 - CLOSED (author's claim; confirmed by audit 6 §5.1)
The breakdown was right and 16 was wrong - "a round number written beside an itemisation nobody added up." effort 16 -> 20, rewrite-5 scope priced rather than absorbed.
§4.5 - NEW4-005 / NEW4-006 - acted on; see §3
Fixed by rewrite 5. Provenance unverifiable - do not read §4 as establishing that an audit raised them. §3 is the record.
§4.6 - Weak ACs: 3/15 -> 0
§4.7 - WHAT FIVE AUDITS MISSED: the disclosure was SELF-CERTIFYING
The author's own finding, against no audit's prompting, and the sharpest thing in the round:
The AI Authorship Disclosure was itself stale and SELF-CERTIFYING. It claimed four audits (now five) and that "every numeric claim was re-measured" - and rewrite 4's false 1525 shipped UNDERNEATH THAT SENTENCE. The one clause meant to prevent the failure certified it instead.
Now scoped and checkable: re-derived-and-CONFIRMED vs re-derived-and-CORRECTED vs measured-and-ADDED, and it states that the audit's own figures were treated as claims to verify. (This partition became TASK-IMP-124's COND-004, with rewrite 5's disclosure cited as the worked prototype.)
§5 - ROUND 6: audit 6, of rewrite 5 - FAIL 8/10
Provenance: RECONSTRUCTED FROM COMMIT
1f8143cf(2026-07-18); no contemporaneous audit file exists. The orchestrator's summary of an independent audit. The auditor's own text is gone.
§5.1 - Verdict summary
FAIL 8/10. Same score as round 4, categorically smaller reasons. Remaining work is four clause edits, not a rewrite.
THE FALSE-NUMBER ERA IS OVER. Every originated number re-derived, ZERO false - a first in six rounds. What the auditor re-derived and confirmed:
1534/102dc507and1525/86cafee8confirmed with counts;- all four AC-10 combinations confirmed exactly;
- arm 8 run and confirmed;
- the effort breakdown sums to 20;
- "zero unclassified paths" independently reproduced:
1546real$CYpaths =1534+ 5 store + 7 exempt-present, 0 unclassified.
"The disclosure is now checkable, not self-certifying, and the auditor re-derived every claim in its CONFIRMED bucket and found them exact."
NEW4-006: the author OUT-AUDITED the auditor - the "zero side effects" property the previous auditor VERIFIED (§2.1) was held by no clause. See §3.4.
§5.2 - The remaining findings
NEW5-001 - AC 2 is BYTE-IDENTICAL to rewrite 4's while §1.2 widened to three items
The author widened the clause to close their own NEW4-002 and never re-read the AC tracing to it. "The pattern, in a new organ."
NEW5-002 - §1.3's prune invariant vs §1.5's mandated entry: the build fails unconditionally
dist/cyberos/memory/store does not exist, so resolved over the payload prune:memory/store/ removes NOTHING -> §1.3 says fail the build -> the build fails unconditionally on the list §1.5 mandates. "Extensional test, structural rationale; they diverge."
The collision is between two of rewrite 5's own fixes: the invariant from §4.2 and the entry from §1.5. Closing NEW4-002 opened this.
NEW5-003 - AC 5 claims nine deletion arms; only 8 are producible
.install.lock is absent, so the ninth arm cannot be produced.
NEW5-004 (INHERITED - missed by ALL FIVE prior audits) - AC 15 unsatisfiable
version.sh:33-37 forces CYBEROS_UPDATE_CHECK=always, defeating the :39 throttle -> :99 writes every run. Measured: cache 1784334942 -> 1784336844 after one version.sh run.
This is the finding round 3's §1.2 logged as "NEW2-010 (':99 on every run' - THIRD round unedited)", and which rewrite 4's commit message declared corrected as ":99 is guarded by three early returns, not 'every run'". Audit 6 measured it and the original reading was right. Five audits passed over it.
NEW5-006 - :199 is the REMOVAL site for gates.env.bak.*; creation is :286-287
A citation error in §1.5's exclusion list.
§5.3 - NEW5-005 - NO SURVIVING RECORD
There is no NEW5-005. Not in 1f8143cf, not in any other commit message on any ref, not in any tracked or untracked file, not in either spec. The commit enumerates NEW5-001, NEW5-002, NEW5-003, NEW5-004, NEW5-006 and NEW5-007 - it skips 005 without comment.
No finding text is invented for it here. Whether the id was allocated and dropped, allocated and folded into another finding, or simply misnumbered in the commit message cannot be determined from the surviving record. Nothing cites NEW5-005, so nothing is broken by its absence - it is recorded because an unexplained gap in a finding sequence is exactly the thing a reader must be able to see.
§5.4 - NEW5-007 - THE AUDITS WERE NEVER PERSISTED
Found independently by two agents; verified. This is the finding this file exists to answer, and it is the orchestrator's own defect, recorded rather than quietly fixed. Quoted from
1f8143cf:
THE DEFECT (found independently by two agents; NEW5-007; verified):
NEW4-001-> in 0 tracked docs.NEW-002-> in 0 tracked docs.IMP-122/audit.mdis still the ROUND-3 file: verdict FAIL 6/10, "FLAT for four rounds", and an obsolete STOP_SIGNAL, atb37b795a.IMP-121/audit.mdis still the 4/10 file.spec.mdcites "audit rated LOW" x2 for NEW4-005/006 - findings that exist NOWHERE in the repo."I wrote every audit into COMMIT MESSAGES and then handed the findings to the next author through my prompt. Each author took my word for findings they could not open. An audit that is not persisted cannot be checked; a finding id that is misremembered or invented is indistinguishable from a real one. This is the exact pattern the whole session is about - an unverifiable claim accepted on authority - except it is one level above the three authors' and I was narrating the rule while committing it. Recorded here rather than quietly fixed. The audit files must be reconstructed from 7309cd80 / 15894b1e / this commit before any of these three specs is trusted."
Status: this file is that reconstruction (2026-07-18). It does not close NEW5-007 - the underlying process defect (audits authored into commit messages) is a workflow matter, and the information destroyed by it (§3, §5.3) is not recoverable by writing this file. What it does is make every id cited in spec.md resolve to a section, and make the unrecoverable parts legible as unrecoverable.
§5.5 - Required before re-audit (round 6's list)
- NEW5-001 - re-derive AC 2 against §1.2's widened three-item clause.
- NEW5-002 - reconcile §1.3's prune invariant with §1.5's mandated
prune:memory/store/; the build currently fails unconditionally. - NEW5-003 - AC 5's ninth deletion arm is not producible;
.install.lockis absent. - NEW5-004 - AC 15 is unsatisfiable while
version.sh:33-37forcesalways. - NEW5-006 - fix the
:199/:286-287citation.
Four clause edits, not a rewrite. Not promoted; no BACKLOG row.
§6 - ROUND 7: rewrite 6 NEW5 repairs - PASS 10/10
Audited 2026-07-25 (batch/12a). Four clause edits (plus AC 10 digest de-normativisation and __pycache__/*.pyc hash filter), not a rewrite of the architecture.
| Finding | Repair |
|---|---|
| NEW5-001 | AC 2 now asserts THREE §1.2 items: cone list, exclusion list, AND _rsha(). |
| NEW5-002 | §1.3 prune invariant: a prune that removes nothing fails UNLESS the prune path is absent from the tree (defensive prune:memory/store/ over payload); still fails if misspelt under an existing parent. |
| NEW5-003 | AC 5: if .install.lock is absent, fixture MUST create it under $CY before the deletion arm. |
| NEW5-004 | AC 15 / §1.15: tree may differ ONLY by .update-check-cache (including when version.sh forces always). |
| NEW5-006 | §1.5 gates.env.bak.* citation remeasured to creation at install.sh:369-370 (removal remains :267). |
| AC 10 / Success Metrics | Hardcoded digests and file counts removed as normative; expected fingerprint derived via fresh temp-install (§1.7). Historical four-combination table stays non-normative Problem/evidence prose. |
| Hash filter | _rules_cone_list / _rules_sha_of skip __pycache__/ and *.pyc (documented in §1.5). |
Verdict: PASS 10/10. Status → ready_to_implement then implement.