Skip to content

post-v2.7.19: pyrightconfig venv resolution fix - #743

Merged
AIOSAI merged 43 commits into
mainfrom
dev
Aug 28, 2026
Merged

post-v2.7.19: pyrightconfig venv resolution fix#743
AIOSAI merged 43 commits into
mainfrom
dev

Conversation

@AIOSAI

@AIOSAI AIOSAI commented Aug 24, 2026

Copy link
Copy Markdown
Owner

No description provided.

AIOSAI added 2 commits August 23, 2026 21:05
…ows. The site-packages extraPath spelled out .venv/lib/python3.12/... - a path that dies silently the day the venv rebuilds on another Python, same species as setup.sh's hand-written bootstrap list: a fact someone must remember to re-type. Replaced with venvPath+venv, which makes pyright resolve site-packages from the venv itself at whatever version it actually is. Also deleted the src/aipass/memory/.venv extraPath outright - that directory does not exist; a dead path in a config is a claim nobody is checking. Found tonight because Patrick's editor showed chromadb as a type error in a per-branch window: the root config never loads below the root, so the fix for HIM is open-at-repo-root or select the repo venv interpreter - but while proving the code was innocent (CLI pyright: 0 errors, chromadb 1.5.9 installed WITH py.typed) these two config lies surfaced. Verified after the change: memory storage handlers, devpulse apps, api modules - 0 errors, 0 warnings each. Selective commit on purpose: the tree carries @memory's live anchored-match dispatch and an unexplained TELEGRAM_PORT_MAP.md move, neither of which is this commit's to sweep.
…ite was a data-loss path (@memory's work, committed by devpulse). The symptom was a ranking oddity - DPLAN-0012 Hook Management pinning TDPLAN-0012 to the top at 100% - and the defect underneath was worse in exactly the way that matters: plan_label in source_file is an unanchored substring test, and DPLAN-0012 is a substring of TDPLAN-0012. FOUR sites carried it, not the three scoped. _check_plan and _get_by_source (both fetch), _pin_plan_id_matches (transitively through _get_by_source - its own _PLAN_ID_RE was already correct, the extraction was never broken, only the fetch), and the unnamed fourth: _delete_by_source, the IDENTICAL one-line predicate with DELETE behind it. delete_by_source DPLAN-0012 would have wiped TDPLAN-0012's vectors outright - no in-repo caller reaches it (JSON operation only), which is precisely why it would have been found by data loss and not by review. Fixed with its siblings; one site past the brief, flagged rather than smuggled. THE LIVE PROOF, against the real DB: DPLAN-0012 does not exist in the archive, and before the fix drone @memory verify DPLAN-0012 answered Vectorized (27 chunks) - all 27 borrowed from TDPLAN-0012. A verification door confirming a nonexistent plan on another plan's chunks means the coming 5000-plan sweep's failure mode was FALSE CONFIRMATIONS, not misses: the sweep would have under-reported the missing, which is the dangerous direction. After: DPLAN-0012 NOT vectorized, TDPLAN-0012 keeps its 27. The anchor is leading-only BY DESIGN: char before the label must not be alphanumeric, no trailing anchor because DPLAN-0012_watch is a legitimate prefix shape; the latent trailing variant needs 5-digit plan numbers, which do not exist below 10000. And it keys off the BOUNDARY, not the prefix list - so Patrick's pending TDPLAN/TPLAN naming ruling (todo 179) cannot re-open it either way; what would re-open it is a future prefix that is a suffix of another prefix, named here so nobody mints one. Behavior changes, stated not buried: empty pattern now matches NOTHING (was: every row - on the delete path that was a wipe-the-collection trigger); the two source-match operations are boundary match, not generic substring, and their docstrings now say so. Bar: 23 red-first tests (18 red before the fix, 2 deliberate regression guards), 5 mutations each caught by the right test including the rescan loop (a rejected first hit must not stop the scan - TDPLAN-0012_supersedes_DPLAN-0012 is a real shape), seedgo @memory 100%, branch suite 1109 passed / 5 skipped. chroma_subprocess.py 1.2.0 -> 1.3.0. Selective commit: the TELEGRAM_PORT_MAP.md move stays in the tree unexplained and unswept, awaiting Patrick.
AIOSAI added 27 commits August 24, 2026 08:49
…ver evidence of archive. Two halves of ONE bug, committed together because each is meaningless without the other. THE LOSS PATH: purge's _vectorize_emails shells out to @memory's chroma_subprocess with operation vectorize_and_store - an operation that DID NOT EXIST. The handler answers a bad request honestly on stdout (success:false, error: Unknown operation) and exits 0 BY DESIGN - the subprocess ran fine, it was the request that was wrong. purge tested only returncode != 0, so the refusal sailed past as success and _purge_files unlinked the originals it never archived. Four months of purged fleet mail, unrecoverable. ai_mail's half: parse the reply - unreadable stdout is not evidence of success (fail carrying the raw fragment), success:false is a refusal (fail carrying the handler's reason), and nothing is deleted on either. memory's half: chroma_subprocess.py 1.3.0 -> 1.4.0 grows the missing vectorize_and_store operation - text-in vectorization, callers hand texts+metadatas straight in. Bar: test_purge.py +4 red-first tests (TestVectorizationFailureIsNotSuccess: unknown-op-at-exit-0 is failure, nothing deleted on refusal, unparseable stdout is failure, a real success still succeeds), test_chroma_vectorize.py 10 tests on the new op - 25 passed together this morning. ai_mail README documents the seam. Rides along, explained not smuggled: TELEGRAM_PORT_MAP.md moves devpulse -> skills/lib/telegram (Patrick's move, 08-24 - the port map lives beside the skill it maps). Both fixes are their senders' work (@ai_mail, @memory), reviewed green by them, committed by devpulse.
…d, stamped fleet-wide and minted once at birth (Patrick's ruling 08-24, @Spawn's build, committed by devpulse). THE RULING: a passport's number must be UNIQUE per citizen. What passports carried was citizenship.registry_id - the id of the REGISTRY holding the citizen (AIPASS_REGISTRY metadata.id 7087bb93 for all 18 core, each project registry's own id for its citizens), correct as the branch-registry lock but shared BY DESIGN - and BAUD rendered it as Passport no., which is how a fleet audit briefly read as 18 duplicate passports. The unique per-citizen id existed all along in every registry's branches[] entries and simply never reached the passport file. THE BUILD: citizen_id stamped into all 23 live passports (passports are untracked - this commit carries the MACHINERY), copied from each citizen's own branches[] row, verified byte-identical elsewhere, idempotent re-run reports 23 correct / 0 to write. THE REAL WORK was where the id is MINTED: registries minted the citizen UUID in add_to_registry at create step 8 while the passport writes at step 1 - stamping from separate mints would issue TWO uuids per citizen, a passport number matching no registry row. The mint moved into _spawn_agent, one value feeds both writers; add_to_registry takes an optional citizen_id and mints only for adoption. Templates: both classes now stamp citizen_id: {{CITIZEN_ID}} at birth, template registries regenerated. Speakeasy skipped on principle - its registry has zero branches[] entries, so a stamp would fabricate provenance; Patrick ruled it stays legacy, TBD. Known and NOT fixed here, spawn greenlit separately: a brand-new external project's first citizen gets AIPass's registry credential because load_registry's default schema mints no id. Bar: tests/test_citizen_id.py new, 7 tests incl. mutation guards (aliasing CITIZEN_ID to REGISTRY_ID fails 5 by name), 495 passed / 1 skipped repo-root, seedgo @Spawn 100%. Spawn's prompt file-counts corrected (46/18 -> 50/17). BAUD renders the pair as Passport no. / Branch reg no. in its own repo.
…citizen's mailbox stops resolving into a phantom dir in OUR tree (@ai_mail's build, committed by devpulse). THE DEFECT: _lookup_branch_by_name correctly falls back to the caller's project registry for citizens absent from AIPASS_REGISTRY, but returned the RAW ROW - a path relative to the registry that holds it, with no memory of which registry answered. Every consumer joined it to the AIPass repo root, so BAUD (projects/baud, row src/baud/baud) resolved to <aipass>/src/baud/baud. Both measured symptoms were that one path: inbox printed empty against a store holding 4, reply refused an id read straight out of the file under his feet. THE BAD PART: it did not fail loudly, it FABRICATED - the wrong path is inside the AIPass tree, so writes silently succeeded. BAUD's answer to Patrick's continuity probe (papa26, dispatch 6f0a7109) was swallowed into the phantom at 20:13, status refused, seen by nobody. Reply is the ONLY sanctioned cross-project return lane, so the defect forced exactly the silent completion the house forbids - his answer only reached us because devpulse's feedback channel is a separate path. THE FIX, at the source not the nine call sites: _rooted() absolutises a row against its own registry in both lanes of _lookup_branch_by_name and both of get_branch_info_from_registry - rows leave the reader absolute, so the join-to-wrong-root question cannot be asked downstream. Rows already absolute pass through untouched. Three red-first tests, including a guard that an AIPass citizen with a relative row is unaffected (six of eighteen AIPass rows are relative - fixing the project lane by breaking the main one would trade a rare failure for the common one). ACCEPTANCE, live from BAUD's own seat, Patrick's bar: inbox lists all 5 including both timestamp formats (BAUD's own mixed-format suspect thereby refuted by evidence - the formats were real and were not the fault), the once-missing id resolves, and his reply arrived through ai_mail itself - the dead command, alive. Timestamp side note: devpulse's feedback module stops writing UTC ISO-T into ai_mail stores in the sibling commit; the existing ISO rows stay - ai_mail reads them fine, a rewrite of another citizen's store would be a migration, not a tidy. The phantom src/baud/ was removed via drone rm after content was preserved on the live lane. RIDER, explained not smuggled: purge.py's known-gap comment said @memory's vectorize_and_store DOES NOT EXIST - @memory shipped it this morning (chroma_subprocess 1.4.0, commit 660ab69), the seam is verified live from this side, and the comment now records the four-month history instead of asserting a gap that closed. README test counts 1323 -> 1326. Bar: 1326 passed from branch root (re-run independently by devpulse), fresh-checkout mimic green, winhome_sim green, seedgo 100%. NOT touched, flagged to Patrick: @daemon's inbox_sweep discovers candidates from AIPASS_REGISTRY only, so the fresh-wake self-healing that mints pointers for all 18 core citizens has never reached a projects/* citizen - whether they join the fleet sweep is a ruling, not a repair.
…d_registry mints metadata.id for a missing registry, and the mint-once ordering reaches the passport (@Spawn's build, greenlit 08-24, committed by devpulse). THE DEFECT, named in d0ce2ce and fixed here: load_registry's default schema minted no id, so a brand-new external project's first citizen fell back to whatever registry discovery found next - AIPass's own credential on a passport from a project it was never part of. THE FIX in registry.py: _default_registry_schema(credential) builds the empty document, and load_registry splits three ways - file MISSING means a NEW PROJECT and is born with str(uuid.uuid4()); file READS means the file, untouched; file UNREADABLE means an id-less schema plus a logger.warning naming the file. The asymmetry is deliberate and four tests hold it: a file that exists but will not parse is not a new project, it is a live project whose credential we failed to READ - minting a replacement would re-credential it and orphan every passport carrying the real id. Missing means regenerate; unreadable means never clobber. THE SECOND FILE was not scope creep, it was the fix reaching the passport: the passport writes at create step 1 and the registry at step 4, so resolving the credential at registration time hands the passport a value not yet minted - the live probe still leaked 7087bb93 after the registry.py change alone. _spawn_agent now resolves the credential at step 1 via load_registry and hands it to add_to_registry, which adopts it ONLY for a registry it is CREATING - keyed off registry_path.exists() captured BEFORE the load, not off id-already-set, because load_registry now always returns an id and the caller's would otherwise be shadowed into a two-mint disagreement (@Spawn built that bug, caught it by minting a real agent, and took it out - passport 53b58cb2 vs registry 35ed868d, one project two credentials, never shipped). PROOF, live mint in a clean probe: project registry metadata.id == passport registry_id, citizen_id == its own registry row, AIPass 7087bb93 leaked = False; probe removed via drone rm. Additive as scoped - no existing registry is read, written, or touched differently; AIPASS_REGISTRY still carries 7087bb93 and all 23 live passports still match, 23/23. Bar: tests/test_registry_credential.py new, 11 red-first tests with three mutations each caught by the right test by name; 506 passed / 1 skipped (re-run independently by devpulse); seedgo @Spawn 100%. FLAGGED NOT FIXED, awaiting Patrick's GO: add_to_registry against an EXISTS-but-unreadable registry receives the id-less empty schema, adds one branch, and would write that over the real file - every existing branch entry gone. Pre-existing, now precisely nameable: the empty schema is a legitimate return for two different situations and only one is safe to write back. The guard is a small separate fix with its own red-first tests.
…-mode rollback stops lifting a refusal outside its scope (@drone's build, committed by devpulse). THE PAGE THAT STARTED IT was not a fault: BAUD ran pr in projects/baud, cleared all four owner-tier authority checks, and hit the untranslated-verb wall - pr encodes our dev->PR->main flow and is not translated for external repos, so refusing is right. But verify_git_access logged EVERY owner-tier refusal at ERROR, designed ones included: the whole auth.log read 77 lines, 74 designed WARNINGs, 3 ERRORs, all three designed refusals - ERROR in that file had a 0% true-fault rate, which trains everyone to ignore the page. THE HOLE UNDERNEATH, severity medium and the reason this was more than a log-level nudge: AIPASS_GIT_AUTH_MODE=warn is the rollback for the AUTHORITY migration (F59 6.1), tested once against every refusal species - so it ALSO lifted the untranslated-verb refusal. Proven live before the fix: under warn mode, pr in BAUD's repo returned ALLOWED. A rollback scoped to ownership checks was silently re-arming a half-run of our merge flow inside someone else's repository; it requires a deliberate env var, but an ambient credential-shaped env var inherited by a process is exactly how that bites, and nobody would find it by reading the flag's name. THE FIX: authority refusals (not this repo's proven owner) stay ERROR and warn-mode lifts them - that is the switch's job; capability refusals (IS the proven owner, verb untranslated for this repo) log WARNING and warn-mode does NOT touch them. Message honesty corrected with it: a proven owner now reads 'cannot run pr in this repo', not 'is not authorized' - the old wording sent a manager with a clean passport off to audit a passport that was never the problem. Bar: 6 tests, 3 mutations each biting only its own test, 1200 passed / 5 skipped (re-run independently by devpulse), seedgo 34/34 files, branch audit 100%, 0 type errors, auth.py 1.0.1 -> 1.1.0. Deliberately NOT touched, policy not repair: which verbs get translated for external repos, and whether a non-manager's refusal keeps paging - both queued into the single untrack + external-repo-lane design session awaiting Patrick's ruling, tonight being the third incident in 48h of that one family.
…e host's dialect, and the changelog train section rides with the train it documents (devpulse's own lane). THE FIX: compose.py 1.3.1 - _deliver_to_ai_mail stamps ai_mail's canonical local format (%Y-%m-%d %H:%M:%S, their create.py and per-user timestamp_format) into recipients' inbox.json instead of UTC ISO-T. Found through BAUD's bug report (feedback e8c235f8): his store held two timestamp shapes, ai_mail's own beside this module's. Measured honestly on both sides before fixing: the mixed formats were NOT the cause of his dead inbox - that was ai_mail's relative-row resolution defect, fixed in 90d6723, and BAUD's post-fix listing returning all five messages with both formats intact refuted the parser theory by direct evidence. Real pollution regardless: a guest writing into another module's store writes in the HOST's format, not its own. The module's OWN feedback store keeps ISO - internal, unshared, its display reads it raw. Red-first test pins both properties: parses in the canonical shape (raises on ISO-T) and reads as local wall-clock, not a UTC stamp wearing local clothes - a UTC value in that format sits a whole offset from now, which is the quiet variant of the same lie. 70 feedback tests green. Existing ISO rows in baud's inbox.json left as-is: ai_mail reads them fine, and rewriting another citizen's store is a migration to be asked for, not a tidy to slip in. DOCS: CHANGELOG gains the post-v2.7.19 in-progress section carrying this train's five entries (ai_mail rooted rows, spawn credential mint, drone severity split, this fix, and the header restore), and the v2.7.17 section header is restored at its splice point - VERA's find (feedback 028e951f): the v2.7.18 merge glued the header's title mid-line onto a README paragraph, leaving GitHub tag v2.7.17 with no matching section, a released version vanished from the record. Kept the deliberate retitle (CI green campaign) over the 08-19 original (first green board) since the reword and the loss arrived in the same merge and only the loss was the accident. Header sequence verified 2.7.19/18/17/16. CONTEXT FOR THE TRAIN, one line each: the night started as Patrick's BAUD resume probe (cold resume PASSED - code word answered from continued context), detoured through the lane defect that had swallowed BAUD's first answer, and closed with the fix live-verified from BAUD's own seat before anything was committed - resolved and tested before commit, per Patrick's ruling.
…y their own citizens against the code as it exists, the 08-25 night shift (Patrick's GO before bed, executed solo on wake-backs). THE RULE: no guessing - view the actual code, run your real commands, and every number written tonight is a number measured tonight; what could not be verified is marked unverified IN the README rather than standing green. THE VERDICT: Patrick's distrust was justified everywhere - roughly 120 wrong claim families across 20 passes (16 core seats + devpulse self + the four resident projects in their own repos, uncommitted there for his review). HEADLINES: commons' README documented a Reward Drops mechanic (10% artifact chance on posting) that never existed in any code - the purest overclaim specimen; baud's README carried a false safety claim (26 commands listed as the complete backend surface while generate_handler! held 29 - three write-capable memory commands invisible to an attack-surface audit); aipass' own Quick Start told new users to run bare init, which prints help (the real verb is init run - the front door stranded its reader at step 1); and the spawn project_agent template ships contradictions to every child it mints: a --version its generated code never implements, a phantom system_logger name x3, an identical silent except-ImportError-continue at entry-point line 35 x3. THE PATTERN, held across all 20: docs rot BOTH directions - dead features documented live AND real features plus long-fixed debt still listed open. Both poison a post-reset agent equally, which is why this campaign was the precondition for DPLAN-0318's fleet memory reset: the announcement email will say current state + code = truth, and tonight makes that sentence true. DISCIPLINE HELD: docs-only - every code defect found (watchdog killed-or-True, warning-exit-0 family, commons help identity chain, git gate matching command TEXT inside heredoc content, the template trio) was flagged to its owner and queued, never smuggled into a docs commit; each branch edited only its own README + .trinity; every pass re-audited 100% after edits; seedgo readme gates green where a lane exists. The campaign log with all 20 reports, the code-fix queue, and the rulings Patrick owes rides in devpulse dropbox/readme_night_shift.md. Deliberately NOT in this commit: memory/templates/*.template.json (DPLAN-0318 live WIP with Patrick) and every project-repo file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ate's dialect - 495 test functions, 598 pytest cases. The campaign commit ac721b2 failed CI on exactly the defect @canary flagged HOURS EARLIER in the same campaign: seedgo's readme rule counts def test_ lines statically in test_*.py (495 here) while the README carried the honestly-MEASURED pytest number (598 cases - parametrization expands them; 594 passed, 4 skipped, run twice tonight). The gate regex \b(\d+)\s+tests?\b read '598 tests' as a 21% drift and failed the branch for reporting a true number - the same collision that bit canary (38 defs vs 48 cases) and forced @memory into wording gymnastics tonight. THE FIX is wording, not surrender: '495 test functions; pytest expands to 598 cases' states BOTH measured numbers - the gate parses the def-count claim it knows how to verify (0% drift), and the reader keeps the real suite size. Verified: seedgo @devpulse back to 100% overall, Readme + Readme_Quality both 100%. The rule itself (def-vs-case counting punishing parametrized suites) stays on Patrick's rulings queue for @seedgo - a gate that tells three branches in one night to replace measured numbers with smaller wrong ones is optimizing for its own regex, and that is a design question, not a hotfix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… - unique _usage per file, meta lines gain their semantics, health block deleted (DPLAN-0318, Patrick's line-by-line, 08-25 evening). THE TEMPLATES ARE THE STANDARD'S SEED: LOCAL.template.json and OBSERVATIONS.template.json are what every birth and the coming fleet reset stamp, so the agreed text lands here first. WHAT CHANGED: (1) _usage is now unique per file - local.json describes itself as the working draft (sessions = chronicle, key_learnings = transferable lessons, todos = sticky notes never rolled), observations.json as the memory of the USER (nontechnical, per-user, no cadence duty - patterns live for weeks). One generic blurb across both files is where semantic drift starts; a file that does not explain itself gets reinterpreted by every fresh agent. (2) Meta lines become PLACEHOLDER + semantics: the {{TODOS_META}}-style slot still receives the live-rendered caps tab from memory.config.json at birth, and a one-sentence meaning now rides beside it in the template - numbers config-owned, prose template-owned, agent reads the cap where it writes. (3) status.health + last_health_check DELETED, Patrick's ruling over the earlier make-it-real lean: the field had no consumer (hardcoded healthy since 2025-11 and nobody noticed), it stored a derivable fact - a second source of truth waiting to go stale, the exact disease the standard cures - and in a working system it always reads healthy anyway. Health becomes a checker-computed report value, never a stamp in the file. GOVERNING DOC: devpulse dropbox/trinity_pattern.md (seedgo standard format, drafted v1, stripped to pure standard v2 on Patrick's no-journey ruling, agreed tonight). NOT in this commit: the @memory machinery build (B1/B2/B4 measurement bugs, renderer reads templates instead of hardcoding text, refresh preserving the semantics prose, per-branch .template_version.json receipt, dead health stamping removal) and the @seedgo trinity checker - both dispatched as parallel builds referencing the standard; B3 (edit_gate fixed-field read) queues to @hooks. No fleet push rides this commit - existing branches are untouched until the gated, dry-run-first reset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rift pass silently are dead, and the standard's text machinery is live (@memory's build, DPLAN-0318, committed by devpulse). THE LAW ENCODED: a field the gate cannot measure is REFUSED loudly, never measured as zero - the old gate passed unparseable shapes as 0 chars, so the agents seen being corrected were the healthy ones. B1 (entry_limits 1.3.0): _extract_text returns str|None and check_entry refuses non-strings with reason unmeasurable + found_type. Deliberate grandfather, flagged not smuggled: only NEW or EDITED unmeasurable entries are refused - enforce is live and 9 branches carry legacy list-shaped notes, so refusing all would have bricked the fleet the fix protects; the coming reset wipes the legacy shapes anyway. B2 (lint_handler 1.1.0): the len()-on-a-list path is gone; lint prints UNMEASURABLE instead of a false 0/300. B4 WAS TWO FILES, the build's best catch: extractor floored excess at max(len-limit,1) while detector fired at >=, so fixing the extractor alone would have traded the settle-at-14 bug for a fleet-wide NOTHING-DRAINED skip loop - both moved together (extractor guards len<=limit, detector thresholds >= to >), with a boundary-sweep test pinning they never disagree again. RENDERER (tab_renderer 1.1.0): the hardcoded _CORRECTED_USAGE constants are retired - template_usage()/template_semantics() read the gold-source templates and RAISE on a missing template, no stale-string fallback; refresh rebuilds each *_meta as tab + template semantics, so only the brackets are replaced and the meaning survives every rollover. HEALTH: every writer gone per Patrick's delete ruling - memory_files.update_metadata deleted outright (its only job was the forbidden block), extractor's post-drain stamper gone, normalize no longer resurrects status, differ stops treating it as expected; source-scan tests pin the writers STAY gone. RECEIPT (receipt.py, new): per-branch .template_version.json writer with three sanctioned lanes only (push/birth/reset); push stamps only branches it actually changed and never on dry-run; bump_config_rendered refuses to CREATE a receipt - the renderer has no authority to claim a version it never wrote. Known and flagged, not hidden: the push lane targets the dead pre-.trinity layout, so the receipt ships mostly unwired until the pusher rebuild that rides the fleet-reset build; spawn's birth lane adopts the writer separately. Bar: 42 new red-first tests (test_trinity_standard.py), 13 mutations 12 caught + 1 provably-equivalent survivor, 1115 passed / 5 skipped re-run independently by devpulse from repo root, seedgo 100%, 0 type errors. README re-measured (1216 def-tests on disk, 1115 collected - both stated, per the truth-campaign convention). B3 (edit_gate fixed-field read) is @hooks' lane, dispatched separately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rogress train section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ing canonical field by NAME, never measures it as zero (@hooks' build, DPLAN-0318, committed by devpulse). THE LAST OF THE FOUR measurement bugs that let five months of memory-file drift pass silently: the char-cap check read a fixed field name per entry type, so a renamed field (learning in ai_mail/api/hooks) read an absent key, measured empty, and passed - how those branches went 2.7x over cap AFTER the June gate landed. edit_gate 1.5.0: _missing_field_violations reads container/kind/field from @memory's entry_limits config and refuses any NEW or EDITED entry whose canonical field is absent, named in the refusal with the rename instruction ('no value field - cannot be measured against its 200-char cap. Rename the field to value'). THE ASYMMETRY, deliberate and mutation-pinned: exemption keys on RAW-ENTRY identity, byte-for-byte on disk - untouched legacy passes, edit it and you own its shape, and a NEW entry in the drifted shape is REFUSED even though fourteen legacy siblings sit beside it, because keying on the field name would mean one legacy entry licenses ten more (mutation M5 does exactly that; two tests bite it - and @hooks corrected its own first M5 run that falsely reported survived: the sed had missed, re-run properly, bites). SECOND DEFECT fixed en route, same law: @memory's unmeasurable refusals were rendering through the over-cap formatter as '0/300 chars (+0)' - a refusal printing as a zero-length measurement that reads like a gate bug; now renders 'unmeasurable - expected a string, found list'. LIVE-PROVEN against hooks' own real local.json (the actual learning-shape specimen) with enforce=True: unchanged rewrite ALLOWED, new drifted entry REFUSED naming value, new canonical entry ALLOWED. Bar: 7 red-first tests (both dodges FAILED on current code first: renamed 500-char entry was ALLOWED, missing field was ALLOWED), 3 over-refusal guards green before AND after by design, 5 mutations each biting only its own tests, 1688 passed / 2 skipped re-run independently by devpulse, all 45 code standards 100%, 0 type errors. FLAGGED NOT CLOSED, the seam @hooks found and routed correctly: the dodge ORIGINATES in @memory's _extract_text, which still returns empty string for a MISSING field (1.3.0 fixed only non-string) - so @memory's own write path (memory_files.py:116) still dodges while this commit closes the Edit/Write lane. Half a fix, said plainly in the report; @memory holds the dispatch with the repro. KNOWN CONSEQUENCE for the fleet-reset announcement: hooks, ai_mail and api now get refusals on NEW learning-shaped key_learnings - the fix working as specified; the refusal text teaches the rename. Trinity checker footnote: hooks' own audit already shows the NEW Trinity standard at 68%, flagging exactly its 14 legacy entries - B3's footprint confirmed from the checker's side; the cure for that number is the reset, not code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he standards family and the fleet has its first honest memory-file scores (@seedgo's build, DPLAN-0318, committed by devpulse). THE TRIPLET: trinity_check.py (branch_level, NO bypass by design - per-branch differences live in @memory's config, not bypass files), trinity_content.py (query surface), trinity.md (the contract graduated verbatim from devpulse's draft), test_trinity_check.py (125 tests). RED-FIRST ACCEPTANCE HIT EXACTLY: clean-on-observations = 6 of 18 - aipass, backup, canary, devpulse, hooks, memory - precisely the MASTER_LIST six, not five, not seven, all 12 deviants flagged; the set is asserted as a LIVE test against the real .trinity files that must be UPDATED as branches migrate, never loosened. FLEET SCORES tonight: memory 100 (migrated its own files), then 84 down to ai_mail 52, fleet avg 72% - trinity is now the fleet's lowest-scoring standard, which is the point: the number is finally telling the truth the June gate could not see. THE BUG THAT MATTERED, worth every reader's minute: the checker's own first draft broke THE ONE LAW it enforces - _records_check dropped violation records when the entry denominator came out clean, so 'cannot measure: config has no spec' over an EMPTY container scored 100 - a silent pass of an unmeasurable, inside the standard written to end exactly that. The test agent exposed it as strict xfail and did NOT patch it; seedgo fixed the engine (records decide WHETHER, the denominator only decides HOW BAD) and flipped the xfail into a named regression guard. The failure mode is not hard to write - it is the DEFAULT one. Second catch: within an hour the Ordering rule flagged its own author's reversed key_learnings insert from a prior session - the checker caught its builder first. CROSS-LANE CONVERGENCE PINNED: seedgo's expected_meta_line and @memory's compose_meta were written blind to each other and produce byte-identical output, 16/16 across 4 sections x 4 casings - two implementations, one output, held by a test so they cannot drift. HONEST DEVIATIONS, flagged not smuggled: receipt gold-source version compares schema_version (the only field reproducing the contract example - dispatched to @memory for confirmation); guidelines CONTENT not scored (contract ambiguity, every branch differs today - needs a ruling); document_metadata not enforced as a closed set (contract never says 'and nothing else'); number gaps allowed (a read-only checker cannot tell a gap from an archived rollover). RULES FLAGGED AS POSSIBLY WRONG, for Patrick not silently softened: managed_by casing fails 8 internally-consistent branches on a convention nobody wrote down (isolated in one function if the ruling is 'agrees across own files'); and the canonical session shape's 300-char summary cannot hold what sessions actually carry - seedgo's 96 findings[] entries are where its session evidence lives, so the standard should say where real reasoning GOES rather than leave each branch to invent a field. Seedgo deliberately did NOT migrate its own drifted files (scores 71 and stays there): the lossy items are exactly Patrick's open rulings and healing ahead of a ruling bakes in a guessed answer - it will not migrate under its own gun to report a rounder number. Only the status block was removed, executing the already-made ruling. ENGINE DEFECT QUEUED, not smuggled: the incremental audit cache hashes only apps/*.py, so branch_level checkers whose inputs live OUTSIDE apps/ serve stale scores (trinity is the first, json_handler_check has the same exposure) - an audit-engine change with fleet blast radius, its own decision. KNOWN XFAIL SHIPPED: tab_renderer ignores entry_limits per_branch overrides, so any future override diverges rendered vs expected meta lines - reported to @memory, pinned as strict xfail until their fix. Bar: 1836 passed + 1 xfail re-run independently by devpulse, 25 mutations each biting the test written for its rule (a broad-biting first attempt was REPLACED, not accepted), 0 type errors, both new files checklist-green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…in section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…econd half dead, the gate dedupe, and Patrick's first four trinity rulings landed (DPLAN-0318, committed by devpulse). MEMORY entry_limits 1.4.0 + lint_handler 1.2.0 + lint 1.1.0: the missing-field hole @hooks proved is CLOSED - an ABSENT canonical field returns None like any other unreadable payload and refuses with its own reason=missing_field naming the field (present-and-empty still answers '' and stays compliant - the repair differs: rename a key vs fix a shape). Fleet impact measured read-only: 42 missing_field violations invisible until now, all learning-shape key_learnings on hooks/ai_mail/api (14 each), grandfathered until the fleet push like B1. This retires 8d31a64's 'memory_files.py:116 still dodges' - true when written, closed within the hour, raised by @hooks not edited into history. Lint's boundary REVERSED on the way: it had documented missing-field as 'the trinity checker's question' - wrong, the write gate refuses those entries, so lint would call a branch compliant that blocks on its next write. ALSO memory: tab_renderer's per_branch blindness fixed - render_tab and the write gate now share ONE resolver, so @seedgo's strict-xfail flipped to a plain pass and the marker is retired in the same commit (the cross-lane pin working exactly as designed: their test, memory's fix, no coordination meeting); devpulse removed one dead base_types assignment the refactor left behind (ruff F841, caught by the commit gate). HOOKS edit_gate 1.5.1: with both missing-field checks live the same entry printed twice - _dedupe_violations() keyed (entry_type, container, key), first record wins so @memory's richer record survives; the OVERLAP itself is kept deliberately - a gate that outsources all measurement inherits its supplier's blind spots silently, which is precisely how the renamed-field read survived two months; union = strictly more refusals, never fewer. SEEDGO trinity.md: Patrick's session-shape ruling graduated verbatim (byte-identical block, anchored insert, no retype) - the shape stays CLOSED, no new field: summary is the headline; transferable lessons go to key_learnings; the depth lives in @memory vectors via rollover, recalled with drone @memory search; tags are the findability hook. Rulings 2-4 also closed this morning: managed_by EXACT casing, guidelines template-verbatim, document_metadata CLOSED set - all recorded in the DPLAN, all baked into the coming push build. THE 23:37 MYSTERY RESOLVED with an honest correction from @memory: nobody pushed - @aipass's genuine 16/15 rollover (fired by a PreCompact hook) reached rollover_execute's refresh_all_tabs, which walks the REGISTRY and rewrote all 38 files with the just-shipped template prose. Standing risk named: ANY citizen's compaction can propagate renderer changes fleet-wide ahead of a gated dry-run - scoping refresh_all_tabs to the rolled branch goes in the push build brief. Bar: memory + hooks + trinity-checker suites re-run TOGETHER by devpulse before committing - 2948 passed, 7 skipped, 0 failures, no xfails left in the trinity file. CHANGELOG carries the round.
…ne lane, gated, the fleet's cure ready for Patrick's GO (@memory's build, DPLAN-0318, committed by devpulse). THE THREE PARTS per branch: re-render the machine frame (closed metadata set, exact-casing managed_by, template-verbatim _usage/guidelines, re-composed meta lines); PRUNE every non-canonical entry - vectorize VERBATIM, read back BY ID and compare byte-for-byte, only then prune, verification failure = NOTHING pruned and the file left as found; write ONE canonical session entry in the pruned branch's own chronicle naming where its memories went. THE ORDER IS THE LAW: store and read-back are two SEPARATE subprocess round-trips so the second cannot answer from the first's return value; needed a new primitive (chroma_subprocess 1.5.0 get_by_ids) because get_by_source substring-matches and caps at n_results, so a partial hit reads like a full one. Six failure shapes pinned, and absent-vs-corrupted vectors produce DIFFERENT refusal sentences - the missing_field lesson wearing its third hat. CANARY LIVE end to end: 15 pruned, 25 carried, trinity 77 to 100, receipt stamped, then the note's promise TESTED not assumed - drone @memory search --branch canary returns pruned key_learning 30 verbatim; re-run prunes 0 and holds 100, idempotent; dry-run proven to write zero bytes via git. FLEET DRY-RUN, the artifact Patrick reads: 366 entries to archive, 560 carry over, 22 branches, 0 refused, 0 errors, with a MEASURED projection - the push applied into temp copies of each branch's REAL .trinity and scored by seedgo's own checker, not an estimate: fleet avg 70.1 to 97.2. SCOPE RESOLVED ITSELF and it mattered: the registry lane reaches only 19 of 22 (earmark, finch, aipass_site invisible to rollover/lint/health today - flagged); the push uses a NAMED CONSTANT of four resident registries, never a glob - a glob over projects/ would have swept in marketstand, active-flagged inside a directory literally named on-hold. ONE SPECIES WIDENED, checked not smuggled: over-cap entries prune like any other (shape and size are different scan groups - a perfectly shaped 315-char summary held canary at 99), measured through the SAME resolver the write gate and renderer use; the edit_gate grandfather clauses stay until post-fleet cleanup as briefed. R-SCOPE-REFRESH DONE: refresh_all_tabs(branches=...) scoped to what rollover actually rolled - no citizen's PreCompact can propagate renderer changes fleet-wide ahead of a gated push anymore; sync-lines KEEPS the unscoped call deliberately (explicit operator verb, asymmetry on the record). ALSO: the bare 'drone @memory push' alias that once fired an unprompted fleet-wide config reset is DEAD - push now means the trinity push, its fleet lane REFUSES without --confirm, and a source-scan test fails if the alias returns. REMAINING BLOCKER named honestly, needs Patrick's ruling not code: 16 branches carry stray .trinity files (pre_v3 backups etc) and 6 lack .trinity/README.md - deleting citizens' files and authoring their prose are outside the push mandate, so both are REPORTED per branch and left alone; with that ruling executed the fleet hits 100 across the board. Bar: 69 new tests, 1201 passed / 5 skipped, 10/10 mutations bite (the one first-pass survivor became two diagnostic-distinctness tests instead of a booked equivalence), seedgo 100 percent on every standard including trinity, 0 type errors, all four first-audit findings FIXED not bypassed, and the strongest pin runs seedgo's real checker over pushed output requiring all nine groups at 100 - re-verified independently by devpulse: 1326 passed across memory + checker suites. Canary already cured; fleet run awaits Patrick's GO on the dry-run report.
…- versioned backups are citizens' history, not strays, and every branch gets the same trinity README (DPLAN-0318, Patrick's rulings, committed by devpulse). SEEDGO: is_versioned_backup(name) - a versioned backup is canonical-name.pre<sep><token>, sep dash or underscore, token dotless alphanumeric-first. Anchored on 'pre' because that is what the convention MEANS (what the file was before the migration), matching the SHAPE not a suffix list so the next migration's token needs no code change. THE HALF WORTH THE RECORD: widening an allow-rule fails toward BLINDNESS, not noise - 'canonical plus any suffix' would admit local.json.tmp and make torn-write staging files invisible in the one directory whose entire job is durable memory (the 4.3MB truncated tmp specimen from session 90 is the live argument); so the token takes no dots, and versioning a stray does not launder it (STATUS.local.md.pre_v3_backup still flags). Fleet measured old rule vs new on one snapshot: 38 strays to 4, the survivors EXACTLY the four deliberately-still-flagged operational files, zero collateral. Contract and graduated trinity.md carry the new File set wording byte-identical (seedgo edited the contract directly, invited). Seedgo also relocated its own five-months-stale STATUS.local.md to .archive and confirmed the spawn template registry entry naming it is a dead record not a live template. Red-first exactly where the rule changed: 10 tests failed on old code, 23 over-refusal guards passed before AND after by design, 6/6 mutations bite, trinity suite 125 to 166, full suite 1878 (devpulse re-ran independently: one transient failure in a live-dir orphan-scan test that raced spawn's concurrent backfill, re-passes 2/2 - flake noted, not a defect). SPAWN: one generic .trinity/README.md, 1885 bytes, md5 85f13010, byte-identical everywhere - added to BOTH scaffold classes (aipass_framework REPLACED its branchname-placeholder version; project_agent gets it NEW, 17 to 18 files, both registries regenerated) and backfilled to the 6 missing: devpulse, prax, and all four resident projects (paths confirmed against @memory's survey before writing; aipass-site hyphen noted). Content by the ruling: no numbers, no branch names, no shapes restated - the three files and their roles, machine-owned frame vs hand-written memories, caps live in the meta lines rendered from config, rollover means absence locally is not absence, todos never roll, one pointer to the standard (verified it resolves before publishing). THE MANDATE CHECK done BEFORE writing: passports surveyed fleet-wide, no citizen is class project_agent, so the new template file red-boards nobody - learning 70 applied, measured not assumed; CI gate confirms zero Missing-file violations anywhere. Spawn's survey also settled the base beyond argument: 12 of 16 existing READMEs byte-identical modulo branch name, 4 outliers (flow's is literally 'README.md placeholder', api's hardcodes a cap number - exactly the staleness the ruling forbids) - those get the same generic file in the follow-up copy already dispatched. 506 passed, all standards 100, live-minted both classes into a temp tree and read the newborns' files off disk. Fleet board after this round, none of it code: 16 of 18 at 98-99, only trinity CONTENT remaining - receipts, list-notes, renamed fields, status blocks - exactly what the fleet push cures, GO given, firing next.
…ft cured in one gated morning (DPLAN-0318 the trinity pattern, Patrick's GO, committed by devpulse). THE RUN: 22 of 22 branches - 18 core citizens plus baud, earmark, finch, aipass_site - pushed through @memory's one-lane machinery: machine frame re-rendered (closed metadata, exact casing, template-verbatim prose, config-rendered meta lines), ~366 non-canonical entries vectorized VERBATIM, read back BY ID, byte-compared, and only then pruned (0 refusals, every pruned memory recallable forever via drone @memory search), 563 canonical entries carried untouched, receipts stamped in every branch, and a canonical session note written into each pruned branch's own chronicle telling the agent where its memories went. THE TIMEOUT STORY, kept honest: the first fire died at drone's 60s default mid-alphabet; all fleet JSON parsed clean (no torn writes - atomic files doing their job) and the re-fire with --drone-timeout 900 pruned 0 on the already-cured branches, which is the canary idempotency proof holding in anger on live citizens. THE SENTENCE OF THE NIGHT, from seedgo's live acceptance guard, which now SKIPS ITSELF: 'no drifted citizens on disk - live-state guard skipped'. The exact-set test that spent the build night asserting six clean citizens now asserts all eighteen - _CANONICAL_OBSERVATION_BRANCHES flipped in the same working set, 165 trinity tests green against the pushed fleet. FULL FRESH AUDIT (--full, cache bypassed per the known engine defect): trinity 100 on 20 of 22, fleet trinity avg 99, and the only two below are the two deliberately-flagged operational strays whose relocation is owned work - daemon 98 (.recovery/) and devpulse 97 (watchdog_active.json pair, my todo 190); EVERY other standard 100 percent fleet-wide, 0 type errors. THE README SPECIES CLOSED the same hour: all 22 .trinity/README.md byte-identical at md5 85f13010 - spawn's 4-outlier copy surfaced the correction that mattered (a template edit reaches NEWBORNS only: .trinity/ sits in update's NEVER_UPDATE prefixes by design, so 12 living branches still carried the old named text until an explicit fleet copy, authorized under the same ruling and verified by devpulse's own md5 sweep). WHAT THIS MORNING ACTUALLY WAS, for the record: the June gate measured what it could not see and passed five months of silent drift; the trinity pattern rebuilt measurement from the law up - a field you cannot measure is refused, never zeroed - and then cured the patient it diagnosed. Announcement email to the fleet rides this commit. Remaining owned work, none of it blocking: two operational-stray relocations, the grandfather-clause cleanup post-green, rulings 6-7 (audit-cache engine defect - worked around here with --full; sync-lines verb), and the resident-registry gap (earmark, finch, aipass_site invisible to rollover/lint/health - @memory's lane).
…ad within the hour of its discovery (memory 1.1.0, spawn's catch, DPLAN-0318 aftercare, committed by devpulse). THE DEFECT spawn found by living it: the fleet push pruned non-canonical todos to vectors like any drifted entry - archive-side perfect, verbatim recall verified - but a todo in a vector never resurfaces on load, so the one species whose whole job is resurfacing was being silently forgotten; 'todos never roll' must outrank the shape rule. THE FIX, and the refusal that shapes it: mechanical reshape was considered and REFUSED on the module's own law - canonical needs priority AND status, and a machine that invents someone else's priority has rewritten their open work, not rescued it. So todos are exempt from the prune lane entirely (RESHAPE_ONLY_SECTIONS): a non-canonical todo stays BYTE-IDENTICAL in the file and is reported per entry, uncapped - unlike prune samples which cap at 6 - because the report is the only place left-behind work is named; carried[] deliberately does NOT count them, calling a debt clean being exactly how it goes unseen. Deliberate deviation, flagged in the report not smuggled: the in-file note names todos only when something was actually archived - a reshape-only branch mints no note, because a note-per-run would stack a session entry on every push and break the proven idempotency; the REPORT says it every time. THE SWEEP, measured from ground truth: blast radius read from the vectors' own archived_by=trinity_push stamps rather than the push reports, because the reports undercount - the first 60s-timeout-killed fire had already cured backup/canary/commons/daemon (46 entries) before dying. Total 388 archived; TODOS: 67 across 8 branches - baud 41, ai_mail 10, hooks 7, spawn 3, aipass_site 3, drone/aipass/earmark 1 each - and @aipass's single one was perfectly SHAPED, pruned purely on 153>150 chars. Every affected branch mailed its own todos QUOTED IN FULL with per-entry reason and a verified recovery command; baud, aipass_site and earmark were refused by the fleet-to-project replies-only ruling (DPLAN-0288) and went out through devpulse's verified-admin lane instead, from memory's prepared bodies. Also for the record, 10 of 22 branches now legitimately sit at 0 observations (all list-shaped, all in vectors) and 6 at 0 key_learnings - the next audit reader should not be alarmed. LIVE PROOF replayed spawn's exact incident against a temp copy and throwaway chroma: 1 session pruned, 3 todos left byte-identical, note written 266/300 naming all three. THE MUTATION WORTH THE FIX: cutting the resolved cap from the build_note call survived all 12 unit pins (they hand the cap in themselves) - only end-to-end did it bite: no cap, the enumeration busts 300, the canonical-note guard refuses the note, and the branch is told NOTHING about entries that really did move; test_the_written_note_fits_the_branchs_own_cap_end_to_end now exists and bites. Bar: 13 new tests (12 red-first), 8/8 mutations bite, 1214 passed / 5 skipped both rootdirs, seedgo 100 percent incl trinity, 0 type errors, memory's own .trinity re-scored 100 - re-verified independently by devpulse: 1379 passed across memory + trinity checker. The stated cost is the right trade: a branch carrying a drifted todo does not reach trinity 100 until its own agent reshapes it - a debt visible and non-canonical beats a debt canonical and gone. Meanwhile @api dispatched on Patrick's ruling: host-api must survive reboots (baud's phone face died with it this morning - log shows external kill, no crash; hand-restarted at 12:12).
… ruling executed on my own house (DPLAN-0318 circle close, Patrick's GO). watchdog_active.json + lock and watchdog_timers.json now live in a dedicated .watchdog/ dot-dir (gitignored): .trinity/ holds identity and memory only, operational state gets its own home - the same ruling daemon executes next for .recovery. registry.py + timer.py default resolvers changed (tests unaffected by design - they pass explicit paths), the statusline reader repointed (untracked ~/.claude file, noted in todo 174), live wire re-armed on the new path and verified writing there, one zero-byte fossil lock archived not deleted. 99 watchdog tests green, checklist 34/34, fresh --full audit: devpulse trinity 100, overall 100 - 21 of 22 branches now at trinity 100, daemon queued. Rides with the circle-close round: @seedgo dispatched (marker 7 report-to-gate flip + ruling 6 audit-cache + closed-set flagging + guidelines scoring), the rest of the queue staged on wake-backs.
…ely NOT a home-grown supervisor (@api's build, Patrick's ruling after the morning baud outage, committed by devpulse). THE SHAPE and the scar behind it: the fourteen death-and-restart cycles baud read out of a pane on 08-19 CAME FROM a supervisor - a typed shell loop; a daemon check-and-start entry would be that second home-grown supervisor with better manners, polling-granularity crash detection, no boot ordering, and it would have to reimplement the one rule this lane cannot get wrong (never restart what an operator deliberately stopped). systemd already owns boot and already knows that rule - so autostart.py supervises NOTHING: renders a unit, answers whether the supervisor holds the server, asks it to stop. TWO SILENT FAILURES fixed as the real work: status was lying BY CONSTRUCTION (a unit-managed server writes no record file and running() only read the record, so a healthy server reported no-server-running at exactly the moment the answer mattered - it asks the supervisor FIRST now, stale records cannot outrank the live process, every record carries an owner, and the bind is read from the unit's own ExecStart never from stored config); stop routed a supervised stop through systemctl --user stop (a SIGTERM is a stop the restart policy may undo) and RE-CHECKS the pid rather than trusting the accept - supervisor-accepted and process-gone are two facts. UNIT DETAILS, each an avoided no-op: append: logging because file: truncates and the first restart after an outage would destroy the outage's evidence; Restart=on-failure never always so a cleanly refused bind stays refused; StartLimit* under [Unit] because systemd v230+ silently IGNORES the [Service] spelling - a rate limit in the wrong section is an absence wearing a config's clothes; the retry window deliberately wide (60x5s) because at boot the tailnet bind may precede tailscaled's address assignment, and that failure is indistinguishable from a fatal misconfig. One argv function feeds both serve --detach and the unit so the copy nobody re-reads cannot drift. The rendered unit stays gitignored in logs/ - it carries machine-absolute paths and a bind address; committed it is either a hardcoded path or somebody else's broken install. INSTALLED LIVE by devpulse: hand-started 177102 stopped first (the port-conflict trap the command itself warns about), unit enabled with linger, pid 227641 now systemd-owned, tailnet answering 200, restart on failure AND at boot - baud's phone face is reboot-proof. HONEST MISSES kept: @api fired its mutation harness and full suite concurrently so the suite read mutated source (3 false failures, re-run clean - third way its harness has lied to it, banked as a learning); red-first done as a mutation pass not reverts since agents have no git, stated plainly. Also made the 23 existing lifetime tests hermetic - running() now shells out to systemctl so unpatched they would depend on whether the suite machine happens to be serving. Bar: 1579 to 1611 tests, re-run independently by devpulse (1611 passed), seedgo 100 percent on all 46 standards, 0 type errors, 10/10 mutations bite, five first-cut seedgo findings fixed not bypassed, systemd-analyze verify zero warnings.
…, and the cache that stopped serving stale scores (@seedgo's build, DPLAN-0318 circle close, Patrick's GO, committed by devpulse). ITEM 1 PREMISE CORRECTED, measured not performed: trinity has been a GATE since it shipped - non-ADVISORY (counts in the gating average), passed only at score 100 (stricter than the json_handler precedent which passes at 75), failing groups lifted into failed_checks; proved live with a violating branch (17, False, 8 of 9 groups). Nothing to flip, so nothing was invented - instead 6 regression pins hold each gate property INDIVIDUALLY (any one could be lost alone), including a source-level pin that ADVISORY still means non-gating and one that the gate is SATISFIABLE, because a gate nobody can pass is a wall. ITEM 2, ruling 6 dead and the live proof caught the builder's own bug: the cache fix is DECLARATIVE - a branch_level checker states its inputs as globs with {branch} substituted (trinity declares .trinity/*), so a new checker gets invalidation by declaring, no cache edit. First cut declared json_handler's json files as CONTENT inputs and the real tree came back dirty on EVERY run - the checkers' own *_log.json are written DURING the audit, the audit disturbing what it measures; an always-dirty cache is a DISABLED one, worse than the stale-score bug being fixed. Split into two channels named for what they mean: BRANCH_INPUTS (content matters - trinity) vs BRANCH_INPUT_NAMES (presence only - json_handler scores which filenames EXIST and never reads a byte), the latter fingerprinted so add/delete still busts while content churn stays invisible. Live-verified three ways on the real tree; watch set 581 files, .trinity now covered. ITEM 3: document_metadata extras flagged BY NAME (ruling 4 closed set), and status KEEPS its separate diagnostic rather than folding into generic-unexpected-field because that line tells the agent WHY it is deleted - a mutation proved the distinction load-bearing. ITEM 4: guidelines content byte-compared against the gold template in the Meta lines group; unreadable gold REFUSES rather than scoring zero, the One Law's fourth hat. CALIBRATION SAID HONESTLY: the live population for items 3-4 is ZERO because the push cured the fleet before the rules shipped - so the pre-push state still sitting in *.pre_v3_backup served as the deviant corpus (34 files carrying limits/status extras; 17 branches whose guidelines had the right two keys with DIFFERENT text - exactly why presence-only scoring saw nothing for months). Preventive not curative, and the report says so rather than letting a zero read as proof. FLEET RE-MEASURED: 17 of 18 at 100, avg 99, only daemon 98 on File set (.recovery relocation queued with them); items 3-4 cost zero branches a point. MUTATIONS: 12/12 bite; the 3 first-pass survivors were real test gaps not equivalences - best catch: the guidelines refusal guard was SHADOWED by the prose guard, only reachable by a template that parses but lacks the guidelines block; that test now exists. One mutation run was killed mid-flight leaving a mutant on disk - harness re-run with restore in a finally, both sources verified byte-identical after. CROSS-LANE: answered @memory's todo-exemption question mid-build - no pushed-branch-scores-100 assumption in the suite, and the forward case confirmed live (pushed canary + drifted todo = 92, blocked, four groups naming it). Bar: 1911 passed / 1 skipped re-run independently by devpulse (the skip is the live-state guard reporting no drifted citizens on disk), trinity suite 166 to 189, audit 100 on EVERY standard including ruff - seedgo's first clean-across-the-board audit - 0 type errors, checklist green x4.
…and the outage died one line short of the bug it was hiding (@memory's build, DPLAN-0318 circle close, Patrick's GO, committed by devpulse). THE FIND OF THE BUILD, surfaced by the wifi outage's single red test: _announce_bump built its payload with json.dumps and templates.py NEVER IMPORTED json - a NameError raised inside a best-effort try, swallowed by except Exception, logged as 'Event bus unavailable'. The bump announced NOTHING, ever, and the log blamed the environment. Proved live against a fake bus before fixing (only 'startup' came back), then fixed BOTH ways: json imported, and the catch SPLIT - ImportError stays bus-unavailable (an environment fact), everything else logs the failure at ERROR with traceback, because one catch was making a bug wear the environment's clothes. End-to-end pin through the real path; drop-the-import mutation bites. THE SEVEN ITEMS, all verified live on the real tree: (1) templates bump FIRES the trinity push - dry-run default, --confirm executes, and only a push that ACTUALLY succeeded stamps the fleet ledger; (2) rollover normalizes the rolled branch on touch - proved on a throwaway .trinity copy (managed_by casing healed, bogus metadata key gone, meta line restored, entries BYTE-IDENTICAL, sibling untouched) then exercised for real twice; (3) the dead pre-trinity pusher/differ lane RETIRED to the archive with its 67 tests and the measurement written down - both old verbs refuse and name the live lane; (4) ruling 5 CONFIRMED no change needed either side: schema_version IS the field, receipt.template_versions() raises rather than defaults, checker and writer read the same key; (5) sync-lines RENAMED report-lines, old name still routes and explains - genuinely read-only now, the fleet-wide refresh_all_tabs is GONE from it not renamed around; (6) grandfather clauses NARROWED to todos only - RESHAPE_ONLY_SECTIONS is one list shared by the write gate and the push, over-cap is a violation everywhere else regardless of which write made it; (7) the fleet defined ONCE - registry_scope.py names the four residents, detector reads it, report-lines now sees 44 files where it saw 38 - earmark/finch/aipass_site finally visible to monitor/report. BEYOND THE BRIEF, both honest: @ai_mail's fenced suggestion built - push reports now ALWAYS state todos ('N seen, M to reshape in place') because 'owes nothing' and 'open work gone' rendering identically is the exact silence that hid 67 archived todos this morning; and a FOSSIL killed - templates/.template_version.json was the retired pusher's own ledger (last_push June, sixteen UPPERCASE names, no version field), moved to the dead-lane archive and pinned against that shape, because a fossil in templates/ reads to a human as a live ledger with a stale date. CONSEQUENCE ON RECORD: template-status now says BUMP PENDING while every branch reads current - both true (22/22 carry 3.0.0 by their own receipts; no push has yet run THROUGH the bump lane to stamp a fleet ledger). The first 'templates bump --confirm' is a fleet-wide write and @memory correctly did NOT take it - it awaits a GO. Two seedgo findings on its own build fixed not bypassed (no-args gate back at the entry seam; handle_command flattened from nesting 5 to flat if/return). One pre-existing divergence REPORTED not silently fixed: checklist flags test_trinity_push.py naming/windows_compat that the branch audit passes at 100 - a checklist-vs-audit ruling for later. Bar: 1224 passed / 5 skipped from repo root (re-run independently by devpulse: 1225 passed), seedgo --full 100 percent overall including trinity, 0 type errors, checklist clean on touched files, 4/4 new-behaviour mutations bite, README truth-passed including the honest 'nothing listens for trinity_template_bumped yet'.
…iguity warning learns what a credential is (@ai_mail's build, DPLAN-0318 circle close, devpulse's ruling under Patrick's GO, committed by devpulse). ITEM 1: behind the DPLAN-0288 five-leg verification ONLY, resolve_broadcast_targets() adds the four resident projects to @ALL - live-proven both ways (18 targets from an ungranted seat, 4 residents resolving to correct absolute paths). THE DRIFT CAUGHT BY THE BRIEF'S OWN INSTRUCTION (match @memory, do not import): the existing admin lane's get_project_tree_branches() GLOBS projects/*/*_REGISTRY.json and answers SIX projects - it would have broadcast into marketstand and speakeasy, both on-hold, on the strength of a stale ACTIVE flag in marketstand's registry; wider than ruled, silently. So @ALL uses a NAMED constant RESIDENT_REGISTRIES mirroring @memory's registry_scope byte for byte - copy not import, because @ALL must not acquire a runtime dependency on another branch to know who it talks to - with an ast-parsing test that goes red on drift, the surfacing the brief asked for. THE DISTINCTION KEPT ON THE RECORD: resolution scope and broadcast scope are different questions - a held project's citizen legitimately HAS an address, so the resolver still answers for it; being reachable is not being on the announcement list. Whether resolution should ALSO stop at held projects is a new ruling, banked not taken. Non-admin @ALL unchanged; a verifier that RAISES returns fleet-only rather than falling open; residents already in core are not added twice - one inbox, one copy. ITEM 2 with the premise corrected by reading ALL 104 occurrences: the warning was not dispatch monitors - every single one is CALLER_BRANCH ai_mail with cwd walking a different branch, a fleet sweep from ai_mail's own process. The class held (env var right, cwd elsewhere), the mechanism did not, and the wrong cause suggests the wrong discriminator: gating on 'resolution succeeded' would ALSO have silenced the .41 wake, where drone stamped a project DIRECTORY name that resolved perfectly to @aipass the citizen - exactly the misattribution the warning exists for. So the quiet-gate is PROVENANCE: AIPASS_CALLER_IDENTITY_SOURCE in {assigned, passport} AND resolved against a catalog - a credential travels, a location does not. Three cases stay loud, each because it is not proven good: provenance 'project' (a directory answers where, never who), provenance missing/unknown (unprovable is not proven - this lane fails toward noise, never silence), and caller_branch:synthesized (a stamp says who wrote a name, never that anything vouched for it). Bar: 1340 passed (1329+11) from repo root, re-run independently by devpulse (1340), 6/6 mutations bite each against only its own test (including held-project-admitted-to-constant and synthesized-also-silenced), seedgo 100 percent on every standard including trinity, 0 type errors, checklist 34/34 x3, README carries the @all-scope section and the 'A Credential Is Not an Ambiguity' table.
…eplaces the stopwatch (@drone's build, Patrick's ruling, DPLAN-0318 circle close, committed by devpulse). THE SHAPE, and why none of ai_mail's three: all three answered 'how long should THIS verb take' and that question has no stable answer - email @seedgo vs email @ALL generalised. Patrick's constraint is outcome-only, so the seam is a HANG GUARD sized for the worst legitimate case: DEFAULT_TIMEOUT 60 to 600; OUTPUT EXTENDS LIFE - a child still producing at its deadline buys another 120s IDLE_GRACE repeatedly up to an absolute MAX_TIMEOUT 1800, which kills both flagged edges (a chattering hang cannot live forever, ceiling absolute; a long SILENT computation loses nothing because silence never SHORTENS - a mute child keeps its full base, it just does not buy more). Explicit --drone-timeout N means exactly N, extension off when an operator named a number. PARTIAL OUTPUT REPLAYED on kill: both streams tail-first under 'partial stdout (N bytes)' banners, truncated to the last 4000 chars AND SAYING SO, the chained TimeoutExpired carrying the same bytes - this morning's fleet-push kill was diagnosable only because the push wrote its own report file; never again. THE DECISION WORTH THE EYE: TIMEOUT_OVERRIDES emptied - all three entries (memory process-plans 120, memory rollover 100, flow close 90) were written to RAISE above 60 and would have INVERTED into caps under a 600 base, handing the three commands we KNOW are slow the least time in the fleet, the exact failure this ruling ends; the mechanism stays, only the harmful data is gone. BEYOND THE BRIEF, both the same species as the defect being fixed: (1) --drone-timeout was INERT on two whole lanes - interactive commands inherit the terminal and are never timed, module routing runs in-process - the flag parsed and vanished in silence; found by live-proving with audit --drone-timeout 5 and watching it run unbounded; both lanes now WARN to log and stderr naming number and reason. (2) restructuring the KeyboardInterrupt handler turned a compliant except into a silent one - caught by checklist not the builder, said so; seven silent catches now log, the zombie-capable one at WARNING with the pid. MUTATIONS 22/22 bite; the three first-pass survivors were all real - one genuine gap (ceiling clamp invisible because clamped and unclamped landed on the same second), and TWO EQUIVALENT MUTANTS removed rather than tested around, with a new pin for what the max() was gesturing at (a base above the ceiling is honoured in full - the ceiling caps EXTENSION only). LIVE-PROVEN through the real router: exact 1.0s cap with both banners rendering, both inert-flag warnings on real invocations, routing log reading timeout=600s extend_on_output=True on live traffic. SAID PLAINLY: extension past 600s is test-proven with scaled constants, not yet live end-to-end - the only real specimen is the fleet push and it was not fired unasked. Rider: .seedgo/bypass.json line numbers realigned after the helper insertion (a bypass keyed on line numbers is a claim about a file that keeps changing - banked as a learning). Bar: 1238 passed / 5 skipped from repo root, re-run independently by devpulse (1238), 0 type errors, seedgo 100 percent including trinity, checklist green x6, README counts re-derived by collection including the honest edge (a long silent job still needs --drone-timeout).
…tion-era blanket comes off now the fleet is green (@hooks' build, edit_gate 1.6.0, DPLAN-0318 circle close, Patrick's GO, committed by devpulse). THE CHANGE: _missing_field_violations reads RESHAPE_ONLY_SECTIONS off @memory's entry_limits AT CALL TIME - no new import, the gate already holds that module for load_entry_limits and changed_entries; exempt containers keep the raw-entry on-disk pass, every other container refuses drift whether or not this write created it; dedupe untouched, union of both sides kept, richer record wins. THE JUDGMENT CALL, approved: reading the attribute beats a local copy because two lists of containers-we-may-not-prune that can disagree within a release is precisely the failure @memory's own docstring warns about - a mutation replacing the getattr with a hardcoded local bites two tests. Fallback is LOUD: an entry_limits too old to publish the constant falls back to todos-only and WARNS naming it, because exempting nothing would refuse every write to a file carrying one drifted todo - the exemption bricking the branch it protects; the warning-removal mutation bites. THE CAUTION PINNED both directions: a drifted todo on disk blocks nothing elsewhere, a NEW drifted todo is still refused, and EDITING a drifted todo forfeits its exemption - the 67 restored todos keep working, nobody adds a 68th. FOUR MIGRATION-ERA TESTS REVERSED not deleted, banners saying what expired - including the one whose own docstring called it THE critical no-false-reject test: it was, while the fleet was mid-migration; that premise ended 36 hours ago, and the intent (an uncurable entry must not block an unrelated edit) still lives - in todos, the one container no machine may prune. Reversals keep the ruling's history readable in the file. HONESTY IN THE COVERAGE: the seam test is deliberately UNIT level because an end-to-end version passes for the wrong reason - the union also runs @memory's real changed_entries which refuses regardless of whose list the gate read; narrower coverage, honest coverage. Checked not assumed: with the blanket still on, hooks' half returned EXEMPT on an untouched drifted key_learning while @memory's returned CAUGHT - the correct fleet behaviour was coming from one side and the other was dead weight; it is not now. RIDER in scope for an enforcement-lane session: auto_fix 1.1.0 - open_no_encoding tested open( as a plain SUBSTRING and matched inside subprocess.Popen(, firing six times on @drone's executor.py which contains no open() at all, while the advisory says do-not-skip and offers no fix - an enforcement lane handing agents a choice between ignoring the gate and damaging working code; word-boundary match now, 6 red-first tests on @drone's own file as fixture, 2 mutations bite, only the colliding pattern converted. ALSO ON RECORD: hooks' trinity went 68 to 100 (the push cured the data), its 7 archived todos restored in canonical shape after reconciling each against reality - and the builder's first restore broke newest-first ordering, caught by the LIVE checker at 98 not by the builder: the gate gating its own consumer. Red-first 5, mutations 4/4 bite on the gate change (blanket-restored, exemption-removed, local-copy, silent-fallback). Bar: hooks suite 1704 passed / 2 skipped re-run independently by devpulse, seedgo 100 percent on every standard including trinity, 0 type errors, checklist 34/34 x2, no provider wire needed.
…s left unformatted (CI lint step red on 33121948563) - ai_mail test_cross_project_bridge + test_send_identity, hooks test_auto_fix. Spawn's delete_ops.py also needs it but is live WIP - rides their commit.
AIOSAI added 12 commits August 27, 2026 16:37
… learns to see directories (@seedgo's build, CI unblock for PR 743, DPLAN-0318 merge prep, committed by devpulse). DEFECT 1, the CI red: reproduced the exact runner shape first - a branch dir with apps/ and no memories scored trinity 0 with unmeasurable across every group. THE FIX follows the One Law to its third answer: refusing was not enough because branch_audit turned refusal into 0 - trinity now returns not_applicable with score None and branch_audit leaves such a standard OUT of scores[] entirely, because a 0 blames the branch for an environment fact and a 100 claims a measurement that never happened. The old path did not merely mis-score None, it CRASHED (TypeError int+None) - surfaced by the red-first run. DISCRIMINATION CONSERVATIVE, both signals must be absent: no AIPASS_REGISTRY.json searching upward AND no fleet/branch/.trinity anywhere; a live installation that lost one branch's .trinity still has the registry, so that stays the violation it always was - pinned and live-verified (registry present, missing .trinity: still 0, still failed). THE TRAP CHECKED NOT ASSUMED: exactly one .trinity ships in a clean clone - spawn's un-ignored aipass_framework template, two levels down - and the one-level scan ignoring it is now a NAMED TEST not a lucky accident. The skip ANNOUNCES itself in check_branch_info, no branch names special-cased. Three colliding tests kept their assertions - their bare-tmp fixtures had become ambiguous under the new rule, so each gained a registry file with a comment naming the premise it always relied on. DEFECT 2, @daemon's find reproduced both directions: the builder's own morning exclusion 'if match.is_file()' blinded the cache to stray DIRECTORIES - the exact shape the File set ruling is about. Directories now watched by PRESENCE not content (a dir's mtime moves on every child change and the children are already tracked - content-watching would double-report), live-verified mkdir->added rmdir->deleted, plus an invariant test that everything check_branch_info names is in the watch set. The morning's opposite-asserting test REVERSED with a banner, not deleted. MUTATIONS 7/7 bite, sources byte-identical after. THREE FLAGS from the report, on the record: (1) @aipass 99 (stray top-level 'user' section) and @Spawn 99 (newest-first inversion at entry 84) - post-push memory drift by rules that predate today, owners to fix, no author named; (2) two orphaned seedgo_json .tmp files left per never-delete - the 9.1MB one self-attributed to this session's killed harness, save_cache staging cleanup lives in an except a hard kill never runs, plus a live-state test that flakes on concurrent orphans - ruling wanted, scope not widened on a CI fix; (3) trinity_check.py 1550 lines vs its own 1500 limit - seedgo 99 architecture, the split (nine group functions to trinity_groups.py) queued as its own pass, NOT smuggled into a merge-prep fix. Bar: 1928 passed / 1 skipped from repo root, re-run independently by devpulse (1931 passed), 0 type errors, checklist green.
…rchive - marker 7's spawn leg, and the premise measured before built (@Spawn's build, DPLAN-0318 circle close, Patrick's GO, committed by devpulse). MEASURED FIRST AND THE BRIEF WAS HALF THE STORY: a freshly minted citizen scored trinity 77 with FOUR groups red - receipt and File set were the brief, but Top-level keys 78 (spawn's own seeds carried the status block the standard deletes, and stamped managed_by in the wrong case) and Meta lines & _usage 0 (seed prose drifted from gold) were spawn's and nobody had ever measured them; building only what was asked would have shipped an 85 and called it fixed. (1) BIRTH: receipt_ops.py wired as step 3d - AFTER mint verification, BEFORE registration, so a registered citizen always carries a receipt (ordering pinned by a spy test). THE DECISION WORTH THE EYE: versions read from the GOLD source (memory/templates schema_version), never spawn's own seeds - a drifted seed minting a receipt that claims a version the fleet never issued would score GREEN against gold in exactly the case the receipt exists to catch; seed drift is caught separately, where it belongs. Shape COPIED NOT IMPORTED: an ast test pins STAMPED_BY equality with @memory's sanctioned constant (red the day they rename), another asserts no aipass.memory import exists. FAILURE POLICY stated: unreadable gold stamps NOTHING and surfaces the reason in validation_issues - but does not abandon the birth; a receipt naming an unverifiable version is worse than an absent one, and a citizen unbornable because another branch's files are unreadable is worse than both. (2) SEEDS REBUILT FROM GOLD, both classes, byte-identical pins modulo the branchname substitution and one sanctioned divergence - pins go RED the moment @memory bumps, the only honest way to hold a copy of someone else's source of truth; the casing violation's root cause found (BRANCHNAME->UPPER vs gold's lowercase). (3) ADOPTION beyond the brief: create @eXisting stamps ONLY IF ABSENT - a branch @memory's push stamped carries 'memory push', and restamping it 'spawn birth' would replace a true record of which lane last touched the files with a false one; adoption fills a hole, it does not rewrite history. (4) RETIRE made observable: .trinity already travelled intact (ARCHIVE_EXCLUDE never touched it) - what was missing was the SAYING SO; the retire log now names the archive path and lists the trinity files carried, recorded in the operation log, because that fact cannot be re-derived once the directory is gone. (5) EVENT BUS refused with evidence: spawn publishes nothing today and the bump event's subscriber list is empty - no listener built for a bus nobody fires; birth and retire are observable as logs plus operation entries as briefed. LIVE PROOF: one citizen minted per class into temp trees, scored by seedgo's REAL checker - aipass_framework 100, project_agent 100, receipt read off disk verbatim (3.0.0/3.0.0, spawn birth); temp trees removed via drone rm, the live registry verified untouched. HONEST MISS banked: first full-repo run read 4 false reds because the mutation harness was rewriting spawn source mid-run - the same trap @api banked, now spawn's too; re-ran alone, clean. FINDING for seedgo's ledger: trinity_check.py's docstring still claims no branch carries a receipt and the machinery is still to come - stale on both counts since this morning, their file, not touched. Bar: 531 passed / 1 skipped in spawn (was 506, 25 new red-first), full repo 17589 passed / 23 skipped exit 0, re-run independently by devpulse (531), 12/12 mutations bite, 0 type errors, seedgo @Spawn 100 percent including trinity, checklist green on every touched file.
… three greens were vacuous (@memory's build, PR 743 merge prep, committed by devpulse). THE FIX is one discriminator in one place: a live_fleet fixture in tests/conftest.py that skips with 'no AIPASS_REGISTRY.json at <root> - live-state guard skipped', wording matched to @seedgo's clean-checkout guard so the two lanes read the same. A FIXTURE not a helper import on purpose - dotted sibling imports resolve only on a branch-dir rootdir and go red on CI's repo-root run (their KL 82, a trap this branch was already caught by); fixtures inject by name from any rootdir. It checks BOTH repo roots (registry_scope and trinity_push each resolve their own) because a guard verifying one lane while the other is blind is the exact 22-vs-19 asymmetry marker 7 closed. REPRODUCED RED FIRST: a pytest plugin masking both _REPO_ROOTs at an empty temp dir remade the exact CI failure list locally (5 failed 125 passed) before any fix. THE DELIBERATE DEVIATION, on the record not buried: the brief said guard only the 5 failing tests - @memory guarded 3 MORE that PASS on clean CI (held-project never swept x2, push-and-registry-agree) because they pass for the one reason that makes the assertion worthless: an empty set contains nothing and two empty sets satisfy subset - a green reporting a measurement that never happened, the same defect species the push report and entry gate just closed. Devpulse accepts the deviation as correct. Swept the WHOLE suite under the mask from both rootdirs: 1219 passed 13 skipped ZERO failed - no other test depends on live fleet state. Honest limit stated: the mask is a simulation of a clean clone, not byte-identical to one - the fresh CI run is the real proof. RIDER from @hooks' same-round mail survived their set: legacy identity keyed on field name not raw entry means two different malformed todos both extract to None and the second reads as already-on-disk - pinned at the contract with BOTH hiding facts written into the test (the obvious new-key test never reaches the mutated line; the exempt path is currently dead code since the clause narrowed to todos) because a dead branch that is also unpinned comes back wrong. ALSO on the record: their rollover lane rolled devpulse's local.json too (402 to 390, 2 entries archived) - normal detector behavior on an over-limit file, not a reach-in. Bar: 1227 passed / 5 skipped live from repo root, re-run independently by devpulse (1227/5 exact match), masked 1219/13/0 from both rootdirs, seedgo --full 100 percent, 0 type errors, one naming violation their new test introduced renamed rather than added to the pile.
…tray section was never anonymous drift, it was profile.py writing on read since June (@aipass's build, PR 743 merge prep, committed by devpulse). PREMISE CORRECTED with direct evidence not inference: the stray top-level user section in local.json was written by aipass's OWN get_user_profile() - which WRITES on read - and had carried first_seen 2026-06-10 for 2.5 months; @aipass read the file at 09:08 today, hours before the 11:27 fleet push, and the section was already there. The push pruned it, profile.py recreated it minutes later, and init_flow's existing.get(first_seen) or now() silently reset the June date to today - so it PRESENTED as same-day drift by an unknown author. Lesson for every stray report: appeared-after-the-push does not mean recent. THE FIX moves the profile to its own home: aipass_json/user_profile.json, profile.py never writes .trinity at all - because deleting the key alone would last until the next aipass profile call recreated it and dropped the branch back to 99. A legacy user section is still READ once as fallback (no installation loses a profile) and never written back; first_seen restored to the true 2026-06-10 from the pre-push read; the human-meaningful content landed as canonical observation 37. TWO LIVE DEFECTS caught while verifying, both theirs, both fixed: (1) the test suite was MUTATING THE LIVE USER PROFILE - test_init_flow injects a MagicMock at sys.modules but from-import resolves the attribute already bound on the parent package once any earlier test imported the real module, so the mock was silently bypassed and the real profile stage wrote the real file; only the two files TOGETHER corrupt it, either alone is clean, which is why no single-file run ever caught it - fixed with an autouse conftest fixture redirecting both profile paths to tmp plus two regression tests that fail if the guard is removed. (2) the first filename chosen was a landmine: profile_data.json collides with json_handler's managed module triplet - save_profile's own log_operation auto-detects module profile and REGENERATES the store, erasing it by the very call that logged the save; renamed user_profile.json with a no-mocks round-trip test red on the old name and a pin that the filename never re-enters the triplet. ON THE RECORD not fixed: audit Modules 98 (profile.py 80, line 81 mkdir) is PRE-EXISTING - the hand-rolled writer shipped before today, replacing it deletes a trigger.fire integration and an OSError durability path, a scoped refactor not a merge-prep smuggle; checklist lane passes the same file on all 34 standards, the known two-lane split. Bar: 1041 passed (+7: legacy/never-write x3, isolation x2, round-trip/naming x2), re-run independently by devpulse (1041 passed), fresh audit trinity 100 all nine groups - FLEET NOW 22 OF 22 AT TRINITY 100 - 0 type errors, live CLI round-trip proven with local.json md5-identical before and after.
…- the train's last two pre-merge builds, fleet 22/22 trinity 100
…k with no __path__, and the resident guard was reading the resolver instead of the disk (@memory's build, PR 743 merge prep round 2, committed by devpulse). DEFECT 1, the 3.10-only red: the bus-announce test reached the trigger bus through conftest's autouse MagicMock package tree, and MagicMocks have no __path__ - 3.12's import bytecode short-circuits on sys.modules and finds the mock, 3.10's machinery walks the parent packages, hits the missing __path__, raises ModuleNotFoundError, and _announce_bump swallows ImportError BY DESIGN (the bus is optional) - so fired came back empty on one interpreter for a reason unrelated to the behaviour under test. Rewritten with real types.ModuleType objects carrying __path__, no MagicMock in the chain, interpreter-independent by construction. STATED PLAINLY: 3.10 was NOT reproduced locally (machine has 3.12 only) - the MECHANISM was reproduced standalone (mock tree without __path__ gives the exact CI assertion), demonstrated mechanism not confirmed root cause - and the test now asserts the stand-in is REACHABLE before calling the code, because bus-unreachable and bus-not-fired both read as fired empty; if 3.10 still fails it fails on the reachability line and names itself. DEFECT 2, the guard that was WRONG not incomplete: live_fleet asks is-aipass-installed-here, the Windows e2e installs from the wheel and HAS a real registry, so the guard correctly let the resident tests run - and residents-subset-of-fleet failed because earmark/finch/aipass_site/baud live in projects/ on ONE machine. A reachable-residents claim is about an installation, not the software. New narrower fixture live_residents layered on live_fleet, and THE DECISION WORTH THE RECORD: it measures the four registry files with pathlib, NEVER by calling resident_registry_paths() - asking the code under test whether its own inputs exist would turn every resolver regression into a SKIP, the guard deleting the exact failure it exists to expose. Proved not asserted: with residents on disk, resident_registry_paths mutated to if-False gave 2 FAILED not 2 skipped; source restored byte-identical. The fleet-scope test SPLIT in two rather than guarded whole - core citizens under live_fleet, residents under live_residents - because guarding the whole assertion would skip the measurable core half on the wheel lane; the split IS the fix. Bar: 1228 passed / 5 skipped live from branch dir, repo root, and repo root under xdist, re-run independently by devpulse (1228/5 exact match); clean-checkout mask both rootdirs 1219/14/0; installed-no-residents mask both rootdirs 1226/7/0 with the skip NAMING all four absent files; 0 type errors; seedgo 100 all 34 standards. Honest limits kept: both masks are simulations, the fresh matrix run is the real proof; the audit also caught @memory's own file at 99 (two learnings both numbered 97) - renumbered, 100.
…as five, plus six greens measuring nothing, plus a live lie on THIS host (@api's build, PR 743 merge prep round 2, committed by devpulse). THE DIAGNOSIS: not an exception path - _systemctl asks is_supported() BEFORE running anything, so on a machine with no systemctl the platform gate returns first and the patched subprocess.run is never reached; the mock was not wrong, it was unreachable. Reproduced as a stated SIMULATION (no Windows box): is_supported's two inputs masked both ways CI can have them - win32, and linux with systemctl absent from PATH - both remade the failure; the fresh matrix run is the real proof. THE COUNT: 5 red not 1 (the job stops at the first), and SIX MORE passing vacuously - they assert 0 or (None,None), exactly what the untouched gate returns, green while measuring nothing; fixed as ONE fixture rather than five patches because the six silent ones are the reason. THE RULING SPLIT IN TWO, each pinned: no-systemd-on-the-platform still answers ZERO - on a machine that CANNOT have a unit, no-unit-holding-the-server is a fact with no uncertainty, the strongest answer a probe can give, and running() falls through to the detached record, the only server that can exist there. But a probe that FAILED on a CAPABLE machine refuses - new SupervisorUnreachable raised at the source - because _systemctl was answering None for two different facts (no systemd here, and systemctl-is-here-and-did-not-answer) and both became no-unit-running, which on THIS host is a live lie: the installed unit writes no record file, so a swallowed probe sends status down the record path saying No server is running about a server serving requests. PROVEN LIVE against the real unit holding pid 227641: probe forced to fail, old behaviour invents an absence, new behaviour refuses and names why - the same defect this lane was built to close, one layer down from where it was found. All three callers wanted the refusal for their own reasons (status will not invent absence; stop will not signal into the dark a restart policy may undo; serve will not double-bind a port it cannot see); only supervised_bind tolerates it, and that tolerance was UNPINNED until a surviving mutation found it. Two seedgo findings on the fix itself fixed not bypassed: the silent catch in supervised_bind, and cmd_status/cmd_autostart carrying implementation again - state decision moved into handlers as server_state()/autostart_report(), which LOUDLY broke two host_api CLI tests (they asserted on a MagicMock repr once cmd_status stopped calling running()) - reconnected, plus a CLI-level pin that cannot-tell never quietly renders as not-running at the surface an operator reads. Bar: 1611 to 1625 all green, re-run independently by devpulse (1625 passed) with the live unit re-verified active holding 227641 (devpulse first probed a wrong unit name and got inactive - the real unit is aipass-host-api.service, the report was right); whole suite under BOTH masks 1617 passed ZERO failed; seedgo 100 on all 46; 0 type errors; 12/12 mutations bite; README counts corrected with the ruling written into the host-api section.
…the durability argument for keeping the writer was wrong on the merits (@aipass's build, PR 743 merge prep round 2, committed by devpulse). THE FLAG DECODED: the checker returns only file_operations[0], so line 81's mkdir hid a json.dump in the same writer equally forbidden by the same rule - the next red already queued behind this one. Both die with the writer, and all five forbidden tokens (mkdir/write_text/read_text/json.dump/json.load) are pinned in a source-scanning test so the next one cannot arrive silently. THE TWO BEHAVIOURS the morning refusal protected, named where they live now: DURABILITY moved to json_handler.save_path and came out IMPROVED - the hand-rolled writer had no fsync, no Windows retry, and an OSError-only temp cleanup; the handler does tempfile + fsync + replace-with-retry and cleans in a BaseException branch. The builder states plainly their own morning argument was wrong once made to actually look. TRIGGER kept: _fire_file_deleted now fires from the failure branch of _write_profile_json, same event name, same reason, identical signal class to consumers. THE TRAP FLAGGED FOR ANYONE MAKING THIS SWAP: write_json returns False on OSError and never raises - left alone, every failed save becomes a success at the call site; the False is re-raised as OSError, and the refactor is silent-failure-shaped BY DEFAULT without that line. The event's path names the STORE not the handler's internal temp file (which this module never learns), with a detail line saying the store was left untouched - checked first that nothing subscribes to bare file_deleted today, rename offer banked as @trigger's call. PROVEN with three mutations each biting the right pin (source md5-identical after): drop the re-raise = 4 red, drop the fire = 1 red, reinstate the mkdir = 1 red; durability tests force a REAL handler failure (_replace_with_retry raising, as a full disk would) not a stubbed False - a stub would measure signalling and miss the save silently going non-atomic - asserting the previous store byte-identical, the old value still served, and no temp file left behind. Both landmine checks VERIFIED not assumed: the autouse isolation fixture covers the new path (patches _PROFILE_JSON, which save_path receives), proven by md5 on the live user_profile.json and local.json across the full run; filename still user_profile.json outside the managed triplet. ON THE RECORD unfixed by scope: init_flow.py carries the IDENTICAL hand-rolled writer at lines 117-139, invisible to the audit because their own bypass.json exempts it from the whole modules standard on a file-SIZE argument - a file-ops violation riding a bypass written for a different reason; a real finding about their own bypass, banked as its own scoped job. Bar: 1047 passed (+6 pins), re-run independently by devpulse (1047 passed, fresh audit 100 overall including Modules 100), Trinity 100, 0 type errors, live CLI round-trip re-proven through the new writer with the restored June first_seen intact.
… 429 engine + 1231 groups, proven byte-identical over the live fleet (@seedgo's build, the last PR 743 CI blocker, committed by devpulse). THE CUT, adjusted from the brief on evidence not taste: the ENGINE keeps ALL disk and JSON I/O and the nine groups became pure functions over the context dict - because (1) the tests monkeypatch load_memory_config/_load_templates whose only caller is _build_context, and moving either would have made the patches silently miss, a suite green while measuring nothing; and (2) json_structure requires every handler to import json_handler and call log_operation, so a groups module doing raw json.load would have needed a bypass entry - moving the I/O out made it comply honestly instead of by exemption. HOW: an ast script computed each definition's exact source span and moved whole chunks with their banners - no line retyped - and a dependency analysis proved the graph acyclic (the one cycle found, load_template_prose calling _load_templates, is WHY load_template_prose sits engine-side). PROOF stronger than a score diff: pre-split file pulled from git HEAD, loaded as a second module INSIDE the package, both run over all 18 live branches in ONE process - full result dicts and info lines 18/18 BYTE-IDENTICAL, plus clean-checkout, live-missing-trinity, and stray-dir cases identical - because percentages can agree while two groups cancel out. The harness lied first and the builder said so: the /tmp-loaded copy read every branch at 77 (_repo_root walks up from __file__), fixed the harness rather than reporting the number. ONE ADDITION DECLARED NOT SMUGGLED: the engine calls a single public all_groups(ctx) instead of nine private imports - and it closes the regression a split invites: A DROPPED GROUP SCORES HIGHER because the weighted mean divides by less, so the roster, its order, and the engine-never-reaches-past-the-entry-point are pinned by tests whose mutations bite (dropping Freshness bites, reordering bites). THE THREE RIDERS: save_cache's real hole was BaseException not a hard kill - KeyboardInterrupt and SystemExit walk past except Exception and the cleanup never ran; red-first proved it, an ACCIDENTAL LIVE PROOF beat the unit test (a SIGINT-killed fleet audit left zero new orphans, the same kill class that left a truncated tmp at 16:30), and the docstring states plainly that SIGKILL/SIGTERM still orphan because nothing unwinds the stack - no finally can shut that hole and the code does not claim to. The orphan-tmp flake fixed at the source: the assertion read LIVE state so anything dying mid-write anywhere failed an innocent run; a session-scoped snapshot makes the claim THIS SESSION LEFT NO NEW ORPHAN - the claim the test can actually support - with pre-existing orphans WARNED BY NAME never silently baselined, both directions proved. The stale docstring was wrong in four places ALL toward more pessimism than reality (guidelines content now scored, metadata extras now closed-set, every branch carries a receipt, fleet at 100) - rewritten for what the file now is, with the not_applicable third answer documented. HONESTY KEPT: first baseline audit was CONTAMINATED (split written while it audited branch 16) and thrown away rather than quoted; aipass reading 100 is the other dispatch landing, no credit claimed; test_json_durability's pre-existing deep_nesting and silent_catch flags verified present at HEAD, reported and banked, not smuggled. Bar: 1937 passed / 1 skipped from branch dir AND repo root, re-run independently by devpulse (1937/1 exact match); fresh audit by devpulse: seedgo 100 overall, Architecture 100, Trinity 100; fleet 18/18 at 100; 9/9 mutations bite, sources byte-identical after; 0 type errors; checklist 34/34 on all three handler files.
…ile blocking lint, the last red on PR 743 (46 tests re-run green after)
…ed for the trinity-pattern merge train (PPLAN-0041 pre-merge steps; tag fires after Patrick's merge GO)
Comment thread src/aipass/drone/apps/handlers/executor.py Dismissed
AIOSAI added 2 commits August 27, 2026 19:23
…an autouse MagicMock impersonating a package for months, and nine files evicting the real one one-way (@memory's build, PR 743 merge prep round 3, committed by devpulse). REPRODUCED DETERMINISTICALLY on 3.12 in one command - TestOutputCapture then TestReceiptWiring fails with the exact CI assertion, reversed order passes; not a 3.13 story, not a flake, and last round's honest-limit caveat does not apply: this is the real failure. DEFECT 1, the hole: conftest._mock_infrastructure is AUTOUSE - active in all 1238 tests - and installed a bare MagicMock at the PACKAGE name aipass.memory.apps.handlers.json; a MagicMock does not answer __path__, so for months every lazy from-import under that package only worked if sys.modules happened to be warm. DEFECT 2, the trigger: NINE test files evicted the real package with a bare sys.modules.pop/del and never put it back - a one-way eviction that outlives the test and is inherited by every later test in the same worker. Cold cache plus defect 1 equals the CI message, and tab_renderer reports the import failure the same way it reports a bad file, so it surfaced as a wrong COUNT pointing at the receipt renderer - not where the defect was. THE DETAIL EXPLAINING THE ROULETTE: the receipt tests were green standalone because a SIBLING test higher in the same file evicts and re-imports on its way out, warming the cache for them - the file passed because a neighbour supplied its precondition, and under xdist that neighbour is not guaranteed to share the worker. THE FIX both halves: conftest impersonates the package with a REAL module carrying the real package's __path__ (submodules resolve honestly; json_handler stays mocked because a set attribute wins over a submodule import - pinned BOTH ways, including that the mock still shadows, so if that flips the suite starts naming its own disk I/O). All 9 files converted to monkeypatch.delitem. All 13 stand-in installs at that name now carry __path__ - fixed not banked, since green-today is the condition that hid this. THE BUILDER'S OWN CORRECTION on the record: their first census said FOUR files - a head-30-truncated grep; the source-scanning pin found nine. Writing the pin before the claim caught it, and the pin scans source rather than trusting a count. NEW test_import_isolation.py, 10 pins, 4/4 mutations bite, sources md5-identical after: reverting conftest turns the receipt failures into 'this is an isolation defect, not a receipt defect' - poisoning NAMES ITSELF, checked without importing because an import probe would repair the state it measures; the scanner uses a lookback window because the prefix-loop del form writes the name and the eviction on different lines (the reading that let it survive), and judges variable evictions on the window so innocents are not charged - their first scanner reported four innocents and was fixed. REPORTED NOT FIXED, banked: a dozen files bare-pop LEAF modules (parents real, no wrong answer follows - own pass later); pre-existing /tmp and home-path checklist flags on 4 touched files verified NOT theirs. Bar: 1238 passed / 5 skipped from branch dir, repo root, xdist -n4 and -n8; re-run independently by devpulse: exact repro order 6 passed, full suite under xdist 1238/5 exact match; seedgo 100 all 34, 0 type errors, new file 23/23.
…devpulse's own file list, riding now (200 passed / 1 skipped re-verified). These are the tests that split commit's message already describes: all_groups returns every weighted group in reporting order (with the set-equality guard naming the failure - a group weighted but never run, or run but never weighted), check_branch reports the same nine, and the engine holds one handle instead of nine imports - because a DROPPED group scores HIGHER when the weighted mean divides by less. Committer's miss, not the builder's: @seedgo shipped the file with the split; devpulse's commit enumerated the earlier status snapshot and this file was not on it.
@AIOSAI
AIOSAI merged commit 67f7e7b into main Aug 28, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants