- memory.config.json is the single source of truth: char caps (entry_limits, global) + rollover counts (per_branch, materialized from registry); .trinity files stripped to a one-line _usage header
- changed_entries gate now matches by content identity, not array position — prepending a new entry never re-flags unchanged legacy entries (old=old, new=new; no trimming required on a cap change)
- rollover push command + top-level 'drone @memory push' alias; corrected config _note + --help (rollover push surfaced, labeled destructive system-wide reset)
- removed 3 dead functions: seed_per_branch, its orphaned write_config, add_learning + its tests
- spawn birthright/builder + LOCAL/OBSERVATIONS templates aligned to the stripped shape
- 966 tests, seedgo 100%
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LOCAL.template.json: session_number->number, +tags:[], schema_version 3.0.0
OBSERVATIONS.template.json: pattern/source->number+note+tags:[], schema_version 3.0.0
New citizens now born in the unified schema (matches spawn templates from 7276e03).
Live 15-branch .trinity cleanup (drop session_number dup, unify obs->note) applied
+ verified by artifact (0 session_number, counts preserved, 34 backups) — gitignored local state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migration surfaced two consumers that still counted key_learnings as a dict: detector v2 trigger (at-cap list invisible -> fell to v1 line-count) and learnings/manager (used by rollover + symbolic). Made list-aware + dual-mode; +5 regression tests (detector counts a LIST, manager round-trip) — the gap 955 tests missed. rollover check now shows '25/25 key_learnings' (v2), was '609/500 lines'. 960 tests; seedgo 99% (pre-existing unused-function on unwired add_learning, not a regression).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gate now covers Write/Edit/MultiEdit via _resolve_after_text (reconstruct post-edit
text: Edit replace first/all, MultiEdit sequential) + _evaluate_limits +
_check_trinity_change, all reusing @memory changed_entries. Because only NEW/CHANGED
entries are checked, editing an unrelated field in a file full of legacy over-limit
entries is ALLOWED — proven on devpulse's REAL local.json under enforce=true
(unrelated todo edit allowed, over-limit edit blocked, file never written).
Fail-open on old_string-not-found / invalid-JSON / import error / any exception.
+17 tests (39 trinity, 511 hooks total), seedgo 100%, enforce false. @hooks side
complete. Warn-first build (Phases 1-5) done. Part of DPLAN-0205.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Additive gate in edit_gate.handle(): on Write to .trinity/{local,observations}.json,
lazily importlib-imports @memory's load_entry_limits + changed_entries and flags
new/changed over-limit entries. enforce:false → allow (warn); enforce:true → block
with reason. Fail-OPEN on bad JSON / import error / any exception (this hook runs on
every edit system-wide — never block on its own failure). Edit/MultiEdit pass
through (Phase 5). All 4 existing gates (inbox/daemon/cross-branch/edit-while-errors)
intact. +22 tests (494 total, 13 existing edit_gate green), seedgo 100%, enforce
false. Verified by artifact incl. fail-open + rollover-safe + char-not-byte proofs.
Part of DPLAN-0205.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
changed_entries(before,after,limits): pure diff that flags only NEW/CHANGED
over-limit entries, ignoring unchanged legacy fat — so rollover (trims by count,
writes back recent fat entries) is never rejected. Wired into write_memory_file
via _validate_entry_limits (gates only .trinity/{local,observations}.json): warn
mode logs+writes, enforce mode rejects new/changed over-limit only. Validation
wrapped in try/except → a validator bug can never abort a write. +15 tests (917
total), seedgo 100%, enforce stays false. Verified by artifact incl. live proof
of rollover-safety + the defensive guarantee. @memory side (P1-3) complete. The
changed_entries() helper is what @hooks imports next. Part of DPLAN-0205.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pure check_entry(type,text,limits) validator (chars not bytes, boundary at cap,
unknown-type safe) reusable by both gates. New 'drone @memory lint run' scans all
branches' .trinity via registry, handles dict+list containers and both
key_learning value shapes, sorts worst-first — strictly READ-ONLY (never writes/
trims, honors never_trim_s153). Phase-1 unused_function bypass removed (reader now
called). +12 tests (902 total), seedgo 100%. Verified by artifact incl. live lint:
513 over-limit entries across 17 branches (devpulse worst at 71, top offender
5724/600). enforce still false. Part of DPLAN-0205.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Config-driven char caps for .trinity memory entries. Phase 1 = foundation only:
adds entry_limits section to memory.config.json (4 caps: learnings 200, sessions
300, todos 200, observations 600) and the load_entry_limits(branch) reader
(deep-merge per_branch overrides, safe-defaults on missing/malformed). Reader has
NO callers yet (Phase 3 wires it) — unused_function bypass is intentional.
Verified by artifact: 14/14 tests, seedgo 100%, scope clean. enforce:false →
zero behavior change. Part of DPLAN-0205.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backup root is now .backup/ via BACKUP_DIR (builder.py:19); tracker.py uses backup_root() not a hardcoded path; patterns.py BUILTIN_IGNORES + docstrings/README updated. Removed the orphaned per-timestamp versions/ scaffold (setup.py) and unused build_versioned_path() — both superseded by the Phase-3 versioned/ baseline+diff store. .backup/ coexists with flow's .backup/processed_plans/. Repo-root .backupignore now ignores both .backup/ and (until manual deletion) .backup_system/ (also carries Patrick's *logs rule). Verified by artifact (seedgo 100%, 220 tests) + live (throwaway writes to .backup/, no versions/, Drive reads .backup/versioned/).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.backupignore is now AIPass's managed backup filter (true gitignore semantics via pathspec), so it belongs in version control like .gitignore — a fresh clone gets the curated rules, not just the auto-seed default. Includes the .ruff_cache/ + .coverage additions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace hand-rolled fnmatch+part-loop matcher with pathspec gitwildmatch (leading-slash anchoring, !negation, dir-only foo/, *-not-crossing-/, last-match-wins). Demote BUILTIN_IGNORES to a seed-only default (written when absent, never merged at runtime); delete IGNORE_EXCEPTIONS/is_exception (exceptions are native ! lines). snapshot+versioned+all+mirror-cleanup all obey one .backupignore. Remove the drive_sync dotfile-skip so .trinity/.chroma/.aipass/.ai_mail.local (4558 files incl memories) now reach Drive. Add a Drive-sync output panel matching snapshot/versioned. Declare pathspec (pure-python, cross-OS). Verified by artifact (seedgo 100%, 220 tests incl 26 new gitignore-parity) + live (dotfile flows into store, !negation re-includes end-to-end).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Faithful port of the GOLD versioned engine (no reinvention). Replaces the mtime
full-copy-into-per-run-dirs remnant with ONE persistent store
(.backup_system/versioned/) using GOLD's file-folder packaging:
<parent>/<name>/<name> current (copy2, mtime preserved)
<parent>/<name>/<stem>-baseline-<date>.<ext> first-run full copy, never touched
<parent>/<name>/<name>_diffs/<name>_v<old-mtime>.diff unified-diff per change
Patrick's laws, all enforced + tested:
- versioned backs up the EXACT same files as snapshot (same scan/ignore;
all.py shares one scan between modes)
- first versioned run = baseline snapshot of that state
- append-only: versioned NEVER deletes (cleanup stays snapshot-only)
- change detection is LEDGER-FREE (source mtime vs store-current mtime) —
removes versioned's use of shared timestamps.json, killing the
snapshot-starves-versioned regression
New diff/restore.py (list_versions + restore_file); diff/generator.py wired
(binary detection, DIFF include/ignore patterns); path/builder.py file-folder
versioned branch (root/ wrap, >50-char hash shortening). +15 tests -> 125.
Verified by artifact (audit 100% all 36, pytest 125, ruff clean) + LIVE
end-to-end: snapshot-first-then-versioned baselines all 5 files (starvation
dead) -> edit -> diff with old-mtime timestamp + current overwritten + baseline
intact -> source delete -> versioned store untouched while snapshot
mirror-deletes -> restore round-trip byte-identical.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_broker.py (AF_UNIX sockets + openat2) and test_sandbox.py (bwrap) are
Linux-only; module-level pytestmark skips them on windows-latest while leaving
Linux runs unchanged. Unblocks the windows-setup CI check (red since the
sandbox build 0b4ba63).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hoist per-checker SKIP_DIRS to shared SOURCE_SKIP_DIRS (artifacts/dropbox are
output dirs, not source; no git coupling). Diagnostics: python3->sys.executable,
parse/run failures now fail loud instead of silent 0-errors-clean, and pin
pyright resolution with --pythonpath sys.executable. drone bypasses test-only
broker start_background. Proven all-13-branches-100% deterministic in an
unactivated shell (local==CI).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
src/aipass/common was the only non-citizen directory in the agent namespace.
Per @seedgo design review: moved into @aipass (owner) as aipass.aipass.shared,
content byte-identical. @spawn imports across (blessed shared-infra category,
same as aipass.prax/cli). New subprocess guard test pins the bootstrap-safety
invariant (shared/ loads zero branch deps — aipass init stays pre-drone-safe).
9 import/doc sites updated, 9 documented seedgo bypasses (pre-infra leaf,
stdlib-only by design). aipass 480 + spawn 315 tests green, both audits 100%,
repo-wide zero refs to the old path.
Every autonomous agent can launch inside a kernel-enforced mount namespace
(srt -> bwrap+seccomp): reads stay open (shared live FS preserved, bind-mount not
isolation; own-tree writes land live), but rm/python/find/Write on .git or sibling
trees hit EROFS. /tmp + own tree writable; .git RW devpulse, RO builders. Inert by
default behind AIPASS_SANDBOX_ENABLED (off); flag-off path byte-identical to old.
hooks: srt wrapper + per-role build_policy + broker_secret mask; rm_gate demoted.
drone: out-of-sandbox broker (identity allowlist, openat2 RESOLVE_BENEATH, HMAC
handshake over inherited fd, audit); drone rm via broker when sandboxed.
ai_mail: dispatch gate + broker-fd wiring (fail-loud exit -4, never silent).
aipass: doctor Sandbox group + setup.sh prereqs (LOUD on missing).
Proven by a live 16-check red-team suite. seedgo 100% + 2859 tests green across
all 5 touched branches.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same action-gated pattern as the notification handlers — speak() -> 'sound'
return-key. Missed in b26bd7c. Hooks suite green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Notification handlers (announce, email, stop_sound, tool_sound) return a
'sound' key the engine plays on action instead of calling speak() on every
invocation — quieter and honest (skipped loaders stay silent). Slim
cadence_investigation.md. Tests updated to assert the return-key form. 472/472
hooks green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three ruff call sites called bare `ruff`, absent from the hook subprocess
PATH (ruff lives only in .venv) — logged 'ruff not found' 177x over ~a month,
silently skipping lint+format on every edit. Also `--output-format=text` was
removed from modern ruff. Fixed all three sites to `sys.executable -m ruff`
(the pattern the working pyright leg already uses) + concise format + honest
rc>=2 error logging. Tests now pin the invocation (argv == sys.executable -m
ruff) so a regression fails loud — the subprocess-mock is how this hid.
438/438 hooks tests green; live-verified through the real hook pipeline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rewrite the always-injected global prompt from a ~13.8KB encyclopedia
into a ~7.8KB navigation map. The prompt now carries AWARENESS; detail
is fetched on demand via 'drone @agent --help'. Dissolves the harness
~10k-char truncation bug — the old prompt's tail (Hard Rules onward)
silently never arrived; the slim one injects whole.
- drone pinned at top as the router; one drilled reflex: --help before use
- framework tree restored; all 13 agents as 2-3 sentence bios
- introspection named as our term; breadcrumb-first navigation flow
- git its own section (raw git/gh blocked, drone-only, devpulse-writes)
- plans section (DPLAN/FPLAN/PPLAN/RPLAN + 'drone @flow templates')
- @memory chroma awareness (local + global stores, search before cold)
- sub-agent usage section incl. model practice (never fable)
- PROMPT_STYLE-conformant; 7855 chars (cap 8000, measured in chars)
Backup retained: .aipass/aipass_global_prompt.BACKUP-2026-06-09-S211.md
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root cause: _HOOK_PATTERN required an action= key that cadence never
emits — it logs the action as the bare second word (fired/skipped).
Extraction failed, so events never reached the styled print_hook_event
renderer (bold-green lightning / dim dot). Pipeline was already correct.
- _HOOK_PATTERN -> bare-word capture: r'\[HOOKS\]\s+(\w+)\s+(\w+)'
- enriched hook event detail (period, offset, short session id)
- corrected docstring that documented the phantom action= format
- tests updated to real production format + real-pipeline test added
- type:ignore on watchdog imports (repo convention)
Verified: 914/914 prax suite green (90 log_watcher). @prax dispatched
for full-pipeline trace; stale monitor process explained the no-show.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>