1
0
forked from jason/echo

Phase 1: mechanical echo→chorus rename with back-compat shims

Identity rename, no behavior change (CHORUS-PLAN.md Phase 1):
- Plugin echo-memory → chorus-memory: manifest (v2.0.0-alpha.1), skill dir,
  16 scripts (chorus.py, chorus_config.py, …), EchoError → ChorusError,
  /chorus-* commands, hook paths, docs, scaffold seeds, eval harness,
  build.py. Docs endpoint → chorusapi.mpm.to.
- Env ECHO_* → CHORUS_*; config → ~/.claude/chorus-memory/config.json;
  state dir → ~/.chorus-memory/; marker → _agent/chorus-vault.md.

Back-compat shims (one major version):
- chorus_config aliases legacy ECHO_* env at import; reads a legacy
  echo-memory config.json when no CHORUS config exists (writes never
  land there); doctor/config report the legacy source.
- State dir honors an existing ~/.echo-memory when the new dir is absent
  (offline queue not stranded).
- Marker dual-probe in load/doctor/bootstrap/lint/sweep/migrate: a
  pre-fork _agent/echo-vault.md counts as bootstrapped; bootstrap repair
  won't write a second marker; routing gains agent-marker-legacy (GET).

Verified: 25/25 unit tests, scaffold + routing-sync checks, 4 mock e2e
suites, run_eval metrics unchanged, +6 shim smoke tests green.
Rebuilt chorus-memory.plugin (79 entries).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 13:35:51 -05:00
parent ff2f2efd0b
commit d366ca4032
98 changed files with 1312 additions and 1164 deletions
+10 -10
View File
@@ -3,7 +3,7 @@
A dry-run previews and writes NOTHING; --apply routes each proposal through capture
(creating notes, the inbox line, and skipping low-confidence items). Drives the real
echo.py against eval/mock_olrapi.py. No creds, no live vault.
chorus.py against eval/mock_olrapi.py. No creds, no live vault.
Run: python test_reflect.py [--port 8850]
"""
@@ -20,7 +20,7 @@ import urllib.request
from pathlib import Path
HERE = Path(__file__).resolve().parent
ECHO = HERE.parent / "echo-memory.plugin.src" / "skills" / "echo-memory" / "scripts" / "echo.py"
CHORUS = HERE.parent / "chorus-memory.plugin.src" / "skills" / "chorus-memory" / "scripts" / "chorus.py"
KEY = "test-key-not-a-real-secret"
failures = []
@@ -50,9 +50,9 @@ def main():
except Exception as e: # noqa: BLE001
return getattr(e, "code", 0), ""
def echo(*args, stdin=None):
env = dict(os.environ, ECHO_BASE=base, ECHO_KEY=KEY, ECHO_VERIFY="1", ECHO_TODAY="2026-06-22")
return subprocess.run([sys.executable, str(ECHO), *args], input=stdin,
def chorus(*args, stdin=None):
env = dict(os.environ, CHORUS_BASE=base, CHORUS_KEY=KEY, CHORUS_VERIFY="1", CHORUS_TODAY="2026-06-22")
return subprocess.run([sys.executable, str(CHORUS), *args], input=stdin,
capture_output=True, text=True, env=env)
def ground(path):
@@ -65,10 +65,10 @@ def main():
urllib.request.urlopen(f"{base}/__debug__reset", data=b"", timeout=1); break
except Exception:
time.sleep(0.1)
http("PUT", f"{base}/vault/_agent/echo-vault.md", "---\nschema_version: 4\n---\n# marker\n")
http("PUT", f"{base}/vault/_agent/chorus-vault.md", "---\nschema_version: 4\n---\n# marker\n")
proposals = [
{"title": "Acme Corp", "kind": "company", "body": "A vendor ECHO integrates with.", "confidence": 0.9},
{"title": "Acme Corp", "kind": "company", "body": "A vendor CHORUS integrates with.", "confidence": 0.9},
{"title": "Use uv not pip", "kind": "semantic", "body": "Jason standardizes on uv.", "confidence": 0.95},
{"title": "half-formed idea", "inbox": True, "confidence": 0.9},
{"title": "Maybe relevant", "kind": "concept", "confidence": 0.2}, # below floor -> skipped
@@ -77,13 +77,13 @@ def main():
json.dump(proposals, pfile); pfile.close()
# dry-run: previews, writes nothing
r = echo("reflect", pfile.name)
r = chorus("reflect", pfile.name)
check("dry-run previews", "dry-run" in r.stdout and "Acme Corp" in r.stdout, r.stdout)
check("dry-run drops the low-confidence proposal", "Maybe relevant" not in r.stdout, r.stdout)
check("dry-run writes nothing", ground("resources/companies/acme-corp.md") is None)
# --apply: routes each through capture
r = echo("reflect", pfile.name, "--apply")
r = chorus("reflect", pfile.name, "--apply")
check("apply reports applied count", "applied" in r.stdout, r.stdout + r.stderr)
check("apply creates the company note",
(ground("resources/companies/acme-corp.md") or "").find("type: company") >= 0)
@@ -94,7 +94,7 @@ def main():
ground("resources/concepts/maybe-relevant.md") is None)
# stdin path also works (proposals piped, not a file)
r = echo("reflect", "-", stdin=json.dumps([{"title": "Piped Co", "kind": "company", "confidence": 0.9}]))
r = chorus("reflect", "-", stdin=json.dumps([{"title": "Piped Co", "kind": "company", "confidence": 0.9}]))
check("reflect reads proposals from stdin", "Piped Co" in r.stdout, r.stdout + r.stderr)
print(f"\n{len(failures)} failure(s)" if failures else "\nall reflect tests passed")