core.py adopt-path read the passport via json.loads(read_text()) — a direct
file op that fails the json_handler standard and the CI seedgo-audit gate.
Switch to json_handler.read_json() (matches the pattern ~90 lines above),
drop the now-unused 'import json as _json'. @spawn 100%; 315 spawn tests green.
Guarding the fcntl import let Windows collection succeed, which surfaced 3
telegram tests that had never run on Windows — all test-portability bugs:
- log_streamer byte-count broke on CRLF -> fixture writes newline=''
- bot_registry write-failure used Unix-only /proc -> file-as-parent (all OS)
- validate_bot_config rejected POSIX work_dir on Windows (Path.is_absolute is
host-dependent) -> test absoluteness under PurePosixPath OR PureWindowsPath
493 telegram tests green on Linux; ruff clean.
bot_registry did a bare 'import fcntl' (POSIX-only); on Windows the 8
telegram test modules importing it failed at collection (ModuleNotFoundError),
reddening Windows Test on recent PRs. Guard the import and route flock calls
through no-op-on-Windows _lock/_unlock helpers. 246 telegram tests green.
Mirrors the live 'drone @prax monitor run' Mission-Control feed to a dedicated
Telegram bot (DPLAN-0221). New monitoring/telegram_relay.py taps _render_event,
batches every 5s (4000-split, 150 flood-cap, fail-silent-once), gated by
--relay/env so local monitor stays console-only. Reboot-survivable
prax-monitor.service. 937 prax tests green (31 new).
Deploy fixes (devpulse): ExecStart -> 'monitor run' (module __main__ rejects
'run all --relay'); service log moved out of system_logs/ to ~/.aipass/ to break
a monitor<->@trigger feedback loop.
Revives the old prax-monitor capability as a feature of the existing
@aipass bot (no 2nd bot, no new credential). /monitor on|all|off|status
on base_bot; subscribed chat persisted to @api (survives restart) and
boot-started on startup. LogStreamer gains system_wide glob + level_filter
(default WARNING/ERROR/CRITICAL, all=passthrough). 33 new tests,
telegram 493/493, skills 252/252, seedgo 98%.
Route B (true AS-WAS @prax event-feed relay) tracked separately.
DPLAN-0221
The ported telegram-bot@.service logged to a non-existent ~/system_logs
(would crash-loop the service); point StandardOutput/StandardError at
<repo>/system_logs where the app already logs. Then installed the unit,
enable --now + loginctl enable-linger so the @aipass mother-bot runs as a
proper user service with reboot survival and a one-line restart. Startup
log confirms: Telegram API OK, Command menu set (6 commands), poll loop,
tmux session preserved, NRestarts=0.
DPLAN-0220
Resolves the build_botfather_commands design call (Patrick: KEEP, not delete).
POPULATE: base_bot sets its Telegram command menu on startup (setMyCommands)
after verify_connection, so every bot — base or minted — gets a populated
slash-menu, not just create_bot'd ones (the live @aipass was hand-launched
and had none).
SYNC: build_botfather_commands (telegram_standards) is now the single source
feeding base_bot-startup AND create_bot; DEFAULT_BOT_COMMANDS retired. The
Telegram menu and /help list the same commands incl. /create + /cancel.
ENRICH: friendlier command descriptions + /help intro/footer.
Wiring the builder (vs deleting it as 'dead') lifted Unused_Function 92->93%.
6 new tests (menu==help sync, enriched copy, startup-menu, custom cmds);
telegram 460/460, skills 252/252. Running bots need a restart to pick up the
startup menu.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
bot_factory.create_bot now calls set_secret('telegram', bot_id, config,
as_json=True) right after building the config (fail-loud on OSError), so a
newly-minted bot's token reaches the @api store that load_bot_config reads.
The disk write is downgraded to a non-fatal shadow; registry now records
bot_token_ref='@api:telegram/{id}' (TG-LIFE-069).
Proven: new TestCreateBotRoundTrip — create_bot -> @api -> load_bot_config
returns the persisted config; + a fail-loud test (set_secret OSError ->
create_bot returns None). Telegram 454/454, skills 252/252.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
Surfaced by a full completeness audit of the telegram skill against
TELEGRAM_PORT_MAP.md (366 tags, ~83% ported, 452/452 tests green).
@api — in-process set_secret(provider, slug, value, *, as_json) writer
mirroring get_secret (0o600 files / 0o700 dirs, no stdout echo). The store
was read-only; this is the GAP1 enabler the telegram mother-bot needs to
persist a created bot's config. 515 @api tests, seedgo 100%.
@skills telegram wave-1 (fix-forward, no deletions):
- GAP2: bot_factory + telegram-bot@.service launched a non-existent
~/.venv/bin/python3; now sys.executable -m ...base_bot (+ lib/__init__.py
and lib/telegram/__init__.py for package resolution).
- Reboot survival: enable_service now installs the unit to
~/.config/systemd/user/ + daemon-reload (was never installed).
- GAP9: gitignore lib/telegram/.local/ so runtime state stops leaking to git.
- prax-monitor: log_streamer now resolves repo-root system_logs (honoring
AIPASS_TEST_LOG_DIR) instead of a hardcoded ~/system_logs.
Verified: telegram 452/452 green (twice), base_bot imports via -m.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
The CLI help-checker fix (4d41065) immediately surfaced the same
console.print(parser.format_help()) laundering in 4 @api modules on its first
audit run — exactly the latent stragglers the static-scan loophole had been
hiding. Rewrote each print_help() to hand-rolled Rich markup (content was
already in the argparse epilogs); removed the help-only argparse parsers.
- api_key.py, usage_tracker.py, google_client.py, openrouter_client.py
- @api audit Cli + Overall back to 100% (38/38), 504 tests pass, no bypass
DPLAN-0217 (follow-on).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
seedgo's cli/help_text/introspection standards are static source scans — they
confirm a print_help function, console.print, and --help wiring exist, but never
execute --help. So a module could score 100% while rendering raw argparse.
ai_mail did exactly that via console.print(parser.format_help()), laundering
argparse plain text through the approved console API and dodging the existing
parser.print_help() ban.
- seedgo: cli_check now flags .format_help(); cli.md/cli_content.py name it
alongside print_help(); +2 regression tests (1095 pass, self-audit 100%)
- ai_mail: rewrote print_help() to hand-rolled Rich (737 tests pass); --help now
renders Rich with no raw argparse, Cli back to 100% legitimately
- behavioral --help check (run it, assert not raw argparse) noted as a follow-up
DPLAN-0217.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
Backup was the outlier — its default .backupignore content was hardcoded as the
BUILTIN_IGNORES Python list + assembled in _build_backupignore(). Moved it to a
template DATA FILE (backup/templates/backupignore.template), matching the AIPass
convention (flow/spawn/memory all keep templates as files).
- New: templates/backupignore.template (header + patterns, incl logs/).
- _build_backupignore() reads the template via __file__-relative pathlib and
RAISES FileNotFoundError if it's missing — never silently empty (an empty
.backupignore = back up everything = crash). Behavior-preserving otherwise.
- Retired BUILTIN_IGNORES (only setup.py consumed it). Runtime load_spec path
untouched.
- Tests expanded (30 pass): per-pattern template assertions + reads-template +
raises-on-missing-template. Docs/comments repointed to the template.
seedgo @backup 100%. td-30.
Confirmed (via @backup) the two-layer ignore model and wrote it down so it stops
getting re-discovered:
- BUILTIN_IGNORES (patterns.py) = the SEED that generates a new project's
.backupignore at register; never consulted at backup time.
- .backupignore (via load_spec) = the runtime source of truth. No static
fallback exists, so the seed is safety-critical — an empty .backupignore backs
up everything (.venv, node_modules, .git) and can crash the machine.
Added a 'How Ignores Work' README section + code comments on BUILTIN_IGNORES and
load_spec. Added logs/ to the seed so new projects exclude log dirs (prax .jsonl
output) by default, not just *.log files, with a test. seedgo @backup 100%.
td-27.
README: added the 3 missing agents (@daemon, @skills, @commons) to the tree and
tables, normalized the agent count to 17 everywhere (was an inconsistent 13/14).
@daemon -> Quality & operations; new 'Capabilities and community' group for
@skills + @commons (td-28).
/prep: both the Claude command and Codex skill mirror gained a 'Reconcile todos
against reality' step — audit every open todo against the actual system and close
what's verifiably done, catching past-session work that was never closed.
CHANGELOG updated.
The standard email footer told dispatched agents 'CLOSE FPLAN -> drone @flow
close <plan_id>', which led them to close the orchestrator's master/parent plan
referenced in their brief (bit us in FPLAN-0260). Reworded to 'CLOSE YOUR PLAN
-> ... this task's plan only, never the master/parent': a worker still closes the
sub-plan handed to it, the master stays the orchestrator's to close on completion.
td-6. Footer string + test assertion; 737 ai_mail tests pass.
Completes the backup-docs sweep (td-218):
- @memory README: note rollover writes rollover_backup_*.json to <branch>/.backup/
- @flow README: note closed plans archive to <repo-root>/.backup/processed_plans/
both cross-referencing @backup's canonical README.
- Removed orphaned src/aipass/prax/.backupignore (prax is not a registered
backup target; only the AIPass project root is).
seedgo green across all three (@flow 100, @memory 100, @prax 99 = pre-existing
Json_Handler, unrelated).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
The bulletin_created event handler propagated a 'bulletin_board' section into
every branch dashboard, but it was fully dead: nothing fired the event, its
BULLETINS.central.json store no longer exists, and prax already prunes
'bulletin_board' via DEPRECATED_SECTIONS. Archived the handler to
events/.archive/, removed its import + trigger.on() registration, dropped the
5 covering tests (558 pass). seedgo audit 100%. prax pruning left intact.
Closes td-102.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
unused_function bypasses matched by file+line; the line was the function's
def line, so any code shift above it staled the bypass and silently re-flagged
the exempted function, dropping the branch below 100% (S216/S217).
Mechanism: is_bypassed() gains a 'functions' field + name param; name-scoped
match takes precedence, 'lines' kept for back-compat (no other standard
changes). unused_function_check passes the function name. +7 tests (1093),
seedgo self-audit 100%, bypass schema documented.
Migration: converted 10 line-scoped entries to functions: across
drone/memory/skills; removed 3 dead memory/vector_search entries already
pointing past EOF (file is 152 lines). drone/memory/skills re-audit:
Unused_Function 100% (names verified live). Closes td-009.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
readme_check did its own modules/ and tests/ globs that bypassed the
central audit collector, so an in-place foo(disabled).py tripped a false
'missing module' violation and inflated README test counts. Wire
is_disabled_file into both globs (check_module_list, _count_test_functions).
+2 regression tests, 1086 green, self-audit 100%. Closes td-103.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEQZXCtgnF3NQtcttTErpq
Version bump 2.5.3 -> 2.6.0 (MINOR — ships compass v2, daemon scheduler, @backup
restoration, telegram skill, tiered prompts). Bumped in both pyproject.toml and
src/aipass/__init__.py. CHANGELOG top section enriched into a 2.6.0 release
roll-up so the GitHub Release notes read properly. Rides into PR640.
README Readme standard was at 75%: compass module/handler undocumented and the
test count had drifted. Added compass to the architecture tree + a Compass
command section, bumped tests 236->282, refreshed the date stamp. devpulse audit
back to 100%.
Batch of S243/S244 work held for PR640. Only devpulse has git write, so all
branches' changes (@memory, @prax, @hooks, @aipass, @skills, @flow, @backup,
@seedgo) land through this single commit.
Memory rollover (correctness):
- @hooks rollover hook now delegates to drone @memory rollover check/run — it
had been reading stale .trinity limits (moved to memory.config.json by
DPLAN-0210), falling back to a 600-line check that never fired, so rollover was
silently dead for weeks. compact.py reads the current list schema. Both fail loud.
- @memory removed the v1 line-count/600 fallback entirely — v2-only, fail-loud
(959 tests).
Retire-for-all (DPLAN-0215):
- Legacy global prompt fully removed across every runtime: global_loader.py +
tests deleted, hooks.json/project_hooks.json blocks stripped, bootstrap global
seeding removed, cadence default + bypass cleaned, global .md files archived.
Codex SessionStart + Claude cadence read the same tier files.
Hardcoded-path cleanup (seedgo #37):
- New HARDCODED_PATH checker (#37). @memory symbolic.py + @prax branch_detector.py
home paths -> dynamic/generic. Both 100% Hardcoded_Path.
- seedgo provider_hooks_snapshot.json fixture refreshed to the tiered baseline.
Genericization: patrick -> user across tracked source, docs, templates.
CHANGELOG: 2026-06-19 + 2026-06-23 sections added.
Closes the deployment gap — cadence_config.json + the settings.json bridge are machine-local (gitignored), so fresh clones needed the tiered wiring seeded from committed sources:
- cadence.py DEFAULTS (keystone): adds tier0(period 1) + navmap(period 5) to the code fallback, so a fresh clone with no cadence_config.json gets tiered cadence automatically (was defaulting tier0 to period 5).
- setup.sh: fresh-install bridge seed now emits tier0_kernel + navmap, drops global_prompt.
- provider_manifest.json: doctor update path adds the tiered entries on existing machines, drops global_prompt.
Convergence: the committed hooks.json (global_prompt enabled:false) means even a stale settings.json with a global bridge is skipped by the engine. 615/615 tests (1 new: test_defaults_include_tiered_loaders), seedgo 100%.
Harvested from Claude Code's skill-authoring spec:
- when_to_use frontmatter field (trigger phrases) on all 3 SKILL.md templates + github catalog exemplar; discovery scan surfaces it so agents see triggers without loading the full body.
- Per-step 'Done when:' success criteria in the Steps section.
- 'Use when / Do NOT use when' structure in the When to Use section.
252/252 tests pass.
Replaces the single 8k always-injected global prompt with cadence-tiered injection:
- Tier 0 (.aipass/tier0_kernel.md, ~2k) injects EVERY turn — identity grounding, the drone --help reflex, disaster-preventer rules. Folds DPLAN-0213 C1 (faithful-reporting) + C2 (no-gold-plating sub-agent brief).
- Tier 1 (.aipass/tier1_navmap.md, ~7.7k) injects every 5th turn + session-start + post-compaction — full agent roster, framework, conventions, plus a new Terminology section migrated from the S211 backup.
- Old global_prompt loader retired (disabled in hooks.json, removed from cadence wiring); aipass_global_prompt.md kept as a reference snapshot.
Engine (built by @hooks): per-loader period in cadence.py should_fire() (back-compatible: unset period falls back to global); new tier0_kernel + navmap handlers; bypass.json extended to cover the two new dynamically-dispatched handlers. 614/614 tests pass, seedgo @hooks 100%.
Live-verified: tier0 fires every turn, navmap on turn 0/5/10, turn counter advances once per turn (not per loader), no double-injection. Machine-local wiring (cadence_config.json, ~/.claude/settings.json bridge) updated on this host; fresh-clone seeding of those is a tracked follow-up.
PROMPT_STYLE.md reference updated to point at the tier files as canonical examples.
- PROMPT_STYLE.md: new 'Writing voice' section (file_path:line refs, no-colon-before-tool-call, no emojis, write-for-a-person, three-tier where-detail-lives) — harvested from Claude Code's own prompt
- devpulse local: blast-radius habit before any drone write-op (reversibility + scope)
- global + devpulse-local: S241 whitespace/structure cleanup (readable English restored)
Compass guidance now lives in the public local prompt (compass is public). Recall
-> @memory; decide/fork -> compass query; good/bad decision -> compass add;
Patrick fires /compass. Old gitignored private_prompt injection now redundant.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patrick fires /compass <rating> <note>; the model composes the decision text from
conversation context and stores via drone @devpulse compass add --source patrick.
The human-triggered answer to the 'noticing' problem. P4 (rate/archive/review)
already covered by P1+P2 — verified live (re-rate, archive-as-avoid-list, review
stamp, archived excluded from query).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Thin command layer over the P1 storage core: add/query/stats/rate/archive/review
via drone @devpulse compass. Ratings shown in query output ([GOOD]/[BAD]/...),
--db flag for testing, auto-discovered (no devpulse.py change). 18 cmd tests,
seedgo 29/29, no regressions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add @skills/@daemon/@commons/@backup to global prompt agent list; trim+restyle
devpulse local prompt to PROMPT_STYLE (single # headers, no emphasis, de-dup vs
global); smooth .claude culture doc (kill repeats, drop mechanical overlap).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A PID containing "429" (e.g. 14290) in the monitor's own header line was
substring-matched as an HTTP 429, mislabeling sandbox-abort (-4) bounces as
"API rate limit" and flaking test_sandbox_failure_sends_bounce in push CI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #640's only failing required check was Code scanning/CodeQL: 3 HIGH
py/clear-text-logging-sensitive-data alerts where get-secret printed raw secret
values to stdout. Research (OWASP, CodeQL rule source, secret-CLI survey)
confirmed a real exposure — acute for AIPass since it runs inside Claude Code,
which captures command stdout into model context, and the telegram skill
shelled out to get-secret and parsed the token from stdout.
@api (P1):
- NEW apps/modules/secrets.py — in-process cross-branch door (get_secret,
list_secrets) wrapping the auth handler; consumers import this, not the CLI.
- get_secret_cmd rewritten: masked summary by default ('slug: set (N chars)'),
--out FILE writes the raw value 0o600 and prints only the path, --list shows
slug names via console.print. All 3 raw-value print() sinks removed.
- bypass.json reasoning + README + help updated.
@skills (P2):
- telegram config._get_secret / list_bot_configs rewired from subprocess+stdout
parse to the in-process aipass.api.apps.modules.secrets API; subprocess/json
imports dropped. Tests + SKILL.md updated.
Also: seedgo test_checkers_batch2.py — comment the synthetic sk-or-v1 fixture
keys as FAKE (not real credentials).
Verified: @api 504 tests + seedgo 100%; telegram 452/452; skills 252/252; no
secret reaches stdout by any path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- telegram skill: register a minimal telethon sys.modules stub in the test
conftest so botfather_client tests (which patch telethon.*) run without the
optional MTProto library installed. Fixes 7 ModuleNotFoundError failures;
telegram suite now 452/452 green.
- pyrightconfig.json: add the root .venv site-packages to extraPaths (has
pytest + project deps) alongside memory's venv, so the @hooks auto_fix
pyright check stops emitting false 'Import pytest could not be resolved' on
every test file. CI does not run pyright; this is local-DX only.
Both CI-safe: telegram tests live under .aipass/ (excluded from umbrella
pytest) and pyright is not a CI gate, so PR #640 stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Once the collection-level blockers were fixed, the Windows runner finally ran the
suite and surfaced 7 pre-existing failures — all tests asserting Linux-only
behavior, while the production code already handles non-Linux gracefully:
- api test_secrets: chmod(0o000) can't make a file unreadable to its owner on
Windows (the 'unreadable -> None' precondition is unreachable)
- daemon test_scheduler_cron: patches fcntl.flock; fcntl is None on Windows
(scheduler_cron already skips locking on non-Unix)
- skills test_runner: system_status memory/uptime/processes/summary read Linux
/proc (skill returns a graceful error on Windows; disk test stays, it's portable)
Guard each with @pytest.mark.skipif(sys.platform == 'win32', reason=...). 68
tests pass on Linux, ruff clean, api+daemon audit 100%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The CI Linux seedgo-audit step failed: commons + daemon at 99%, readme 87%
('Directories in tree not found on disk: tools'). Their READMEs document tools/,
a gitignored branch-local runtime dir (like logs/, dropbox/) absent in CI's
tracked-only checkout. The readme-currency skip-list already covered logs/dropbox
but missed tools.
- Add 'tools' to the readme-currency runtime-dir skip set (readme_check.py)
- Test coverage in test_readme_content_checks.py
Verified: commons + daemon readme 100% (was 87%), overall 100% (was 99%);
seedgo self-audit 100%, 1060 seedgo tests pass. Work by @seedgo (FPLAN dispatch).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The custom norecursedirs in pyproject dropped pytest's default '.*' pattern, so
pytest recursed into .aipass/ scaffolding. The telegram skill bundled at
src/aipass/skills/.aipass/skills/telegram/tests/ (with __init__.py) made its
conftest resolve to module 'tests.conftest', colliding with branch tests/
conftest.py -> ImportPathMismatchError aborted collection on BOTH Linux CI and
Windows (the sole remaining green-CI blocker after the guard fix).
- Re-add '.*' to norecursedirs (skips .aipass/.trinity/.seedgo/... scaffolding)
- Verified: full src collection 9540 tests, no ImportPathMismatch; only the
telegram .aipass scaffold tests excluded (the single tracked test dir under
any dot-dir), all real branch tests still collected
Note: the telegram skill's bundled tests (7 failing locally) are out of umbrella
CI; skills owns stabilizing + properly integrating them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The cross-branch import guard's same-branch check used a POSIX-only path test,
so on Windows (backslash paths) it failed to recognize a branch importing its
OWN handlers -> ImportError at collection, failing all commons + 2 daemon tests
on the Windows CI runner. (Unmasked once the pathspec fix let collection proceed.)
- commons: '/commons/' substring -> 'commons' in Path(caller_file).parts
- daemon + skills: add .replace('\\','/') before the check (matches the idiom
already used by 15 other branches' guards)
- Convert AIPASS_DEBUG_GUARD debug print() -> sys.stderr.write (cli standard;
avoids import-time logger dependency inside the guard)
Security semantics unchanged: same-branch allowed, cross-branch still blocked
(verified cross-platform). commons+daemon audit 100%, 700 daemon+skills tests
pass, commons 449 tests pass. (skills local 99% = untracked skills_json orphans,
not in CI.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Disabled files (AIPass convention: rename name(disabled).py instead of delete)
are intentionally-parked inert code, but seedgo audited them as live source —
ai_mail's dashboard_sync(disabled).py dragged it to 99%, blocking green CI.
- Add is_disabled_file() + DISABLED_FILE_MARKER to skip_dirs.py (single source
of truth alongside SOURCE_SKIP_DIRS)
- Apply in branch_audit, dead_code, unused_function, test_quality checkers +
test_map function_scanner + checklist directory mode
- New test in test_coverage_audit.py
Verified: ai_mail 99->100%, seedgo self-audit 100%, 1060 seedgo tests pass,
@cli/@flow unchanged at 100%.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The commons craft/trade/capsule subsystem lives at apps/handlers/artifacts/
but the blanket 'artifacts/' ignore (meant for branch-local runtime dirs)
silently excluded it from git. The tracked test_artifacts.py imports it, so
CI hit ImportError at collection while local passed (files present locally).
- Add *.py-scoped negation in .gitignore (keeps logs/ + __pycache__ ignored)
- Track artifact_ops.py, trade_ops.py, capsule_ops.py, __init__.py
- 19 test_artifacts.py tests pass; imports resolve
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add pathspec>=0.12 to root pyproject dependencies (was undeclared, caused
ModuleNotFoundError in CI across all Python versions + Windows)
- Rename drive_test.py -> drive_check.py so pytest stops collecting the module
as a test file; update MODULE_NAME, PRIMARY_COMMAND, help text, README, tests
- 220 backup tests pass, seedgo 100% all 37 standards
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>