From 2b07b7e3724f2f62e0e17e38fd7c1c72c89120f7 Mon Sep 17 00:00:00 2001 From: sshekhar563 Date: Tue, 14 Jul 2026 20:56:23 +0530 Subject: [PATCH 1/3] fix(#286): correct eternal storage CLI examples and catch unknown-tier errors --- README.md | 4 ++-- rfc/RFC-005-ETERNAL-STORAGE-PROVIDER.md | 4 ++-- src/soul_protocol/cli/main.py | 6 +++++- tests/test_eternal/test_cli_eternal.py | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1887e568..17c3f236 100644 --- a/README.md +++ b/README.md @@ -381,8 +381,8 @@ The `EmbeddingProvider` interface is defined in `spec/`. Swap in OpenAI, Cohere, ## Eternal storage ```bash -soul archive aria.soul --tiers local,ipfs -soul recover aria.soul --source ipfs +soul archive aria.soul -t ipfs -t arweave +soul recover QmRef123... --tier ipfs --output recovered.soul soul eternal-status aria.soul ``` diff --git a/rfc/RFC-005-ETERNAL-STORAGE-PROVIDER.md b/rfc/RFC-005-ETERNAL-STORAGE-PROVIDER.md index a6ed9663..258e4286 100644 --- a/rfc/RFC-005-ETERNAL-STORAGE-PROVIDER.md +++ b/rfc/RFC-005-ETERNAL-STORAGE-PROVIDER.md @@ -148,8 +148,8 @@ itself. This provides: The runtime supports archiving to multiple tiers simultaneously: ```bash -soul archive aria.soul --tiers local,ipfs -soul recover aria.soul --source ipfs +soul archive aria.soul -t ipfs -t arweave +soul recover QmRef123... --tier ipfs --output recovered.soul soul eternal-status aria.soul ``` diff --git a/src/soul_protocol/cli/main.py b/src/soul_protocol/cli/main.py index fa56e16a..c071bcfa 100644 --- a/src/soul_protocol/cli/main.py +++ b/src/soul_protocol/cli/main.py @@ -906,7 +906,11 @@ async def _archive(): manager.register(MockIPFSProvider()) manager.register(MockArweaveProvider()) manager.register(MockBlockchainProvider()) - results = await manager.archive(soul_data, soul.did, tiers=tier_list) + try: + results = await manager.archive(soul_data, soul.did, tiers=tier_list) + except ValueError as exc: + console.print(f"[red]Archive failed:[/red] {exc}") + return # Persist archive results into the .soul manifest _update_soul_manifest(path, results) diff --git a/tests/test_eternal/test_cli_eternal.py b/tests/test_eternal/test_cli_eternal.py index 853df295..5b1afa1c 100644 --- a/tests/test_eternal/test_cli_eternal.py +++ b/tests/test_eternal/test_cli_eternal.py @@ -61,3 +61,18 @@ def test_recover_missing_reference(tmp_path): assert result.exit_code == 0 assert "failed" in result.output.lower() or "Recovery failed" in result.output + + +def test_archive_unknown_tier(tmp_path): + """archive with an unknown tier prints a clean error, not a traceback.""" + runner = CliRunner() + soul_path = str(tmp_path / "unknown-tier.soul") + + runner.invoke(cli, ["birth", "TierBot", "-o", soul_path]) + result = runner.invoke(cli, ["archive", soul_path, "-t", "local"]) + + assert result.exit_code == 0 + assert "Archive failed" in result.output + assert "local" in result.output + # Must NOT contain a raw traceback + assert "Traceback" not in result.output From f442aa73c09a05e1871546df611d974b45a00649 Mon Sep 17 00:00:00 2001 From: sshekhar563 Date: Fri, 17 Jul 2026 14:10:47 +0530 Subject: [PATCH 2/3] fix(#286): sync cli-reference.md, exit 1 on failure, bump headers --- docs/cli-reference.md | 2 +- src/soul_protocol/cli/main.py | 4 +++- tests/test_eternal/test_cli_eternal.py | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/cli-reference.md b/docs/cli-reference.md index fd21a1b0..d53ab721 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -1301,7 +1301,7 @@ Archive a `.soul` file to eternal storage tiers (IPFS, Arweave, Blockchain). Use ```bash soul archive my-soul.soul -soul archive .soul/ --tiers ipfs arweave +soul archive .soul/ -t ipfs -t arweave ``` **Arguments:** diff --git a/src/soul_protocol/cli/main.py b/src/soul_protocol/cli/main.py index c071bcfa..1567920a 100644 --- a/src/soul_protocol/cli/main.py +++ b/src/soul_protocol/cli/main.py @@ -1,4 +1,6 @@ # cli/main.py — Click CLI for the Soul Protocol (org + user groups + runtime commands) +# Updated: 2026-07-17 (#286) — Catch unknown-tier ValueError in ``soul archive``; +# exit 1 so scripts can detect failure. # Updated: 2026-04-29 (#42) — Trust chain commands: ``soul verify`` checks # integrity of a soul's signed action history. ``soul audit`` prints a # human-readable timeline; supports --filter and --limit; --json @@ -910,7 +912,7 @@ async def _archive(): results = await manager.archive(soul_data, soul.did, tiers=tier_list) except ValueError as exc: console.print(f"[red]Archive failed:[/red] {exc}") - return + raise SystemExit(1) # Persist archive results into the .soul manifest _update_soul_manifest(path, results) diff --git a/tests/test_eternal/test_cli_eternal.py b/tests/test_eternal/test_cli_eternal.py index 5b1afa1c..45f18d53 100644 --- a/tests/test_eternal/test_cli_eternal.py +++ b/tests/test_eternal/test_cli_eternal.py @@ -1,5 +1,7 @@ # test_eternal/test_cli_eternal.py — CLI tests for eternal storage commands. # Created: 2026-03-06 — Tests archive, recover, and eternal-status commands. +# Updated: 2026-07-17 (#286) — Added test_archive_unknown_tier; verifies +# clean error message and exit code 1 for unregistered tiers. from __future__ import annotations @@ -71,7 +73,7 @@ def test_archive_unknown_tier(tmp_path): runner.invoke(cli, ["birth", "TierBot", "-o", soul_path]) result = runner.invoke(cli, ["archive", soul_path, "-t", "local"]) - assert result.exit_code == 0 + assert result.exit_code == 1 assert "Archive failed" in result.output assert "local" in result.output # Must NOT contain a raw traceback From 968e534bd3ed77159b835befef9379259c71b893 Mon Sep 17 00:00:00 2001 From: sshekhar563 Date: Mon, 27 Jul 2026 13:37:29 +0530 Subject: [PATCH 3/3] fix(#286): restore deleted header entries, add two-flag test (#301 review 2) Restored 10 accidentally deleted # Updated: changelog entries (#284, #247, #231, #192, #142, #191, #203, #201, #189, #160) that were erased when prepending the #286 header line. Added test_archive_two_tier_flags for -t ipfs -t arweave form. --- src/soul_protocol/cli/main.py | 62 ++++++++++++++++++++++++++ tests/test_eternal/test_cli_eternal.py | 13 ++++++ 2 files changed, 75 insertions(+) diff --git a/src/soul_protocol/cli/main.py b/src/soul_protocol/cli/main.py index f53c856d..ccad9ca5 100644 --- a/src/soul_protocol/cli/main.py +++ b/src/soul_protocol/cli/main.py @@ -1,6 +1,68 @@ # cli/main.py — Click CLI for the Soul Protocol (org + user groups + runtime commands) # Updated: 2026-07-17 (#286) — Catch unknown-tier ValueError in ``soul archive``; # exit 1 so scripts can detect failure. +# Updated: 2026-07-18 (#284) — Replaced ~45 private attribute accesses +# (soul._memory, m._episodic, m._graph_entities.clear(), etc.) with public +# MemoryManager API methods. `repair --rebuild-graph` now calls +# manager.rebuild_graph() instead of clearing internals directly. +# Updated: 2026-07-24 (#247) — `soul recall --json` now emits a `score` field +# per result (the entry's ACT-R activation score). Added a `--min-relevance` +# flag (0.0-1.0) that plumbs through to recall() as the graded relevance +# floor; weak query matches below the floor are dropped. Default 0.0 leaves +# recall behaviour unchanged. +# Updated: 2026-05-05 (#231) — Adds `soul note ""` — the dedup +# pipeline counterpart to `soul remember`. Routes through Soul.note() so +# repeated calls with similar content collapse into SKIP / MERGE rather +# than accumulating duplicate semantic facts. Flags: --no-dedup (force +# blunt write), --no-contradictions (skip contradiction detection, +# plumbed for follow-up). Output panel reports CREATED / SKIPPED / +# MERGED with the relevant memory IDs and similarity score. +# +# Naming deviation from the brief: the brief named the new command +# `soul observe`, but a pre-existing `soul observe` (cognitive +# pipeline, --user-input + --agent-output) lives later in this file +# and would shadow the new handler at click dispatch time. Registered +# as `soul note` to match the runtime method (Soul.note()). The +# follow-up issue should rename / consolidate. +# Updated: 2026-05-02 (#192) — Brain-aligned memory update primitive commands. +# - `soul confirm ` refresh activation on a verified memory. +# - `soul update --patch ` in-place patch within the +# 1-hour reconsolidation window. PE band [0.2, 0.85). The CLI calls +# recall against the current entry content first so the window opens +# in this single invocation. +# - `soul purge --id --apply` hard delete with .soul.bak +# and a payload-hash audit entry. Reserved for GDPR / safety paths. +# - `soul reinstate ` restore retrieval_weight to 1.0. +# - `soul forget` semantics shift to weight-decay (single-id and bulk). +# Help text updated; behaviour was a hard delete before. +# - `soul upgrade --to 0.5.0 [--dry-run]` derive the supersedes +# back-edge from existing superseded_by. Pydantic v2 backfills the +# other new defaults at load time. +# Updated: 2026-05-02 (#142) — Wire `soul optimize ` from +# cli/optimize.py. Drives the autonomous self-improvement loop: eval → propose +# knob change → re-eval → keep/revert. Defaults to dry-run; --apply keeps the +# winning trajectory and appends soul.optimize.applied trust chain entries. +# Updated: 2026-04-30 (#191) — Wire `soul diff ` from cli/diff.py. +# Renders a structured comparison (identity / OCEAN / state / memories / +# bond / skills / trust chain / self-model / evolution) in text, json, or +# markdown. Read-only; raises a clean error on schema mismatch. +# Updated: 2026-04-30 (#203) — `soul prune-chain` lands as the touch-time +# pruning stub for v0.5.0. Dry-run preview by default, --apply to execute, +# --keep N for explicit length, defaults to Biorhythms.trust_chain_max_entries. +# Mirrors the `soul cleanup` / `soul forget` safety pattern. +# Updated: 2026-04-30 (#201) — ``soul audit`` Rich table now includes a +# Summary column derived from each entry's per-action human-readable +# description (set at append time via TrustChainManager.append's new +# ``summary=`` parameter or the action-keyed default formatter +# registry). New ``--no-summary`` flag hides the column for callers +# who only want the hash. JSON output always includes ``summary``. +# Updated: 2026-04-30 (#189) — Wire `soul journal {init,append,query}` +# subcommand group from cli/journal.py. Lets shell hooks, CI, and non-Python +# runtimes append structured events without spinning up a Python session. +# Updated: 2026-04-29 (#160) — `soul eval` command for YAML-driven soul-aware +# evals. Registers from cli/eval_cmd.py. Runs one .yaml spec or every +# .yaml under a directory; passes/fails based on per-case scoring; exit +# code 0 = all pass (skipped allowed), 1 = any fail/error. # Updated: 2026-04-29 (#42) — Trust chain commands: ``soul verify`` checks # integrity of a soul's signed action history. ``soul audit`` prints a # human-readable timeline; supports --filter and --limit; --json diff --git a/tests/test_eternal/test_cli_eternal.py b/tests/test_eternal/test_cli_eternal.py index 45f18d53..cfe21851 100644 --- a/tests/test_eternal/test_cli_eternal.py +++ b/tests/test_eternal/test_cli_eternal.py @@ -78,3 +78,16 @@ def test_archive_unknown_tier(tmp_path): assert "local" in result.output # Must NOT contain a raw traceback assert "Traceback" not in result.output + + +def test_archive_two_tier_flags(tmp_path): + """archive with repeated -t flags archives to multiple tiers (#286 review).""" + runner = CliRunner() + soul_path = str(tmp_path / "multi-tier.soul") + + runner.invoke(cli, ["birth", "MultiBot", "-o", soul_path]) + result = runner.invoke(cli, ["archive", soul_path, "-t", "ipfs", "-t", "arweave"]) + + assert result.exit_code == 0 + assert "ipfs" in result.output.lower() + assert "arweave" in result.output.lower()