diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62b454b..ea100be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,14 @@ jobs: - name: Check formatting run: cargo fmt --all -- --check + release-guards: + name: Release Guard Scripts + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Run release guard tests + run: bash scripts/release-guards-test.sh + clippy: name: Clippy runs-on: ubuntu-24.04 @@ -232,7 +240,7 @@ jobs: # Summary job that depends on all other jobs ci-success: name: CI Success - needs: [fmt, clippy, test, build, doc, e2e, benchmark-smoke] + needs: [fmt, clippy, test, build, doc, e2e, benchmark-smoke, release-guards] runs-on: ubuntu-24.04 if: always() steps: @@ -244,7 +252,8 @@ jobs: [[ "${{ needs.build.result }}" != "success" ]] || \ [[ "${{ needs.doc.result }}" != "success" ]] || \ [[ "${{ needs.e2e.result }}" != "success" ]] || \ - [[ "${{ needs.benchmark-smoke.result }}" != "success" ]]; then + [[ "${{ needs.benchmark-smoke.result }}" != "success" ]] || \ + [[ "${{ needs.release-guards.result }}" != "success" ]]; then echo "One or more jobs failed" exit 1 fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e3e31c1..ce9d3f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,16 +7,62 @@ on: workflow_dispatch: inputs: version: - description: 'Version to release (e.g., 0.2.0)' + description: 'Version to release (e.g., 3.1.0, no leading v)' required: true type: string + dry_run: + description: 'Run guards (and, if they pass, builds) but do not publish a GitHub Release or push a tag' + required: false + type: boolean + default: false env: CARGO_TERM_COLOR: always jobs: + guard: + name: Release guards + runs-on: ubuntu-latest + outputs: + version: ${{ steps.meta.outputs.version }} + tag: ${{ steps.meta.outputs.tag }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Fetch origin/main + run: git fetch --no-tags origin '+refs/heads/main:refs/remotes/origin/main' + + - name: Resolve version + id: meta + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + raw="${{ github.event.inputs.version }}" + else + raw="${GITHUB_REF_NAME}" + fi + raw="${raw#v}" + echo "version=${raw}" >> "$GITHUB_OUTPUT" + echo "tag=v${raw}" >> "$GITHUB_OUTPUT" + + - name: Guard tagged commit is on main and version matches Cargo.toml + run: | + bash scripts/release-guards.sh \ + --version "${{ steps.meta.outputs.version }}" \ + --sha "${GITHUB_SHA}" \ + --main-ref origin/main \ + --cargo Cargo.toml + + - name: Guard CHANGELOG.md has a matching section + run: | + bash scripts/changelog-section.sh "${{ steps.meta.outputs.version }}" CHANGELOG.md \ + > "$RUNNER_TEMP/release-notes.md" + test -s "$RUNNER_TEMP/release-notes.md" + build: name: Build (${{ matrix.name }}) + needs: guard runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -46,16 +92,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Get version - id: version - shell: bash - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT - fi - - name: Install system dependencies (Linux) if: runner.os == 'Linux' run: | @@ -123,7 +159,7 @@ jobs: - name: Create archive directory shell: bash run: | - VERSION=${{ steps.version.outputs.version }} + VERSION=${{ needs.guard.outputs.version }} ARCHIVE_DIR="agent-memory-${VERSION}-${{ matrix.name }}" mkdir -p "dist/${ARCHIVE_DIR}" @@ -152,7 +188,7 @@ jobs: if: runner.os != 'Windows' shell: bash run: | - VERSION=${{ steps.version.outputs.version }} + VERSION=${{ needs.guard.outputs.version }} ARCHIVE_DIR="agent-memory-${VERSION}-${{ matrix.name }}" cd dist tar -czvf "${ARCHIVE_DIR}.tar.gz" "${ARCHIVE_DIR}" @@ -162,7 +198,7 @@ jobs: if: runner.os == 'Windows' shell: pwsh run: | - $VERSION = "${{ steps.version.outputs.version }}" + $VERSION = "${{ needs.guard.outputs.version }}" $ARCHIVE_DIR = "agent-memory-${VERSION}-${{ matrix.name }}" cd dist Compress-Archive -Path $ARCHIVE_DIR -DestinationPath "${ARCHIVE_DIR}.zip" @@ -177,25 +213,18 @@ jobs: release: name: Create Release - needs: build - if: always() && !cancelled() + needs: [guard, build] + # success() is required: a custom `if` replaces the implicit "needed jobs + # succeeded" check. The previous `if: always() && !cancelled()` is how a + # partial set of archives could ship. dry_run skips publish after a green + # guard+build, which is the live way to verify the guards without a tag. + if: ${{ success() && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true') }} runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - - name: Get version - id: version - run: | - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - echo "tag=v${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT - else - echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT - echo "tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT - fi - - name: Download all artifacts uses: actions/download-artifact@v4 with: @@ -203,31 +232,50 @@ jobs: pattern: release-* merge-multiple: true - - name: List artifacts - run: ls -laR artifacts/ + - name: Require all five platform archives + run: | + ls -laR artifacts/ + missing=0 + for name in linux-x86_64 linux-aarch64 macos-x86_64 macos-aarch64 windows-x86_64; do + if ! ls artifacts/agent-memory-${{ needs.guard.outputs.version }}-${name}.* >/dev/null 2>&1; then + echo "::error::missing archive for ${name}" + missing=1 + fi + done + if [[ "$missing" -ne 0 ]]; then + echo "Refusing to publish a partial release." + exit 1 + fi - name: Generate checksums run: | cd artifacts - sha256sum *.tar.gz *.zip > SHA256SUMS.txt 2>/dev/null || sha256sum *.tar.gz > SHA256SUMS.txt 2>/dev/null || echo "No artifacts to checksum" - cat SHA256SUMS.txt 2>/dev/null || true + sha256sum *.tar.gz *.zip > SHA256SUMS.txt + cat SHA256SUMS.txt + + - name: Release notes from CHANGELOG.md + run: | + bash scripts/changelog-section.sh "${{ needs.guard.outputs.version }}" CHANGELOG.md \ + > release-notes.md + test -s release-notes.md - name: Create tag (workflow_dispatch only) if: github.event_name == 'workflow_dispatch' run: | git config user.name "GitHub Actions" git config user.email "actions@github.com" - git tag -a ${{ steps.version.outputs.tag }} -m "Release ${{ steps.version.outputs.tag }}" - git push origin ${{ steps.version.outputs.tag }} + git tag -a ${{ needs.guard.outputs.tag }} -m "Release ${{ needs.guard.outputs.tag }}" "${GITHUB_SHA}" + git push origin ${{ needs.guard.outputs.tag }} - name: Create GitHub Release uses: softprops/action-gh-release@v1 with: - tag_name: ${{ steps.version.outputs.tag }} - name: Release ${{ steps.version.outputs.version }} + tag_name: ${{ needs.guard.outputs.tag }} + name: Release ${{ needs.guard.outputs.version }} draft: false - prerelease: ${{ contains(steps.version.outputs.version, '-') }} - generate_release_notes: true + prerelease: ${{ contains(needs.guard.outputs.version, '-') }} + generate_release_notes: false + body_path: release-notes.md files: | artifacts/*.tar.gz artifacts/*.zip diff --git a/.planning/MILESTONES.md b/.planning/MILESTONES.md index 5b845b1..0dee9c5 100644 --- a/.planning/MILESTONES.md +++ b/.planning/MILESTONES.md @@ -1,6 +1,22 @@ # Project Milestones: Agent Memory -## v3.1 Make It True (Shipped: 2026-08-31) +## v3.2 Prove It (In progress: 2026-09-01) + +**Goal:** v3.1 made the claims true; v3.2 makes them provable. A real LOCOMO +number, evidence behind every "Solid", a daemon someone can run for a week, +and a repo whose backlog is public. + +**Spec:** `docs/plans/v3.2-prove-it-plan.md` + +**Phases:** 59 Guardrails and Inventory (executing), 60 Real Numbers, 61 +Operate It, 62 Cross-encoder rerank (conditional on #39). + +**Known Gaps (now issues):** #39 LOCOMO run, #40 vector/topic quality, #41 +backfill, #42 install-service, #43 TOC rebuild, #44 cross-encoder. + +--- + +## v3.1 Make It True (Shipped: 2026-09-01) **Delivered:** no new capabilities. Four phases closing the gap between what the project claimed and what it did, after a v3.0 verification document self-graded diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md index f192113..6dbaeb2 100644 --- a/.planning/PROJECT.md +++ b/.planning/PROJECT.md @@ -2,26 +2,30 @@ ## Current State -**Version:** v3.0 (In Progress) -**Status:** Building retrieval orchestration, CLI API, and benchmark suite +**Version:** v3.1.0 (Shipped 2026-09-01) +**Status:** v3.2 "Prove It" in execution — make the v3.1 claims provable -## Current Milestone: v3.0 Competitive Parity & Benchmarks +## Current Milestone: v3.2 Prove It -**Goal:** Close the three gaps that keep Agent-Memory from being the category leader: retrieval pipeline orchestration, a dead-simple CLI API, and a benchmark suite that produces a publishable LOCOMO score. +**Goal:** a stranger arriving from a Show HN link finds a real LOCOMO number, +evidence behind every "Solid", a daemon they can run for a week, and a repo +that looks alive. No new capabilities. v3.1 made the claims true; v3.2 makes +them provable. -**Target features:** -- Retrieval Orchestrator crate (query expansion, RRF fusion, LLM reranking) -- Simple `memory` CLI binary (search, context, recall, add, timeline, summary) -- Benchmark suite with custom harness + LOCOMO adapter -- Positioning writeup (side quest, not a GSD phase) +**Target work:** +- Release pipeline guards (tag on main, crate version matches tag, all five platforms) — Phase 59 +- Committed LOCOMO LLM-judge result on the real dataset — Phase 60 / #39 +- Quality fixtures for vector search and the topic graph — Phase 60 / #40 +- Backfill, `install-service`, offline TOC rebuild, panic audit — Phase 61 / #41 #42 #43 +- Claude Code plugin registration + installer uninstall/status — Phase 61 +- Cross-encoder rerank only if 60-02 says retrieval is the bottleneck — Phase 62 / #44 -**Previous version:** v2.7 (Shipped 2026-03-22) — Multi-runtime installer with 6 converters +**Previous version:** v3.1.0 (Shipped 2026-09-01) — Make It True. No new +capabilities; closed the claim/reality gap (orchestrator reachable, hybrid +actually fuses, honest benchmarks, shop window). See +`docs/plans/v3.1-make-it-true-plan.md`. -**Spec reference:** `docs/superpowers/specs/2026-03-21-v3-competitive-parity-design.md` -**Plan references:** -- `docs/superpowers/plans/2026-03-21-v3-phase-a-retrieval-orchestrator.md` -- `docs/superpowers/plans/2026-03-21-v3-phase-b-simple-cli-api.md` -- `docs/superpowers/plans/2026-03-21-v3-phase-c-benchmark-suite.md` +**Spec reference:** `docs/plans/v3.2-prove-it-plan.md` The system implements a complete 6-layer cognitive stack with control plane, multi-agent support, semantic dedup, retrieval quality filtering, multi-runtime installer, and comprehensive testing: - Layer 0: Raw Events (RocksDB) — agent-tagged, dedup-aware (store-and-skip-outbox) @@ -31,23 +35,23 @@ The system implements a complete 6-layer cognitive stack with control plane, mul - Layer 4: Semantic Teleport (Vector/HNSW) — also used for dedup similarity checks - Layer 5: Conceptual Discovery (Topic Graph) — agent-filtered queries - Layer 6: Ranking Policy (salience, usage, novelty, lifecycle) + StaleFilter (time-decay, supersession) -- Control: Retrieval Policy (intent routing, tier detection, fallbacks) +- Control: Retrieval Policy (intent routing, tier detection, fallbacks) + MemoryOrchestrator (RRF fusion, optional LLM rerank, explainability) - Dedup: InFlightBuffer + HNSW composite gate, configurable threshold, fail-open -- Installer: memory-installer crate with RuntimeConverter trait, 6 converters, tool mapping tables -- Adapters: Claude Code, OpenCode, Gemini CLI, Copilot CLI, Codex CLI (via installer) +- Installer: memory-installer crate with RuntimeConverter trait, 5 converters (Claude, Gemini, Codex, Copilot, generic skills), tool mapping tables +- Adapters: Claude Code, Gemini CLI, Copilot CLI, Codex CLI (via installer). OpenCode removed in v3.1 Phase 57 — the converter reported success and wrote nothing - Discovery: ListAgents, GetAgentActivity, agent-filtered topics -- Testing: 46 cargo E2E tests + 144 bats CLI tests across 5 CLIs -- CI/CD: Dedicated E2E job + CLI matrix report in GitHub Actions -- Setup: Quickstart, full guide, agent setup docs + 4 wizard-style setup skills -- Benchmarks: perf_bench harness with baseline metrics across all retrieval layers +- Testing: 1,205 workspace + 60 e2e cargo tests; 114 bats CLI tests; Tier 1 (Claude Code, Codex) gates PRs, Tier 2 (Gemini, Copilot) weekly +- CI/CD: Dedicated E2E job + CLI matrix report; rust-toolchain pinned to 1.97 +- Setup: Quickstart, full guide, agent setup docs + wizard-style setup skills +- Benchmarks: honest custom harness (real recall@k) + LOCOMO adapter v2; committed results are mock-backend / mock-judge until #39 -~56,400 LOC Rust across 15 crates. memory-installer with 6 runtime converters. 46 E2E tests + 144 bats tests. Cross-CLI matrix report. +~64,626 LOC Rust across 20 crates. First full-platform GitHub Release: v3.1.0. ## What This Is **Agent Memory is a cognitive architecture for agents** — not just a memory system. -A local, append-only conversational memory system for AI agents (Claude Code, OpenCode, Gemini CLI, GitHub Copilot CLI) that supports agentic search via a permanent hierarchical Table of Contents (TOC), grounded in time-based navigation. The TOC acts as a Progressive Disclosure Architecture: the agent always starts with summaries and navigates downward only when needed. Indexes (vector/BM25) are accelerators, not dependencies. +A local, append-only conversational memory system for AI agents (Claude Code, Gemini CLI, GitHub Copilot CLI, Codex CLI) that supports agentic search via a permanent hierarchical Table of Contents (TOC), grounded in time-based navigation. The TOC acts as a Progressive Disclosure Architecture: the agent always starts with summaries and navigates downward only when needed. Indexes (vector/BM25) are accelerators, not dependencies. **See:** [Cognitive Architecture Manifesto](../docs/COGNITIVE_ARCHITECTURE.md) for the complete philosophy. @@ -270,11 +274,17 @@ Agent Memory implements a layered cognitive architecture: ### Deferred / Future -- Cross-project unified memory - Per-agent dedup scoping - Consolidation hook (extract durable knowledge from events, needs NLP/LLM) -- True daemonization (double-fork on Unix) -- API-based summarizer wiring (OpenAI/Anthropic) +- True daemonization (double-fork on Unix) — v3.2 ships launchd/systemd unit files instead (#42); double-fork stays deferred because it does not survive reboot +- Cross-encoder rerank — extension point returns `NotImplemented`; build only if #39 shows retrieval is the bottleneck (#44) +- REST/HTTP endpoint, Python SDK, memory views UI — v3.3+ (new capabilities; v3.2's job is proof and operability) + +### Shipped after this list was first written + +- API-based summarizer wiring (OpenAI/Anthropic) — Phase 51.5, PR #27, 2026-04-28 +- Cross-project federated query — Phase 53.5, PR #25; status remains Experimental +- Retrieval orchestrator reachable from shipped binaries — v3.1 Phase 54, PR #32 ### Out of Scope @@ -289,7 +299,7 @@ Agent Memory implements a layered cognitive architecture: **Ingestion via Hooks (Passive Capture)** -Conversations are captured via agent hooks (Claude Code, OpenCode, Gemini CLI, GitHub Copilot CLI). Hook handlers send events to the daemon via gRPC. This is zero-token-overhead passive listening. +Conversations are captured via agent hooks (Claude Code, Gemini CLI, GitHub Copilot CLI, Codex CLI). Hook handlers send events to the daemon via gRPC. This is zero-token-overhead passive listening. Event types (1:1 from hooks): | Hook Event | Memory Event | @@ -379,8 +389,8 @@ CLI client and agent skill query the daemon. Agent receives TOC navigation tools | Match expressions for tool maps | Compile-time exhaustive, zero overhead vs HashMap | ✓ Validated v2.7 | | Write-interceptor for dry-run | Single write_files() handles dry-run; converters produce data only | ✓ Validated v2.7 | | Hooks generated per-converter | Each runtime's hook mechanism too different for canonical YAML format | ✓ Validated v2.7 | -| OpenCode converter as stub | Full impl deferred; OpenCode runtime format still evolving | — Deferred v2.7 | +| OpenCode converter as stub | Full impl deferred; OpenCode runtime format still evolving | Resolved-by-removal v3.1 Phase 57 (#36) | | Archive adapters (not delete) | One release cycle before removal; README stubs redirect to installer | ✓ Validated v2.7 | --- -*Last updated: 2026-03-22 after v3.0 milestone start* +*Last updated: 2026-09-01 after v3.1.0 shipped and v3.2 Prove It adopted* diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 99a82f3..27abccd 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -11,8 +11,9 @@ - ✅ **v2.5 Semantic Dedup & Retrieval Quality** — Phases 35-38 (shipped 2026-03-10) - ✅ **v2.6 Cognitive Retrieval** — Phases 39-44 (shipped 2026-03-16) - ✅ **v2.7 Multi-Runtime Portability** — Phases 45-50 (shipped 2026-03-22) -- **v3.0 Competitive Parity & Benchmarks** — Phases 51-53 + Phase 51.5 (in progress; Phase 51.5 merged 2026-04-28) -- ✅ **v3.1 Make It True** — Phases 54-58 (shipped 2026-08-31) +- **v3.0 Competitive Parity & Benchmarks** — Phases 51-53 + Phase 51.5 (shipped 2026-05-14; Phase 53 merged as #30) +- ✅ **v3.1 Make It True** — Phases 54-58 (shipped 2026-09-01 as v3.1.0) +- **v3.2 Prove It** — Phases 59-62 (in progress; Phase 59 executing 2026-09-01) ## Phases @@ -138,7 +139,7 @@ See: `.planning/milestones/v2.7-ROADMAP.md` -### v3.0 Competitive Parity & Benchmarks (In Progress) +### v3.0 Competitive Parity & Benchmarks (Shipped 2026-05-14) **Milestone Goal:** Close the three gaps that keep Agent-Memory from being the category leader: retrieval pipeline orchestration, a dead-simple CLI API, and a benchmark suite that produces a publishable LOCOMO score. @@ -146,7 +147,7 @@ See: `.planning/milestones/v2.7-ROADMAP.md` - [x] **Phase 51.5: API Summarizer Wiring** - Wire `ApiSummarizer` from config (out-of-band; merged 2026-04-28 via PR #27) - [x] **Phase 52: Simple CLI API** - New `memory` binary with search, context, recall, add, timeline, summary subcommands (merged 2026-05-14 via PR #29) - [x] **Phase 53.5: Cross-Project Federation** - Federated query across multiple project stores (out-of-band; merged 2026-05-14 via PR #25) -- [x] **Phase 53: Benchmark Suite** - Custom TOML-fixture harness with LOCOMO adapter and publishable scoring (PR in review 2026-05-14) +- [x] **Phase 53: Benchmark Suite** - Custom TOML-fixture harness with LOCOMO adapter and publishable scoring (merged 2026-05-14 via PR #30; honesty pass in v3.1 Phase 56) ## Phase Details @@ -227,7 +228,9 @@ Phases execute in numeric order: 51 -> 51.5 (merged out-of-band) -> 52 -> 53 | v2.5 Semantic Dedup | 35-38 | 11/11 | Complete | 2026-03-10 | | v2.6 Cognitive Retrieval | 39-44 | 13/13 | Complete | 2026-03-16 | | v2.7 Multi-Runtime Portability | 45-50 | 11/11 | Complete | 2026-03-22 | -| v3.0 Competitive Parity | 51-53 + 51.5, 53.5 | 6/TBD | In progress | Phase 51 + 51.5 + 52 + 53.5 merged; Phase 53 (Benchmark Suite) in PR review | +| v3.0 Competitive Parity | 51-53 + 51.5, 53.5 | 10/10 | Complete | 2026-05-14 | +| v3.1 Make It True | 54-58 | 14/14 | Complete | 2026-09-01 | +| v3.2 Prove It | 59-62 | 3/13 | In progress | Phase 59 executing | --- @@ -291,16 +294,50 @@ Close the claim/reality gap, then open the shop window. No new capabilities. - [x] 57-02: Positioning writeup vs Mem0 / Zep / MemMachine / Letta - [x] 57-03: Scope trim — Tier 1/Tier 2 surface; OpenCode stub deleted -### Phase 58: Launch (side quest) — IN EXECUTION 2026-08-31 +### Phase 58: Launch (side quest) — COMPLETE 2026-09-01 (tag `v3.1.0`) - [x] Version bumped to 3.1.0 (was still 2.7.0 across v3.0 and v3.1) - [x] CHANGELOG.md and v3.1 upgrade notes - [x] Release archives ship all four binaries; assets renamed `agent-memory-*` - [x] Blog post and Show HN / reddit copy drafted in `docs/launch/` -- [ ] Tag `v3.1.0` (maintainer — the agent session cannot: tag push is 403 through the git proxy, and the GitHub App cannot dispatch release.yml) +- [x] Tag `v3.1.0` published 2026-09-01 01:45 UTC, 5 of 5 platforms (the first push tagged a stale SHA for 17 minutes — Phase 59 exists because of that) - [ ] Repo description, topics, Discussions (maintainer — repo settings) - [ ] Recorded demo (maintainer) -- [ ] Post the blog and the launch threads (maintainer) +- [ ] Post the blog and the launch threads (maintainer; product posts wait on #39) -*Updated: 2026-08-31 — Phase 57 merged (#36); v3.1 shipped; Phase 58 launch prep* +--- + +## v3.2 Prove It (Phases 59-62) + +See: `docs/plans/v3.2-prove-it-plan.md` + +v3.1 made the claims true. v3.2 makes them provable: a real benchmark number, +evidence behind every "Solid", and a daemon someone can run for a week. +Nothing on this list is a new capability except Phase 62, which is conditional. + +### Phase 59: Guardrails and Inventory (3/3 plans) — IN EXECUTION 2026-09-01 + +- [x] 59-01: Release pipeline checks (ancestor of main, crate version, all five platforms, CHANGELOG notes) +- [x] 59-02: Orphan branch triage (`docs/plans/phase-59-orphan-branch-triage.md`) +- [x] 59-03: Planning truth (PROJECT.md, ROADMAP, STATE, GitHub issues #39–#44) + +### Phase 60: Real Numbers (0/3) + +- [ ] 60-01: Live-backend isolation for `memory-bench locomo --backend cli` +- [ ] 60-02: The run — maintainer, needs API key + documented machine (#39) +- [ ] 60-03: Vector and topic quality fixtures (#40) + +### Phase 61: Operate It (0/5) + +- [ ] 61-01: Backfill (`admin backfill-index`) (#41); cherry-pick export/import from 59-02 +- [ ] 61-02: `install-service` launchd/systemd (#42) +- [ ] 61-03: Panic audit (`unwrap()`/`expect()` on request paths) +- [ ] 61-04: Offline TOC rebuild (#43) +- [ ] 61-05: Installer register / uninstall / status (CREG/META from 59-02) + +### Phase 62: Cross-encoder rerank (conditional) (#44) + +- [ ] Only if 60-02 shows retrieval, not generation, is the bottleneck + +*Updated: 2026-09-01 — v3.1.0 released; v3.2 Prove It adopted; Phase 59 executing* diff --git a/.planning/STATE.md b/.planning/STATE.md index 5d7c8ba..bb194ec 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,38 +1,34 @@ --- gsd_state_version: 1.0 -milestone_name: Make It True -status: shipping +milestone_name: Prove It +status: executing stopped_at: null -last_updated: "2026-08-31T01:30:00.000Z" -last_activity: 2026-08-31 — Phase 57 merged (#36); v3.1 shipped; Phase 58 launch prep (version 3.1.0, CHANGELOG, launch drafts) +last_updated: "2026-09-01T23:30:00.000Z" +last_activity: 2026-09-01 — v3.1.0 released; v3.2 adopted; Phase 59 Guardrails and Inventory executing progress: - total_phases: 6 - completed_phases: 5 - total_plans: 14 - completed_plans: 14 - percent: 100 + total_phases: 4 + completed_phases: 0 + total_plans: 13 + completed_plans: 3 + percent: 23 --- # Project State ## Project Reference -See: .planning/PROJECT.md (updated 2026-03-22) +See: .planning/PROJECT.md (updated 2026-09-01) **Core value:** Agent can answer "what were we talking about last week?" without scanning everything -**Current focus:** v3.1 Phase 58 — Launch (side quest): version 3.1.0, CHANGELOG, release archive fixes, launch drafts. The tag and the public posts are maintainer actions. +**Current focus:** v3.2 Phase 59 — Guardrails and Inventory. Release pipeline cannot repeat the stale-tag incident; March gsd/ line inventoried; planning docs match v3.1.0 shipped. ## Current Position -Phase: 58 of 58 (Launch — side quest, not a GSD phase) -Status: all v3.1 GSD phases merged (54, 54.5, 55, 56, 57). Launch prep in review. -Last activity: 2026-08-31 — #36 merged; version bumped 2.7.0 → 3.1.0 +Phase: 59 of 62 (Guardrails and Inventory) +Status: v3.1.0 shipped 2026-09-01 (5 of 5 platforms). v3.2 Prove It adopted. Phase 59 in execution. +Last activity: 2026-09-01 — issues #39–#44 opened; release guards + orphan triage + PROJECT.md rewrite -Progress: [██████████] 14/14 plans merged. v3.1 GSD work complete. - -Remaining launch steps are maintainer actions: tag `v3.1.0` (publishes public -binaries), set the repo description/topics/Discussions, record the demo, and -post the blog and launch threads. +Progress: [██░░░░░░░░] 3/13 plans (Phase 59). Phases 60–62 not started. ## Out-of-band Work @@ -40,34 +36,36 @@ post the blog and launch threads. | PR | What | Status | |---|---|---| -| _(Phase 58 launch prep)_ | version 3.1.0, CHANGELOG, release fix, launch drafts | Open | +| _(this branch)_ | Phase 59 Guardrails and Inventory | Open | + +### Open issues (the v3.2 backlog) + +| Issue | What | Phase | +|---|---|---| +| #39 | Real LOCOMO LLM-judge run | 60-02 | +| #40 | Vector and topic-graph quality fixtures | 60-03 | +| #41 | Backfill BM25/vector for pre-v3.1 events | 61-01 | +| #42 | `install-service` (launchd/systemd) | 61-02 | +| #43 | Offline TOC rebuild | 61-04 | +| #44 | Cross-encoder rerank (conditional) | 62 | ### Recently Merged | PR | What | Merged | |---|---|---| +| #38 | docs: correct the "no tags" claim and record the release blocker | 2026-08-31 | +| #37 | chore(v3.1): release prep — version 3.1.0, changelog, working release archives | 2026-08-31 | | #36 | Phase 57 Shop Window & Positioning | 2026-08-31 | | #34 | Phase 56 Honest Benchmarks | 2026-08-30 | | #35 | Phase 54.5 truth leaks + rustc 1.97 pin | 2026-08-30 | | #33 | Phase 55 Performance Truth | 2026-08-30 | | #32 | Phase 54 Integration Truth | 2026-08-30 | | #31 | v3.1 Make It True design spec | 2026-08-30 | -| #30 | Phase 53 Benchmark Suite | 2026-08-30 | -| #25 | Phase 53.5: cross-project federated query | 2026-05-14 | -| #29 | Phase 52: Simple CLI API | 2026-05-14 | -| #28 | Phase 51: Retrieval Orchestrator | 2026-04-28 | ## Decisions -- v3.1 scope: Make It True — no new capabilities; close claim/reality gap (Phases 54-58) -- Phase 54.5: explainability reports what ran; shared HNSW handle; CI pins rust-toolchain.toml to 1.97 -- Phase 55: split setup vs query in `perf_bench`; p90/p99 withheld below 10/30 samples -- Warm = one setup + N query samples; cold = new store per iteration -- Phase 56: substring metric is `context_hit_rate`; HOLD LOCOMO comparison marketing until `locomo_llm_judge` artifact exists -- Phase 57 tiering: Tier 1 = Claude Code + Codex CLI (PR gate); Tier 2 = Gemini + Copilot (weekly schedule) -- Phase 57: OpenCode removed rather than archived — a converter whose methods return empty is a false success, not a gap -- Phase 57: no comparative benchmark claim ships while the only committed results are mock-backend / mock-judge -- Phase 58: version is 3.1.0 — it had been stuck at 2.7.0 through the whole v3.0 and v3.1 line. Tags and GitHub releases exist through v2.7.0 (2026-03-22); v3.0 and v3.1 were milestone names that never shipped a release. An earlier note here claimed the repo had no tags — that was a shallow-clone artifact, not the truth -- Phase 58 blocker: this session cannot cut the release. `git push origin v3.1.0` returns HTTP 403 through the agent git proxy, and the GitHub App cannot `workflow_dispatch` release.yml ("Resource not accessible by integration"). The tag must be pushed by a maintainer -- Phase 58: release archives are `agent-memory--` and carry all four binaries; the CLI the quickstart needs was previously not shipped -- Phase 58: `admin rebuild-bm25` is a prune, not a rebuild — relabelled rather than renamed, and there is no event backfill path +- v3.2 scope: Prove It — no new capabilities except conditional Phase 62 +- Maintainer decisions 2026-09-01: cherry-pick March export/import + CREG/META by feature (not by branch); skip OpenCode converter; blog now / product posts after #39; daemonization is unit files not double-fork +- v3.1.0 first tag push shipped `acc7294` (Cargo.toml 2.7.0) for 17 minutes — Phase 59-01 exists because of that +- March `gsd/phase-56-import-bootstrap` is 88 ahead / 20 behind; naïve merge regresses orchestrator and bench. Inventory: `docs/plans/phase-59-orphan-branch-triage.md` +- HOLD comparison marketing until #39 lands a `locomo_llm_judge` artifact diff --git a/.planning/phases/59-guardrails-inventory/59-01-PLAN.md b/.planning/phases/59-guardrails-inventory/59-01-PLAN.md new file mode 100644 index 0000000..67a0026 --- /dev/null +++ b/.planning/phases/59-guardrails-inventory/59-01-PLAN.md @@ -0,0 +1,28 @@ +--- +phase: 59-guardrails-inventory +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - .github/workflows/release.yml + - .github/workflows/ci.yml + - scripts/release-guards.sh + - scripts/changelog-section.sh + - scripts/release-guards-test.sh + - docs/RELEASING.md +autonomous: true +--- + + +A tag that is not on main, or whose version disagrees with Cargo.toml, cannot produce a release. Missing platforms fail the release instead of publishing a subset. Release notes come from CHANGELOG.md. + + + +1. Extract ancestor + version checks into `scripts/release-guards.sh` and changelog extraction into `scripts/changelog-section.sh`, with `scripts/release-guards-test.sh` covering the 2026-09-01 incident (tag v3.1.0 / crate 2.7.0) and a commit not on main. +2. Add a `guard` job to `release.yml` that runs *before any platform build*: fetch origin/main, require `$GITHUB_SHA` is an ancestor, require `workspace.package.version` equals the tag minus `v`, require a matching CHANGELOG section. +3. Replace `release: if: always() && !cancelled()` with `if: success() && !dry_run`. A custom `if` replaces the implicit needed-jobs-succeeded check, so `success()` is load-bearing. +4. Require all five platform archives before `action-gh-release`. Set `generate_release_notes: false` and `body_path` from CHANGELOG. +5. Document the explicit-SHA tag form in `docs/RELEASING.md`. Note that `v9.9.9-test` does not match the tag trigger; live verify is `workflow_dispatch` + `dry_run: true`. +6. Run the guard tests on every PR via a cheap `Release Guard Scripts` job in `ci.yml`, wired into `CI Success`. + diff --git a/.planning/phases/59-guardrails-inventory/59-02-PLAN.md b/.planning/phases/59-guardrails-inventory/59-02-PLAN.md new file mode 100644 index 0000000..ce287d1 --- /dev/null +++ b/.planning/phases/59-guardrails-inventory/59-02-PLAN.md @@ -0,0 +1,25 @@ +--- +phase: 59-guardrails-inventory +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: + - docs/plans/phase-59-orphan-branch-triage.md +autonomous: true +--- + + +One-page-plus inventory of the March gsd/ line vs current main: what each branch contains, which files conflict, which parts are still wanted. Maintainer decides; agent executes cherry-picks in Phase 61. Do not delete branches in this phase. + + + +1. Walk the nested line 53 ⊂ 54 ⊂ 55 ⊂ 56 ⊂ 57 ⊂ 58 against `origin/main` @ d6c8ac7: tip SHA, date, ahead/behind, merge-base, unique commits, triple-dot stat. +2. Produce a conflict map from a throwaway merge of phase-56 and phase-58 onto current main. Call out the add/add war on `memory-orchestrator` (878 vs 1458 lines) and `memory-bench` (1319 vs 2649 + judge.rs). +3. Recommend cherry-pick by feature, not by branch: + - Keep: export/import (JSONL backup, import/bootstrap, streaming RPCs) as the foundation for 61-01 / #41. + - Keep: Claude Code registration + plugin metadata (CREG-01..06, META-01..03) for 61-05. + - Skip: OpenCode converter entirely (fights #36). +4. List leftover branches (`feature/phase-54-integration-truth`, the two `claude/` docs branches) as already-landed or current-docs, not March salvage. +5. Commit the inventory at `docs/plans/phase-59-orphan-branch-triage.md`. + diff --git a/.planning/phases/59-guardrails-inventory/59-03-PLAN.md b/.planning/phases/59-guardrails-inventory/59-03-PLAN.md new file mode 100644 index 0000000..15839e3 --- /dev/null +++ b/.planning/phases/59-guardrails-inventory/59-03-PLAN.md @@ -0,0 +1,25 @@ +--- +phase: 59-guardrails-inventory +plan: 03 +type: execute +wave: 1 +depends_on: [] +files_modified: + - .planning/PROJECT.md + - .planning/ROADMAP.md + - .planning/STATE.md + - .planning/MILESTONES.md + - docs/plans/v3.2-prove-it-plan.md +autonomous: true +--- + + +PROJECT.md describes the shipped system. v3.2 is on the roadmap. The known gaps are GitHub issues, not a private planning folder. + + + +1. Rewrite PROJECT.md Current State for v3.1.0 shipped / v3.2 executing. Remove OpenCode from the adapter list. Move API-based summarizer from Deferred to shipped (PR #27 / Phase 51.5). +2. Add v3.2 to ROADMAP.md and STATE.md. Mark v3.1 Phase 58 tag as done (the release exists). Mark v3.0 as shipped — Phase 53 merged as #30, the "in PR review" line is stale. +3. Open GitHub issues for F3 (#39), F4 (#40), F5's three gaps (#41 backfill, #42 install-service, #43 TOC rebuild), and cross-encoder (#44). Each links the relevant README row. +4. Adopt `docs/plans/v3.2-prove-it-plan.md` (from the same-day docs branch) and record the three maintainer decisions. + diff --git a/.planning/phases/59-guardrails-inventory/59-CONTEXT.md b/.planning/phases/59-guardrails-inventory/59-CONTEXT.md new file mode 100644 index 0000000..b7b60fb --- /dev/null +++ b/.planning/phases/59-guardrails-inventory/59-CONTEXT.md @@ -0,0 +1,32 @@ +# Phase 59: Guardrails and Inventory + +**Gathered:** 2026-09-01 +**Status:** In execution +**Source:** docs/plans/v3.2-prove-it-plan.md + +v3.1 made the claims true. v3.2 makes them provable. Phase 59 is small, +first, and it protects everything after it: the release pipeline cannot +ship a tag that is not on main, the March orphan line is inventoried +before anyone cherry-picks it, and the planning source of truth matches +the shipped v3.1.0. + +## What was already true before this phase + +- `v3.1.0` exists as a 5-of-5-platform GitHub Release (2026-09-01 01:45 UTC) +- The first tag push shipped `acc7294` (Cargo.toml `2.7.0`) for 17 minutes +- The four-binary archive guard from #37 held; ancestor/version/changelog + checks did not exist +- Zero GitHub issues; the backlog lived only in `.planning/` +- `PROJECT.md` still said "Version: v3.0 (In Progress)" and listed OpenCode +- `origin/gsd/phase-56-import-bootstrap` (and the nested 54–58 line) sat + unmerged, 20 commits behind main, with an add/add war waiting in + `memory-orchestrator` and `memory-bench` + +## Constraints carried in + +- Never commit to `main`; feature branch + PR +- Do not delete the `gsd/` branches in this phase — inventory only +- Do not cherry-pick export/import or CREG/META yet (Phase 61) +- Do not run a live `v9.9.9` tag; `dry_run` + unit tests are the verify +- Maintainer decisions (adopted with the plan): cherry-pick by feature; + blog now; unit files not double-fork diff --git a/.planning/phases/59-guardrails-inventory/59-VERIFICATION.md b/.planning/phases/59-guardrails-inventory/59-VERIFICATION.md new file mode 100644 index 0000000..8044df2 --- /dev/null +++ b/.planning/phases/59-guardrails-inventory/59-VERIFICATION.md @@ -0,0 +1,43 @@ +--- +phase: 59-guardrails-inventory +verified: 2026-09-01 +status: passed +--- + +# Phase 59: Guardrails and Inventory Verification + +**Phase Goal:** the next tag cannot repeat the 2026-09-01 incident; the March +line is inventoried; the planning source of truth matches v3.1.0 shipped. + +## Execution evidence + +| # | Claim | Status | Evidence | +|---|-------|--------|----------| +| 1 | Tagged commit must be an ancestor of origin/main | **RUN** | `scripts/release-guards-test.sh`: "commit not on main fails"; `release.yml` `guard` job runs the script before any build | +| 2 | Crate version must equal tag minus `v` | **RUN** | same test: "version mismatch fails (the v3.1.0-on-2.7.0 incident)" | +| 3 | Missing CHANGELOG section fails | **RUN** | `changelog-section.sh 9.9.9` exits 1; `changelog-section.sh 3.1.0 CHANGELOG.md` prints the v3.1.0 body and stops before v2.7.0 | +| 4 | Publish requires every matrix build to succeed | FILE | `release.yml` Create Release `if: ${{ success() && ... }}` — a custom `if` without `success()` would reintroduce `always()` | +| 5 | Partial archives cannot ship | FILE | "Require all five platform archives" step lists linux-x86_64, linux-aarch64, macos-x86_64, macos-aarch64, windows-x86_64 | +| 6 | Release notes come from CHANGELOG.md | FILE | `generate_release_notes: false` + `body_path: release-notes.md` from `changelog-section.sh` | +| 7 | Tag procedure is documented as explicit-SHA | FILE | `docs/RELEASING.md` — `git tag -a vX.Y.Z ` | +| 8 | Guard tests run on every PR | FILE | `ci.yml` job `Release Guard Scripts`; `CI Success` needs `release-guards` | +| 9 | Orphan-branch inventory exists with a conflict map | FILE | `docs/plans/phase-59-orphan-branch-triage.md` — 35 unmerged files on phase-56, add/add on orchestrator/bench, cherry-pick commit list | +| 10 | PROJECT.md Current State is v3.1 shipped | FILE | `.planning/PROJECT.md` | +| 11 | Known gaps are GitHub issues | **RUN** | #39 LOCOMO, #40 vector/topic, #41 backfill, #42 install-service, #43 TOC rebuild, #44 cross-encoder | +| 12 | v3.2 is on ROADMAP and STATE | FILE | `.planning/ROADMAP.md`, `.planning/STATE.md` | + +## Human verification (blockers) + +- [x] `bash scripts/release-guards-test.sh` exits 0 +- [x] `bash scripts/changelog-section.sh 3.1.0 CHANGELOG.md` extracts the real v3.1.0 section +- [x] Issues #39–#44 exist and link the v3.2 plan +- [ ] Live `workflow_dispatch` + `dry_run: true` with a disagreeing version (maintainer — do not push `v9.9.9`) + +## Not done (stated, not waved through) + +| Item | Why | Owner | +|---|---|---| +| Live dry-run dispatch against GitHub | Needs `workflow_dispatch` on the merged workflow; unit tests cover the same predicates | Maintainer, after this PR merges | +| Delete the `gsd/` branches | 59-02 inventories; deletion waits until 61 has cherry-picked the kept features | Phase 61 | +| Cherry-pick export/import and CREG/META | Feeds 61-01 and 61-05; not this phase | Phase 61 | +| Blog post | Maintainer launch action; recommended "now" | Maintainer | diff --git a/README.md b/README.md index 9581775..d259cb1 100644 --- a/README.md +++ b/README.md @@ -163,16 +163,16 @@ is experimental. | Passive hook capture → `memory-ingest` | **Solid** | Covered by the bats CLI suites on Linux + macOS | | TOC build and drill-down navigation | **Solid** | Year → Month → Week → Day → Segment → Grip | | Grips / provenance | **Solid** | Excerpts link back to the events they came from | -| BM25 keyword search (Tantivy) | **Solid** | Exact tokens, no stemming (`jwt` does not match `JWTs`). Events indexed before v3.1 have empty `text_preview` and there is no backfill command — see [UPGRADING](docs/UPGRADING.md) | -| Vector search (HNSW + Candle) | **Solid** | First daemon start downloads the embedding model; with no network the daemon warns and runs BM25-only | -| Topic graph | **Works** | Clustering quality is not benchmarked | +| BM25 keyword search (Tantivy) | **Solid** | Exact tokens, no stemming (`jwt` does not match `JWTs`). Events indexed before v3.1 have empty `text_preview` and there is no backfill command — see [UPGRADING](docs/UPGRADING.md) and [#41](https://github.com/SpillwaveSolutions/agent-memory/issues/41) | +| Vector search (HNSW + Candle) | **Solid** | Mechanism is wired; retrieval *quality* is not yet measured ([#40](https://github.com/SpillwaveSolutions/agent-memory/issues/40)). First daemon start downloads the embedding model; with no network the daemon warns and runs BM25-only | +| Topic graph | **Works** | Clustering quality is not benchmarked ([#40](https://github.com/SpillwaveSolutions/agent-memory/issues/40)) | | Hybrid fusion + `RouteQuery` orchestration | **Works** | Wired end-to-end in Phase 54; explainability reports what actually ran | | LLM summarization / LLM rerank | **Experimental** | Needs an API key; fails open to the heuristic ranker and reports `rerank=heuristic` when it does | | Cross-project federated query | **Experimental** | Implemented; not performance-characterised | -| Cross-encoder rerank | **Not implemented** | The extension point exists and returns an explicit error — it is not silently degraded | +| Cross-encoder rerank | **Not implemented** | The extension point exists and returns an explicit error — it is not silently degraded. Build only if [#39](https://github.com/SpillwaveSolutions/agent-memory/issues/39) says retrieval is the bottleneck ([#44](https://github.com/SpillwaveSolutions/agent-memory/issues/44)) | | Ingest → searchable latency | **~1 minute** | The outbox drains on a schedule; ingest is deliberately not blocked on indexing | -| Offline TOC rebuild (`admin rebuild-toc`) | **Not implemented** | Exits non-zero with guidance. TOC nodes come from the daemon's scheduled rollup jobs | -| Background daemonization | **Not implemented** | `--background` exits non-zero with guidance rather than pretending | +| Offline TOC rebuild (`admin rebuild-toc`) | **Not implemented** | Exits non-zero with guidance. TOC nodes come from the daemon's scheduled rollup jobs ([#43](https://github.com/SpillwaveSolutions/agent-memory/issues/43)) | +| Background daemonization | **Not implemented** | `--background` exits non-zero with guidance rather than pretending. v3.2 will ship `install-service` unit files ([#42](https://github.com/SpillwaveSolutions/agent-memory/issues/42)) | ### Benchmarks @@ -184,7 +184,8 @@ Committed results live in `benchmarks/results/`. Today both are **mock-backend** runs — a mock retrieval backend and a mock judge — so they demonstrate the harness, not competitive quality. **There is deliberately no comparison marketing in this repo**, and there will not be until a real-backend, -real-judge run is committed next to the claim. +real-judge run is committed next to the claim +([#39](https://github.com/SpillwaveSolutions/agent-memory/issues/39)). --- @@ -219,6 +220,7 @@ unaffected by tiering. | [docs/verification/57-quickstart-transcript.md](docs/verification/57-quickstart-transcript.md) | The transcript of this quickstart being run on a clean machine, defects and all | | [docs/positioning/agent-memory-vs-competition.md](docs/positioning/agent-memory-vs-competition.md) | Head-to-head vs Mem0 / Zep / MemMachine / Letta | | [docs/UPGRADING.md](docs/UPGRADING.md) | Version-to-version migration notes | +| [docs/RELEASING.md](docs/RELEASING.md) | How to cut a tag so the pipeline cannot repeat the v3.1.0 stale-ref incident | | [CHANGELOG.md](CHANGELOG.md) | What changed per release, including retractions | ## Contributing diff --git a/docs/RELEASING.md b/docs/RELEASING.md new file mode 100644 index 0000000..cac601f --- /dev/null +++ b/docs/RELEASING.md @@ -0,0 +1,83 @@ +# Releasing Agent Memory + +How a version becomes a GitHub Release. The pipeline has guardrails because +a bare `git tag` from a stale local ref shipped v3.1.0 against `acc7294` +(Cargo.toml still `2.7.0`, none of Phases 54–57 present) on 2026-09-01. It +was public for 17 minutes. The four-binary archive check added in #37 held; +nothing else in the pipeline did. + +## Procedure + +Always tag an explicit SHA that is already on `origin/main`. Never tag +`HEAD` of a local branch. + +```bash +git fetch origin +git checkout main +git pull --ff-only origin main + +# Confirm the commit you intend to ship: +git log -1 --oneline +grep -A2 '\[workspace.package\]' Cargo.toml # version must equal the tag minus v + +# Tag that SHA, not a local name that might have drifted: +SHA="$(git rev-parse origin/main)" +git tag -a vX.Y.Z "$SHA" -m "Release vX.Y.Z" +git push origin vX.Y.Z +``` + +Pushing a tag matching `v[0-9]+.[0-9]+.[0-9]+` starts +[`.github/workflows/release.yml`](../.github/workflows/release.yml). + +`workflow_dispatch` with a version is an alternative. It still has to pass +the same guards, and it tags `$GITHUB_SHA` (the commit the workflow ran on) +rather than whatever happens to be `HEAD` on the runner. + +## What the pipeline refuses + +A `guard` job runs **before any platform build** and fails the release when: + +1. The candidate commit is not an ancestor of `origin/main`. A tag cut from + a feature branch, a stale local ref that was never merged, or a rewritten + history cannot ship. +2. `workspace.package.version` in the root `Cargo.toml` is not exactly the + tag minus `v`. This is the check that would have stopped the 2026-09-01 + incident: tag `v3.1.0`, crate version `2.7.0`. +3. `CHANGELOG.md` has no `## vX.Y.Z` section. Release notes are that section, + not GitHub's auto-list of PR titles. + +After the builds, the publish job additionally: + +- Runs only if **every** matrix build succeeded. A missing platform fails + the release instead of publishing three archives. (`if: success()`, not + `if: always()`.) +- Requires all five archives (`linux-x86_64`, `linux-aarch64`, + `macos-x86_64`, `macos-aarch64`, `windows-x86_64`) to be present. +- Attaches `SHA256SUMS.txt`. + +## Dry-run (how to verify the guards live) + +The tag pattern does **not** match prerelease suffixes, so `v9.9.9-test` +will not even start the workflow. Do not push a real `v9.9.9` tag to try +it — if the guards ever regress, that would publish. + +To exercise the guards against GitHub without publishing: + +1. `workflow_dispatch` with version `9.9.9` and **`dry_run: true`** from a + feature branch. The guard job must fail (`Cargo.toml` is not 9.9.9, and + the commit is not on main). Nothing is tagged or published. +2. The same dispatch from `main` with a version that disagrees with + `Cargo.toml` must fail the version check. + +The unit tests in `scripts/release-guards-test.sh` cover both failure +modes locally and run on every PR (`Release Guard Scripts` in `ci.yml`). + +## Version bump checklist + +Before tagging: + +- [ ] `workspace.package.version` in `Cargo.toml` equals the intended tag +- [ ] `CHANGELOG.md` has a `## vX.Y.Z` section whose body is true of the + tagged commit +- [ ] `task pr-precheck` was green on the PR that landed on main +- [ ] Tag with the explicit-SHA form above, not `git tag -a vX.Y.Z` diff --git a/docs/plans/phase-59-guardrails-inventory-plan.md b/docs/plans/phase-59-guardrails-inventory-plan.md new file mode 100644 index 0000000..77a9f3b --- /dev/null +++ b/docs/plans/phase-59-guardrails-inventory-plan.md @@ -0,0 +1,41 @@ +# Phase 59: Guardrails and Inventory — Plan + +**Milestone:** v3.2 Prove It +**Goal:** the next tag cannot repeat the 2026-09-01 stale-ref incident; the +March `gsd/` line is inventoried before anyone cherry-picks it; PROJECT.md +and the public backlog match v3.1.0 shipped. + +See: [v3.2-prove-it-plan.md](v3.2-prove-it-plan.md) + +## 59-01: Release pipeline checks + +- `scripts/release-guards.sh` — ancestor of `origin/main` + crate version +- `scripts/changelog-section.sh` — `## vX.Y.Z` section or fail +- `release.yml` `guard` job before any platform build +- Publish `if: success()` (not `always()`); all five archives required +- Notes from CHANGELOG, not GitHub's PR auto-list +- `docs/RELEASING.md` — `git tag -a vX.Y.Z ` +- Unit tests on every PR (`Release Guard Scripts`) + +## 59-02: Orphan branch triage + +Inventory: [phase-59-orphan-branch-triage.md](phase-59-orphan-branch-triage.md). + +Keep (cherry-pick in Phase 61): export/import streaming RPCs; Claude Code +CREG/META. Skip: OpenCode converter. Do not merge any `gsd/phase-*` branch +wholesale — add/add on `memory-orchestrator` and `memory-bench` would +regress Make It True. + +## 59-03: Planning truth + +- PROJECT.md Current State is v3.1.0 shipped / v3.2 executing +- OpenCode removed from the adapter list; API summarizer moved out of Deferred +- ROADMAP/STATE/MILESTONES know about v3.2 +- Issues #39–#44 are the public backlog + +## Exit criteria + +1. `bash scripts/release-guards-test.sh` exits 0 +2. A disagreeing version or a commit not on main cannot get past `guard` +3. Issues #39–#44 exist +4. `task pr-precheck` green diff --git a/docs/plans/phase-59-orphan-branch-triage.md b/docs/plans/phase-59-orphan-branch-triage.md new file mode 100644 index 0000000..5ca5873 --- /dev/null +++ b/docs/plans/phase-59-orphan-branch-triage.md @@ -0,0 +1,475 @@ +# Orphan branch triage — SpillwaveSolutions/agent-memory + +**Phase:** 59-02. Inventory vs `origin/main` @ `d6c8ac7`. Do not delete these +branches in this phase. Cherry-pick by feature in Phase 61. + +**Maintainer decision (2026-09-01):** cherry-pick export/import and Claude +Code registration by feature. Skip the OpenCode converter. Keep the branches +until those cherry-picks land. + +Trial merges were run in throwaway worktrees and discarded; the clone was +not modified. + +## How to read this + +Two independent "v3.1" numbering schemes collided: + +| Line | When | What "v3.1" meant | What "phase 54–58" meant | +|---|---|---|---| +| **March GSD line (these orphans)** | 2026-03-21 → 03-25 | Memory Export/Import | 54 daily markdown, 55 JSONL backup, 56 import/bootstrap, then v3.2: 57 OpenCode converter, 58 Claude registration + plugin.json | +| **Current main** | 2026-05 → 08 | "Make It True" | 54 Integration Truth (#32), 54.5 truth leaks, 55 honest percentiles, 56 LOCOMO adapter v2, 57 shop window (deleted the OpenCode stub) | + +Shared fork point for the March line: merge-base +`9be18d8d5e3ad4726f9f0a1cc892c34de0633f03` (`chore: release v2.7.0`, 2026-03-21). +All five primary branches (and leftover `phase-53`) are **20 commits behind** +main. Main later landed the same v3.0 work via PRs #28/#29/#30 (different SHAs), +then built a different v3.1 on top. + +**Ancestry (nested, each tip is a descendant of the previous):** + +``` +9be18d8 (v2.7.0) + └─ origin/gsd/phase-53-benchmark-suite b1af44a (leftover) + └─ origin/gsd/phase-54-daily-markdown-export 2370a2f + └─ origin/gsd/phase-55-structured-backup 5491f59 + └─ origin/gsd/phase-56-import-bootstrap 88eb6da + └─ origin/gsd/phase-57-opencode-converter-registration ee2ff82 + └─ origin/gsd/phase-58-claude-registration-metadata 4f26f49 +``` + +Triple-dot `git diff origin/main...tip` treats `memory-orchestrator`, +`memory-bench`, and `memory-cli` as **Added** because they did not exist at +`9be18d8`. They **do** exist on current main (independent history). That is +why a naïve merge is an add/add war on those crates — see Conflict map. + +--- + +## PRIMARY 1 — `origin/gsd/phase-54-daily-markdown-export` + +1. **Tip** `2370a2f1df1d16604448430e4e3c12bdbc387dc5` — 2026-03-23 18:03:04 -0500 — + `docs(55): create phase plan for structured backup`. + **63 ahead / 20 behind** main. Merge-base `9be18d8d5e3ad4726f9f0a1cc892c34de0633f03`. + Unique vs previous tip (phase-53): **8 commits**. +2. **Log `merge-base..tip` (63 commits).** Newest 15: + ``` + 2370a2f docs(55): create phase plan for structured backup + ccfaf16 docs(55): research phase domain + 39992db docs(phase-54): complete phase execution + c27317e docs(54-02): complete daily CLI subcommand plan + 5be2c19 feat(54-02): add `memory daily` CLI subcommand with markdown rendering + 2ac7532 docs(54-01): complete ExportDaily RPC plan + 408003b feat(54-01): implement ExportDaily handler, trait dispatch, and client method + 1e29127 feat(54-01): add ExportDaily proto messages and RPC + b1af44a docs(54): create phase plan for daily markdown export + 6efdb2d docs(54): research phase domain + f4fd1a2 docs: populate CONTEXT.md files for phases 54-56 from spec + f579d0b docs: create milestone v3.1 roadmap (3 phases) + 12aadf0 docs: define milestone v3.1 requirements + 2b20d7b docs: start milestone v3.1 Memory Export/Import + cf163c0 chore: complete v3.0 Competitive Parity & Benchmarks milestone + ``` + Oldest 10 (v3.0 scaffold already on main via PRs): + ``` + e14625c feat(51-02): implement RRF fusion with deduplication and consensus boosting + 9151d49 docs(51-01): complete retrieval orchestrator scaffold plan + 7dc22c8 feat(51-01): implement heuristic query expansion with 6 tests + 7874baa feat(51-01): scaffold memory-orchestrator crate with core types + 1d25a22 fix(51): revise plan 03 for ORCH-04 mock LLM reranker integration test + 5b8aede docs(51): create phase plan for retrieval orchestrator + bb0420e docs(51): generate context from PRD + 0fe32db docs: create milestone v3.0 roadmap (3 phases) + 087f251 docs: define milestone v3.0 requirements + d84213a docs: start milestone v3.0 Competitive Parity & Benchmarks + ``` + Feature-only increment vs phase-53 (8 commits): proto `ExportDaily`, handler in + `memory-service/src/query.rs` + trait dispatch in `ingest.rs`, client method, + `memory daily` CLI (`commands/daily.rs`, 371 lines). +3. **`git diff --stat origin/main...tip`:** 100 files, +15836/−215 + (non-planning: 52 files, +4995/−26). Highlight: + - `crates/memory-orchestrator/` — shown as add (878-line March snapshot; **main is 1458 lines**) + - `crates/memory-bench/` — shown as add (1319-line March snapshot; **main is 2649 lines + `judge.rs`**) + - `crates/memory-service/src/query.rs` +160/−, `ingest.rs` +43 + - `proto/memory.proto` +37 (`rpc ExportDaily`) + - `crates/memory-cli/src/commands/daily.rs` +371 (**new**) + - `crates/memory-installer/` — no change + - `plugins/` — no change +4. **Feature:** daily markdown export. Unary RPC `ExportDaily(ExportDailyRequest) returns (ExportDailyResponse)` + with `DayExport` (TOC day node, segments, events, grips, `has_rollup`). CLI + `memory daily` renders markdown. Design spec + `docs/superpowers/specs/2026-03-23-memory-export-import-design.md`. +5. **On current main?** **Partial.** Orchestrator/bench/cli crates exist (evolved). + `daily.rs`, `ExportDaily` RPC, `export_daily` handler/client: **no**. + +--- + +## PRIMARY 2 — `origin/gsd/phase-55-structured-backup` + +1. **Tip** `5491f59f55319367e44a258de13911f7ead5c748` — 2026-03-24 12:19:16 -0500 — + `docs(56): add validation strategy and revise plans for IMPORT-02`. + **72 ahead / 20 behind.** Merge-base `9be18d8`. Unique vs phase-54: **9 commits**. +2. **Increment vs phase-54:** + ``` + 5491f59 docs(56): add validation strategy and revise plans for IMPORT-02 + 353ff76 docs(56): create phase plan for import/bootstrap + 08ab1c8 docs(56): research phase domain + e500b22 docs(phase-55): complete phase execution + bcda199 docs(55-02): complete backup CLI command plan + bf51772 feat(55-02): add memory backup CLI command with streaming client + f659356 docs(55-01): complete structured backup server-side plan + 2f2b148 feat(55-01): add streaming backup handler with service wiring + 858532b feat(55-01): add ExportBackup proto definitions, tokio-stream dep, and storage iteration methods + ``` + Full `merge-base..tip` = 72 commits (phase-54's 63 + these 9). +3. **Triple-dot vs main:** 114 files, +18476/−219 (non-planning 59, +5837/−30). + New vs phase-54: + - `crates/memory-service/src/backup.rs` +308 (**new**; first streaming RPC) + - `crates/memory-cli/src/commands/backup.rs` +308 (**new**) + - `proto/memory.proto` +41 (`rpc ExportBackup(BackupOptions) returns (stream BackupChunk)`) + - `crates/memory-storage/src/db.rs` +35 (list-all-grips for export) + - `crates/memory-storage/src/episodes.rs` +41 + - `crates/memory-client` gains `tokio-stream` + `export_backup()` + - orchestrator/bench still the March snapshot +4. **Feature:** structured JSONL backup. Server-streaming `ExportBackup`. Chunk + types: events, TOC (segment/day/week/month/year), grips, episodes, manifest. + Options: `events_only`, `since_ms`, `until_ms`. CLI `memory backup`. +5. **On current main?** **No** for backup.rs / ExportBackup / `memory backup`. + `tokio-stream` already a workspace/client dep on main. Storage list helpers: **no**. + +--- + +## PRIMARY 3 — `origin/gsd/phase-56-import-bootstrap` ← export/import foundation tip + +1. **Tip** `88eb6dae85a1363ddd89569a0137819d4bd53d8e` — 2026-03-25 15:04:29 -0500 — + `docs(57): fix plan issues — add OREG-01, remove -x flag, add VALIDATION.md`. + **88 ahead / 20 behind.** Merge-base `9be18d8`. Unique vs phase-55: **16 commits**. +2. **Increment vs phase-55 (newest 15 of the 16; last is proto):** + ``` + 88eb6da docs(57): fix plan issues — add OREG-01, remove -x flag, add VALIDATION.md + 19dce24 docs(57): create phase plan for OpenCode converter + registration + 15edbb0 docs(57): research phase domain + 98f83c6 docs(57): generate context from codebase-mentor reference + dab420e docs: create milestone v3.2 roadmap (3 phases) + 1d7deae docs: define milestone v3.2 requirements + 3c61ec1 docs: start milestone v3.2 Plugin Installer & OpenCode Converter + acc7294 chore: complete v3.1 Memory Export/Import milestone + 7fe632a docs(phase-56): complete phase execution + 1db4faa docs(56-02): complete import CLI + round-trip tests plan + acbd6ae chore(56-02): apply cargo fmt and clippy fixes across workspace + 53fa9fc test(56-02): add round-trip integration tests for import handler + ea9ee1d feat(56-02): add memory import CLI command with manifest validation + 0786e4a docs(56-01): complete import bootstrap server plan + b6c7935 feat(56-01): add import handler, service wiring, and client method + 2c737a9 feat(56-01): add ImportBackup client-streaming RPC to proto + ``` + Non-planning increment vs phase-55: **12 files, +688/−8**. +3. **Triple-dot vs main:** 126 files, +20953/−208 (non-planning 62, +6517/−30). + Highlight crates (triple-dot, includes the v3.0 add/add illusion): + - `crates/memory-service/src/import.rs` +280 (**new**) + - `crates/memory-service/tests/import_round_trip.rs` +130 (**new**) + - `crates/memory-cli/src/commands/import.rs` +164 (**new**) + - `proto/memory.proto` +110 total vs main (`ImportBackup(stream ImportChunk) returns (ImportResult)` plus 54/55) + - `crates/memory-client/src/client.rs` +110/− (`export_daily` / `export_backup` / `import_backup`) + - `crates/memory-service/src/ingest.rs` +71/− (RPC trait dispatch for all three) + - `crates/memory-orchestrator/` +878 lines shown as add — **do not take** + - `crates/memory-bench/` +1319 lines shown as add — **do not take** + - `crates/memory-installer/` — **no change at this tip** + - `plugins/` — `plugins/memory-opencode-plugin/README.md` exists here, not on main +4. **Feature:** import/bootstrap. Client-streaming `ImportBackup`. `ImportChunk` + reuses `BackupChunkType`, plus `dry_run` and `events_only`. `ImportResult` + counts events/TOC/grips/episodes skipped+imported. CLI `memory import` with + manifest validation. Post-import hint: `memory admin rebuild-toc` (see grep: + that command is a documented stub on main). Completes March "v3.1 Memory + Export/Import". +5. **On current main?** **No** for import.rs / ImportBackup / `memory import` / + round-trip test. Service `lib.rs` on main has `federated` instead of + `backup`/`import`. + +--- + +## PRIMARY 4 — `origin/gsd/phase-57-opencode-converter-registration` ← SKIP + +1. **Tip** `ee2ff82401e84895573eeaa8762cfa5aafb086ab` — 2026-03-25 17:04:05 -0500 — + `docs(58): create phase plan for Claude registration + plugin metadata`. + **95 ahead / 20 behind.** Merge-base `9be18d8`. Unique vs phase-56: **7 commits**. +2. **Increment vs phase-56:** + ``` + ee2ff82 docs(58): create phase plan for Claude registration + plugin metadata + db9cb04 docs(58): research phase domain + 3d5d7e5 docs(58): generate context from codebase-mentor reference + 2737b3a docs(phase-57): complete phase execution + 94c654b docs(57-01): complete OpenCode converter plan + 578883d test(57-01): update E2E and integration tests for OpenCode converter + f28793a feat(57-01): implement full OpenCode converter replacing stub + ``` +3. **Triple-dot vs main:** 134 files, +22981/−248 (non-planning 65, +7381/−64). + Code increment vs phase-56 is **only installer**: + - `crates/memory-installer/src/converters/opencode.rs` +779/− (stub → full converter) + - `crates/memory-installer/src/converter.rs` +2/− (select OpenCode) + - `crates/memory-installer/tests/e2e_converters.rs` +117/− +4. **Feature:** full OpenCode converter (OREG). Replaces the 49-line stub that + already existed on the March line. +5. **On current main?** **No, and main deleted it on purpose.** `#36` + (`feat(phase-57): shop window…`, 2026-08-30) removed + `crates/memory-installer/src/converters/opencode.rs` ("delete the one + converter that reported success while doing nothing"). Current main + converters: claude, gemini, codex, copilot, skills — no OpenCode. + +--- + +## PRIMARY 5 — `origin/gsd/phase-58-claude-registration-metadata` ← CREG/META tip + +1. **Tip** `4f26f49841f3f6a1041d82254d70dcf6827a069d` — 2026-03-25 17:17:07 -0500 — + `docs(phase-58): complete phase execution`. + **99 ahead / 20 behind.** Merge-base `9be18d8`. Unique vs phase-57: **4 commits**. +2. **Increment vs phase-57 (entire log of 4):** + ``` + 4f26f49 docs(phase-58): complete phase execution + 65b30fe docs(58-01): complete Claude registration metadata plan + aedbfb9 feat(58-01): implement Claude Code registry registration in generate_guidance + b806364 feat(58-01): create plugin.json and add chrono dependency + ``` + Full `merge-base..tip` = 99 commits. Newest 15 = these 4 + phase-57's 7 + + start of phase-56 docs. Oldest 10 = same v3.0 scaffold as phase-54. +3. **Triple-dot vs main:** 139 files, +23766/−272 (non-planning 68, +7955/−88). + Highlight vs phase-57 / vs main: + - `plugins/memory-query-plugin/.claude-plugin/plugin.json` +13 (**new**; name + `memory-query`, version `1.0.0`) + - `crates/memory-installer/src/converters/claude.rs` +584/− (`generate_guidance` + writes `known_marketplaces.json`, `installed_plugins.json`, + `settings.json` `enabledPlugins`; key `memory-query@agent-memory`; version + from plugin.json; CREG-01..06 + META-03 tests) + - `crates/memory-installer/Cargo.toml` +1 (`chrono`) + - plus everything from 54–57, including **OpenCode converter** +4. **Feature:** Claude Code marketplace registration + plugin metadata (CREG/META). + `ClaudeConverter::generate_guidance` (empty on main) emits registry files. + `uninstall` is still only a comment in `writer.rs` ("Supports future + `--uninstall`") — same as main. No `install-service` command on either side. +5. **On current main?** `claude.rs` **yes** (stub `generate_guidance` returns + empty). `plugin.json` **no** (zero `plugin.json` files on main). + `known_marketplaces` **no**. CREG/META tests **no**. + +--- + +## Leftover branches (not the March nested line) + +### `origin/gsd/phase-53-benchmark-suite` + +- Tip `b1af44aba6692abc567a538da07db07a5f21a772` — 2026-03-23 14:36:14 -0500 — + `docs(54): create phase plan for daily markdown export`. +- **55 ahead / 20 behind.** Merge-base `9be18d8`. **Ancestor of all five primaries.** +- Content: March v3.0 (orchestrator + CLI + bench + LOCOMO) plus v3.1 planning + docs. **Already on main via PRs #28/#29/#30**, then superseded by Make It True + (judge.rs, LOCOMO v2, honest percentiles). No unique feature vs current main. + +### `origin/feature/phase-54-integration-truth` + +- Tip `8d22cc136e7f2fe5e0aff6e3e9481db2fc05a187` — 2026-08-30 16:33:27 +0000 — + `fix(clippy): use slice::fill in InFlightBuffer::clear`. +- Merge-base with main: `68ab122` (Phase 53 Benchmark Suite #30, 2026-05-14). + **2 ahead / 8 behind.** +- Unique commits: `63b07a8 feat(phase-54): wire orchestrator…` and the clippy fix. +- Orchestrator patch-id of `63b07a8` **equals** `4e0e66a` (`feat(v3.1): Phase 54 + Integration Truth — wire orchestrator (#32)`). Work is on main under a + different SHA. The clippy hunk is also already present on main (`git diff + origin/main 8d22cc1 -- crates/memory-types/src/dedup.rs` is empty). Stale PR + branch. + +### `origin/claude/phase-54-toolchain-drift-3k4fer` + +- Tip `2d205f151b1bfc38c7b181eef8e0a68a2208177e` — 2026-09-01 23:15:34 +0000 — + `docs(plans): reconcile v3.2 plan with the March roadmap and v3 spec futures`. +- Merge-base = **current main** (`d6c8ac7`). **2 ahead / 0 behind.** +- Adds only `docs/plans/v3.2-prove-it-plan.md` (+367). Live unmerged docs branch + sitting on today's main; **not** part of the March export/import line. Name is + misleading (phase-54 here is Make It True, not daily-export). + +### `origin/claude/spillwave-agent-memory-review-len4et` + +- Tip `70699e10ebf70b3d0395d9951667402ba395bad6` — 2026-08-30 07:20:01 +0000 — + `docs: v3.1 'Make It True' milestone design spec and phase plan`. +- Merge-base `68ab122`. **1 ahead / 8 behind.** +- Adds `docs/plans/v3.1-make-it-true-plan.md`. Landed on main as `#31` + (`d937d1d`, same path). Duplicate. + +--- + +## Conflict map (trial merge `--no-commit --no-ff` onto `origin/main`) + +Throwaway worktrees at `/tmp/orphan-merge-{56,58}`, aborted and removed. + +### phase-56-import-bootstrap vs main — **35 unmerged files** + +**Content conflicts (UU):** +- `.github/workflows/ci.yml` (rustc 1.97 pin vs `stable`; bench-smoke `continue-on-error`) +- `.planning/{MILESTONES,PROJECT,REQUIREMENTS,ROADMAP,STATE}.md` (numbering collision) + +**Add/add (AA) — independent crate creation after fork:** +- **Entire `crates/memory-bench/`** (10 files: Cargo.toml, baseline, cli, fixture, + lib, locomo, main, report, runner, scorer). Main also has `judge.rs` (orphan does not). +- **Overlapping `crates/memory-cli/`:** Cargo.toml, cli.rs, main.rs, + commands/{add,context,mod,search}.rs +- **Entire overlapping `crates/memory-orchestrator/`** except `expand.rs` (identical + blob) and Cargo.toml (identical): context_builder, fusion, lib, orchestrator, + rerank, types. +- `benchmarks/baselines.toml`, three fixture tomls, `download-locomo.sh` + +**Content conflict (UU):** +- `crates/memory-client/src/client.rs` — main added `ingest`, `ingest_batch`, + `route_query_ex`; orphan added `export_daily` / `export_backup` / `import_backup`. + +**Auto-merged (clean) — this is the salvageable surface:** +- `proto/memory.proto` (append-only ExportDaily / ExportBackup / ImportBackup) +- `crates/memory-service/{Cargo.toml,ingest.rs,lib.rs,query.rs}` +- `crates/memory-service/src/backup.rs` (added) +- `crates/memory-service/src/import.rs` (added) +- `crates/memory-service/tests/import_round_trip.rs` (added) +- `crates/memory-cli/src/commands/{daily,backup,import}.rs` (added) +- `crates/memory-storage/src/{db.rs,episodes.rs}` +- `crates/memory-client/{Cargo.toml,src/lib.rs}` +- root `Cargo.toml` + +### phase-58-claude-registration-metadata vs main — **38 unmerged files** + +Everything in the phase-56 set, plus three installer conflicts: + +| File | Kind | Why | +|---|---|---| +| `crates/memory-installer/src/converter.rs` | UU content | Orphan re-inserts `Runtime::OpenCode` into `select_converter` / tests; main's `#36` shop-window explicitly dropped OpenCode | +| `crates/memory-installer/src/converters/opencode.rs` | DU modify/delete | **Deleted on main**, modified on orphan (stub → 779-line converter) | +| `crates/memory-installer/tests/e2e_converters.rs` | UU content | OpenCode E2E | + +**Auto-merged on phase-58 (keep):** +- `crates/memory-installer/src/converters/claude.rs` — CREG/META **applies cleanly** + onto current main's claude converter +- `plugins/memory-query-plugin/.claude-plugin/plugin.json` — added, no conflict +- `crates/memory-installer/Cargo.toml` (`chrono`) + +### memory-orchestrator / memory-bench divergence (do not take orphan copies) + +| Crate | main @ d6c8ac7 | March line (p54–p58 identical) | +|---|---|---| +| `memory-orchestrator` | 8 files, **1458 lines**. Wired in v3.1 Integration Truth (#32): rerank 383, orchestrator 519, fusion 188. | 8 files, **878 lines**. expand.rs **identical** to main. types.rs trivial rename. Everything else is the pre-wiring snapshot. | +| `memory-bench` | 11 files, **2649 lines**, includes `judge.rs` (294) + LOCOMO v2 (`locomo.rs` 682, `runner.rs` 458). | 10 files, **1319 lines**, no judge, original LOCOMO adapter. | + +Taking either crate from the orphan line would **regress** main. + +--- + +## What main already has vs what only exists on the orphan line + +Grep of `origin/main` and `origin/gsd/phase-58-claude-registration-metadata` +(excluding `*.md` / `.planning`). + +| Topic | Main (`d6c8ac7`) | Orphan line (p58) | +|---|---|---| +| **Streaming RPCs** | None. No `rpc Export*` / `rpc Import*`. No `stream BackupChunk` / `stream ImportChunk`. | `ExportBackup` server-streaming, `ImportBackup` client-streaming, plus unary `ExportDaily`. Comment in proto: "first streaming RPC". | +| **export** | No `ExportDaily` / `export_daily` / `memory daily`. | `proto` messages + `query.rs:export_daily` + `commands/daily.rs` | +| **import / bootstrap** | No `ImportBackup` / `import.rs` / `memory import`. Word "bootstrap" does not appear in non-doc code. | `import.rs` + CLI + round-trip test. March v3.1 "import/bootstrap". | +| **JSONL backup** | No `backup.rs` / `ExportBackup` / `memory backup`. | `memory-service/src/backup.rs` (308) + CLI backup (308) | +| **known_marketplaces** | Absent. | `claude.rs:build_known_marketplaces` → `~/.claude/plugins/known_marketplaces.json` (CREG-01) | +| **plugin.json** | **Zero files.** Docs mention the path as a future layout (`docs/plans/v2.7-…`, authoring-guide). | `plugins/memory-query-plugin/.claude-plugin/plugin.json` only on **p58** | +| **uninstall** | Comment in `writer.rs` ("future `--uninstall`") + `install-helper.sh uninstall()`. | Same. No new uninstall implementation. | +| **install-service** | **Absent both sides.** | **Absent.** | +| **rebuild-toc** | `memory-daemon admin rebuild-toc` **exists and exits non-zero**: "offline TOC rebuild is not implemented; TOC nodes are produced by the daemon's scheduled rollup jobs". CHANGELOG + README status table match. Import CLI on the orphan tells the user to run it after restore. | Same stub (older daemon). | +| **rebuild-bm25** | Exists; CHANGELOG: "relabelled: it prunes documents below `--min-level` and re-indexes nothing". | Same command exists (pre-relabel). | +| **OpenCode converter** | **Deleted** in `#36` shop-window. | Full converter on p57/p58; stub on p54–p56. | +| **Claude generate_guidance** | Returns empty vec (test `generate_guidance_returns_empty`). | Emits known_marketplaces + installed_plugins + settings (CREG/META). | + +File existence (yes/NO): + +``` +file main p54 p55 p56 p57 p58 +commands/daily.rs NO yes yes yes yes yes +commands/backup.rs NO NO yes yes yes yes +commands/import.rs NO NO NO yes yes yes +service/backup.rs NO NO yes yes yes yes +service/import.rs NO NO NO yes yes yes +tests/import_round_trip.rs NO NO NO yes yes yes +converters/opencode.rs NO yes yes yes yes yes +converters/claude.rs yes yes yes yes yes yes +plugin.json NO NO NO NO NO yes +memory-opencode-plugin/README.md NO yes yes yes yes yes +2026-03-23-memory-export-import-design.md NO yes yes yes yes yes +bench/judge.rs yes NO NO NO NO NO +service/federated.rs yes NO NO NO NO NO +``` + +Main CLI `Commands` enum: Search, Add, Recall, Context, Timeline, Summary. +Orphan p56+ adds Daily, Backup, Import. recall.rs / summary.rs / timeline.rs +blobs are **identical** on main and p56. + +--- + +## Recommendation (cherry-pick by feature; keep branches) + +Two slices. Do **not** merge any `gsd/phase-*` branch wholesale (add/add on +orchestrator + bench would regress v3.1 Make It True). Skip all `.planning/` +(phase-number collision with current v3.1/v3.2). + +### A. Export/import foundation (backfill) — take from phase-56, not later + +Cherry-pick these **feature** commits (skip docs + skip `acbd6ae` workspace +fmt/clippy, which can retouch orchestrator/bench): + +``` +# phase 54 — daily markdown +1e29127 feat(54-01): add ExportDaily proto messages and RPC +408003b feat(54-01): implement ExportDaily handler, trait dispatch, and client method +5be2c19 feat(54-02): add `memory daily` CLI subcommand with markdown rendering + +# phase 55 — JSONL backup / first streaming RPC +858532b feat(55-01): add ExportBackup proto definitions, tokio-stream dep, and storage iteration methods +2f2b148 feat(55-01): add streaming backup handler with service wiring +bf51772 feat(55-02): add memory backup CLI command with streaming client + +# phase 56 — import/bootstrap +2c737a9 feat(56-01): add ImportBackup client-streaming RPC to proto +b6c7935 feat(56-01): add import handler, service wiring, and client method +ea9ee1d feat(56-02): add memory import CLI command with manifest validation +53fa9fc test(56-02): add round-trip integration tests for import handler +``` + +Expected conflict files while cherry-picking onto current main (the rest of +those commits should apply or add new files): + +- `crates/memory-client/src/client.rs` — **will conflict**; keep main's + `ingest` / `route_query_ex`, add the three export/import methods. +- `crates/memory-cli/src/{cli.rs,main.rs,commands/mod.rs}` — **will conflict** + (independent CLI history); add Daily/Backup/Import variants next to existing + Search/Add/Recall. New files `daily.rs` / `backup.rs` / `import.rs` should add clean. +- `proto/memory.proto` — likely **clean** (append after `GetSimilarEpisodes`). +- `memory-service/{ingest.rs,lib.rs,query.rs}` + new `backup.rs`/`import.rs` — + likely **clean** (auto-merged in the trial merge). +- `memory-storage/{db.rs,episodes.rs}` — likely **clean**. + +Do not take March `memory-orchestrator` or `memory-bench`. After import, the +CLI currently tells the user to run `memory admin rebuild-toc`; that command +is a documented non-implementation on main, so the backfill story needs a +follow-up (scheduled rollup, or actually implement rebuild-toc). + +### B. Claude Code registration + plugin metadata (CREG/META) — take from phase-58, skip 57 + +``` +b806364 feat(58-01): create plugin.json and add chrono dependency +aedbfb9 feat(58-01): implement Claude Code registry registration in generate_guidance +``` + +Trial merge showed **`claude.rs` auto-merges** and `plugin.json` is a clean add. +`chrono` on installer Cargo.toml also auto-merged. + +### C. Skip entirely + +- All of phase-57 (`f28793a`, `578883d`, and the OpenCode docs). Restoring + OpenCode would fight `#36` (modify/delete on `opencode.rs`, content conflict + on `converter.rs` + e2e). +- `gsd/phase-53-benchmark-suite` — already on main, older. +- `feature/phase-54-integration-truth` — already `#32`. +- `claude/spillwave-agent-memory-review-len4et` — already `#31`. +- `claude/phase-54-toolchain-drift-3k4fer` is a **current** docs PR for + `docs/plans/v3.2-prove-it-plan.md`; not March-line salvage. Handle separately + if that v3.2 plan is wanted. + +Suggested order on a new branch off current main: **A (54→55→56 feature +commits), then B (58-01 plugin.json + generate_guidance).** Keep all listed +remote branches. + diff --git a/docs/plans/v3.2-prove-it-plan.md b/docs/plans/v3.2-prove-it-plan.md new file mode 100644 index 0000000..5159a79 --- /dev/null +++ b/docs/plans/v3.2-prove-it-plan.md @@ -0,0 +1,366 @@ +# v3.2 "Prove It" — Review and Plan of Action + +**Date:** 2026-09-01 +**Verified against:** `main` @ `d6c8ac7`, release `v3.1.0` (run 33458631284) +**Status:** Adopted 2026-09-01 — GSD milestone v3.2, Phase 59 executing +**Issues:** #39 (LOCOMO), #40 (vector/topic quality), #41 (backfill), #42 (install-service), #43 (TOC rebuild), #44 (cross-encoder / 62) + +--- + +## 1. Where we are + +Everything in this section was checked against the repository, the release, +or the workflow history today, not recalled from planning docs. + +| Fact | Value | +|---|---| +| Latest release | `v3.1.0`, published 2026-09-01 01:45 UTC, **5 of 5 platforms** — first full-platform release in the repo's history | +| Code | 20 crates, 64,626 LOC Rust | +| Tests | 1,205 workspace + 60 e2e cargo tests green; 114 bats CLI tests in 16 files; Tier 2 weekly run passed once | +| Open GitHub issues | **0** — the backlog exists only in `.planning/` | +| Committed benchmark results | 2 files, both **mock backend + mock judge** (`custom-harness-mock.json`, `locomo-smoke.json`, 4 questions) | +| README status table | Solid ×6 · Works ×2 · Experimental ×2 · Not implemented ×3 | +| Unmerged work | `origin/gsd/phase-56-import-bootstrap` — 81 commits, "v3.1 Memory Export/Import", March 2026, never merged | + +### What v3.1 delivered + +v3.1 was a truth milestone. It shipped no capability; it made the claims match +the code: the orchestrator is reachable, hybrid fusion actually fuses, +explainability reports what ran, the 64.6 s TOC figure was retracted, the +benchmark harness stopped calling a substring metric "LOCOMO", and the repo +gained a README, LICENSE, positioning doc, and a supported-surface tier. + +### What v3.1 deliberately left open + +From the README, CHANGELOG, and positioning doc's own words: + +- No real-backend / real-judge LOCOMO run, so **no comparative claim anywhere** +- Vector retrieval quality and topic-graph clustering are **not benchmarked** +- No BM25 backfill for pre-v3.1 events +- Cross-encoder rerank, offline TOC rebuild, background daemonization: + **not implemented**, and now say so instead of pretending + +### What was planned before this, and where it went + +There is no GitHub issue holding a plan — the repo has never had an issue. +The earlier plans live in three places: + +| Plan | Where | Status today | +|---|---|---| +| **v3.1 "Make It True"** (PR #31, `docs/plans/v3.1-make-it-true-plan.md`) | merged | Shipped as v3.1.0. This document is its sequel | +| **March roadmap** — v3.1 *Memory Export/Import* (Phases 54–56), v3.2 *Plugin Installer & OpenCode Converter* (57–59), v3.3+ (`--for all`, `--all`, Gemini/Codex/Copilot registration) | `.planning/ROADMAP.md` on `origin/gsd/phase-58-claude-registration-metadata` | **Never merged.** Superseded 2026-03-26 when v3.1 was re-planned. Export/import: built. Claude Code registration + plugin metadata (CREG/META): built, all requirements checked. OpenCode converter: built, now obsolete. Uninstall + Status (UNINST/STAT): not started. None of it is on `main` — `memory-installer` has no registration, uninstall, or status today | +| **v3 design spec "does not include"** (`docs/superpowers/specs/2026-03-21-v3-competitive-parity-design.md`) | merged | REST/HTTP endpoint, Python SDK, memory views UI, cross-encoder rerank — all still future. Cross-encoder is Phase 62 below; the other three stay **v3.3+** because they are new capabilities and v3.2's job is proof and operability | + +The March line is one nested branch of 99 commits (import-bootstrap ⊂ +opencode-converter ⊂ claude-registration), not three efforts, and it diverges +from `main` in `memory-orchestrator` and `memory-bench` as well as the +installer — it was cut before v3.0's PRs were squash-merged. That is why +59-02 produces a conflict map before anyone cherry-picks. + +--- + +## 2. Findings + +Severity: **blocker** stops the next thing you want to do · **high** will bite +within a milestone · **medium** debt worth scheduling. + +### F1 — The release process has no guardrails `blocker` + +Today a `git push origin v3.1.0` shipped a tag from a stale local ref. The +Release workflow built `acc7294` — `Cargo.toml` said `2.7.0`, none of Phases +54–57 present — labelled it "Release 3.1.0", and published it. It was public +for 17 minutes. Nothing in the pipeline checks that the tagged commit is on +`main`, that the crate version matches the tag, or that all five platforms +built (`release: if: always()` publishes whatever succeeded). + +The four-binary archive guard added in #37 ran for the first time today and +held. The rest of the pipeline has no equivalent. + +### F2 — 81 commits of unmerged work nobody is tracking `high` + +`origin/gsd/phase-56-import-bootstrap` holds a complete earlier "v3.1": +daily markdown export, structured JSONL backup with incremental support, +import/bootstrap with round-trip validation, and the codebase's first gRPC +streaming RPCs. It was finished 2026-03-24 and superseded two days later when +v3.1 was re-planned. The same line continues through +`gsd/phase-57-opencode-converter-registration` (obsolete — Phase 57 of the +*current* roadmap removed OpenCode) into +`gsd/phase-58-claude-registration-metadata`, which holds a finished Claude +Code plugin registration (`known_marketplaces.json`, `installed_plugins.json`, +`settings.json`, `.claude-plugin/plugin.json`) that `main` still lacks. + +This matters beyond hygiene: **an import path is a backfill path.** The BM25 +backfill gap (F5) may already be half-built on a branch nobody remembers. + +### F3 — The real benchmark is one command away and has never been run `blocker` + +The harness is done. `memory-bench locomo --backend cli --scorer llm-judge` +is wired end to end; `benchmarks/scripts/download-locomo.sh` fetches the real +dataset; the judge honors `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` and records +the model id. The only committed results are mock/mock. + +Every comparison claim in the positioning doc is gated on this run by the +doc's own rule ("until one is committed next to the claim"). The Show HN +draft cannot answer the first question it will get. + +One known gap in the harness for a real run: with `--backend cli` all +conversations share the daemon unless it is restarted between them (the +harness's own caveat). Per-conversation isolation on the live backend is a +task, not an assumption. + +### F4 — Retrieval quality has evidence for one layer out of three `high` + +BM25 has fixtures with labelled relevant items (recall@k in the custom +harness). Vector search has **zero** quality tests — `grep` for recall, +precision, MRR, or nDCG across `memory-vector`, `memory-search`, and +`e2e-tests` finds only lifecycle code. The topic graph's clustering is +unbenchmarked by the README's own admission. The status table's "Solid" for +vector search is accurate about the mechanism and silent about whether it +returns the right things. + +### F5 — Operational gaps a real user hits in week one `high` + +- **No backfill.** Anyone with pre-v3.1 events has empty `text_preview` + forever, or starts a new store. `admin rebuild-bm25` is a prune. +- **No daemonization.** `--background` exits non-zero. Users need a + launchd/systemd unit or a terminal they never close. +- **No offline TOC rebuild.** If the rollup job misses, there is no repair. +- **Panic surface.** Phase 54-06 cut lock-poisoning sites from 27 to 5. There + are 266 `unwrap()`/`expect()` calls in non-test daemon and service code. + Most are surely on infallible paths; none have been audited as such. + +### F6 — The planning source of truth is stale `medium` + +`.planning/PROJECT.md` — which CLAUDE.md names as the home of architectural +decisions — says "Version: v3.0 (In Progress)", lists OpenCode among the +adapters, and lists "API-based summarizer wiring" as deferred though #27 +shipped it. `STATE.md` and `MILESTONES.md` are current; `PROJECT.md` is what +a new contributor reads first. And with zero GitHub issues, the entire backlog +is invisible to anyone outside the planning folder. + +### F7 — Launch timing is coupled to F3 `medium` + +The blog post is about process and stands on its own. The Show HN, r/rust, and +r/LocalLLaMA drafts are product posts, and the product's positioning doc +forbids the comparison those audiences will ask for first. + +--- + +## 3. Where the project should be + +By the end of v3.2, a stranger arriving from a Show HN link should find: + +1. **A number.** One committed LOCOMO LLM-judge result on the real dataset, + real backend, documented hardware and model, sitting next to the + competitor figures with an honest note on commensurability. +2. **Evidence for every "Solid".** Each retrieval layer has a quality fixture + and a committed result, or its label drops to "Works". +3. **Something they can run for a week.** Daemon starts at login, existing + events get indexed, and the daemon does not panic on the paths a user can + reach. +4. **A repo that looks alive.** Issues for the known gaps, an accurate + `PROJECT.md`, no orphan branches. + +Nothing on that list is a new capability. v3.2 is the second half of v3.1's +thesis: v3.1 made the claims true; v3.2 makes them **provable**. + +--- + +## 4. Plan + +Four phases plus the launch side quest. Phases are ordered by dependency: +guardrails before anything ships, numbers before anything is claimed, +operability before anyone is invited to try it. + +Effort is in agent sessions (one focused session ≈ one merged PR of the size +v3.1 produced). Owner is **agent** unless it needs credentials, hardware, or +a judgment call, then **maintainer**. + +### Phase 59 — Guardrails and Inventory (3 plans · ~3 sessions) + +Small, first, and it protects everything after it. + +**59-01 Release pipeline checks** · agent · 1 session +- In `release.yml`, before any build: fail unless the tagged commit is an + ancestor of `origin/main`; fail unless `Cargo.toml` `workspace.package.version` + equals the tag minus `v` +- Change `release: if: always() && !cancelled()` to require all `build` + jobs succeeded; a missing platform fails the release instead of publishing + three archives +- Generate release notes from the matching `CHANGELOG.md` section, not + GitHub's auto-list of PR titles +- Verify: push a deliberately wrong tag (`v9.9.9-test` on a non-main commit) + and confirm the run fails at the guard, then delete it +- Document the tag procedure in `docs/RELEASING.md` with the explicit-SHA + form: `git tag -a vX.Y.Z ` — today's incident was a bare `git tag -a` + colliding with a stale local ref + +**59-02 Orphan branch triage** · agent + maintainer decision · 1 session +- Produce a one-page inventory of the three `gsd/` branches: what each + contains, which files conflict with current `main`, and which parts are + still wanted +- Recommendation going in: **cherry-pick by feature**, not by branch — + export/import (JSONL backup, import/bootstrap, streaming RPCs) as the + foundation for 61-01, and Claude Code registration + plugin metadata + (CREG-01..06, META-01..03) for 61-05. Skip the OpenCode converter entirely +- Map conflicts first: the line diverges from `main` in + `memory-orchestrator` and `memory-bench`, not just the installer +- Delete all three `gsd/` branches once the kept features are on `main` +- Maintainer decides; agent executes in Phase 61 + +**59-03 Planning truth** · agent · 1 session +- Rewrite `PROJECT.md` Current State for v3.1 shipped; remove OpenCode from + the adapter list; move API summarizer from Deferred to shipped +- Open GitHub issues for F3, F4, F5's three gaps, and cross-encoder rerank, + each linking the relevant README row, so the backlog is public +- Add v3.2 to `ROADMAP.md` and `STATE.md` once the maintainer approves this + plan + +### Phase 60 — Real Numbers (3 plans · ~4 sessions + one maintainer run) + +The milestone's centre of gravity. + +**60-01 Live-backend isolation** · agent · 1 session +- `memory-bench locomo --backend cli` must give each conversation a fresh + store. Implement per-conversation daemon spawn with a temp `--data-dir` + (the harness already does this for mock), or an `admin reset` RPC guarded + behind a bench-only flag +- Wait for the outbox drain deterministically (poll the checkpoint, not + `sleep 60`) +- Verify: the 1-conversation smoke fixture runs under `--backend cli` in CI + with a real daemon, mock judge, and the result file records + `isolation: per-conversation daemon` + +**60-02 The run** · maintainer (needs API key + a documented machine) · 1 session +- `benchmarks/scripts/download-locomo.sh` +- `memory-bench locomo --dataset locomo-data --backend cli --scorer llm-judge --output benchmarks/results/locomo-2026-MM-DD.json` +- Budget: ~2,000 questions × (retrieve + answer + judge) — under $10 on + `gpt-4o-mini`; wall clock dominated by ingest and drain, expect 1–2 hours +- Record hardware, model id, temperature, dataset SHA in the result (the + harness already writes these fields) +- Commit the result and update `docs/benchmarks.md` "Committed result" + +**60-03 Vector and topic quality fixtures** · agent · 2 sessions +- Add a labelled semantic fixture to the custom harness: queries whose + relevant items share meaning but not tokens (`jwt` vs `JSON Web Token`) + so BM25 alone fails and vector must carry it; report recall@5 for + BM25-only, vector-only, and hybrid +- Add a topic-graph fixture: known clusters, report purity or adjusted Rand + index against the labels +- Commit results; downgrade any README row whose result does not support + "Solid" +- Update the positioning doc's Claims Ledger with each number and its + artifact path + +### Phase 61 — Operate It (5 plans · ~6 sessions) + +**61-01 Backfill** · agent · 2 sessions +- `memory-daemon admin backfill-index --index bm25|vector|all`: replay + events from RocksDB into the index, reset the index checkpoint, resumable, + idempotent; progress on stderr +- Build on the import/bootstrap code from 59-02 if the triage kept it +- Verify: e2e test ingests events with an old daemon build's schema + (fixture), runs backfill, and `memory search` returns previews +- Update README status row and `docs/UPGRADING.md` to say backfill exists + +**61-02 Daemon lifecycle** · agent · 1 session +- Do **not** implement double-fork. Ship `memory-daemon install-service` + that writes a launchd plist (macOS) or systemd user unit (Linux) and + loads it, plus `uninstall-service` +- Keep `--background` exiting non-zero, now pointing at `install-service` +- Verify in the bats suites on both Tier 1 platforms + +**61-03 Panic audit** · agent · 1 session +- Enumerate the 266 `unwrap()`/`expect()` sites in `memory-daemon` and + `memory-service`; classify each as provably-infallible, needs-`?`, or + needs-a-metric; convert the second class; finish the 5 remaining + lock-poisoning sites +- Verify: a fuzz-style e2e that sends malformed and boundary requests to + every RPC and asserts the daemon is still answering afterward + +**61-04 Offline TOC rebuild** · agent · 1 session +- Implement `admin rebuild-toc` for real: rebuild nodes from events for a + date range, replacing the "exits non-zero with guidance" stub +- Verify: delete TOC nodes in a fixture store, rebuild, assert byte-equal to + the scheduled rollup's output + +**61-05 Installer: register, uninstall, status** · agent · 1 session +- Land the March CREG/META work: `memory-installer install --agent claude` + registers the plugin so Claude Code discovers it on launch; version from + `.claude-plugin/plugin.json`; re-install idempotent +- Build the two March phases that were never started: `memory-installer + uninstall --agent ` (removes registry entries and files; no-op when not + installed) and `memory-installer status` (installed runtimes, versions, + paths) +- `--for all` / `--all` and Gemini/Codex/Copilot registration stay v3.3+ as + the March roadmap had them +- Verify: bats — install, `status` shows it, Claude Code loads the plugin, + `uninstall`, `status` says not installed, second `uninstall` exits 0 + +### Phase 62 — Cross-encoder rerank (conditional · 2 sessions) + +Only if the 60-02 result shows retrieval, not generation, is the bottleneck +(the harness's per-type breakdown will say). The extension point exists and +returns an explicit error today; keep it that way until a number says +otherwise. Do not build ahead of evidence — that is how v3.0 got here. + +### Launch (side quest · maintainer) + +- **Now:** publish the blog post. It is about the process and needs no + number. +- **After 60-02 lands:** repo description and topics, enable Discussions, + record the demo, then Show HN / r/rust / r/LocalLLaMA with the number in + the first paragraph. The drafts in `docs/launch/` need one edit each to + cite it. + +--- + +## 5. Sequencing and estimates + +``` +Phase 59 ████░░░░░░░░░░░░░░░░ 3 sessions guardrails, triage, planning truth +Phase 60 ░░░░██████░░░░░░░░░░ 4 sessions + maintainer run +Phase 61 ░░░░░░░░░░██████████ 6 sessions +Phase 62 ░░░░░░░░░░░░░░░░░░██ 2 sessions only if 60-02 says so +``` + +59 and the agent half of 60 can overlap; 60-02 waits on 60-01; 61-01 waits +on the 59-02 decision. Roughly **13–15 agent sessions plus one maintainer +benchmark run**, which at v3.1's pace is two to three weeks. + +## 6. Risks + +| Risk | Mitigation | +|---|---| +| The LOCOMO number is bad | Then it is bad and gets committed anyway; the positioning doc already says how to talk about it. A bad honest number beats the current no number. Phase 62 exists for this case | +| Cherry-picking 81 commits is worse than rewriting | 59-02 produces the conflict map first; the maintainer chooses with data. Rewrite is acceptable — the branch is a reference, not an obligation | +| Live-backend isolation is slow (10 daemon spawns) | Acceptable for a run that happens once per release. Do not optimise it before it exists | +| API cost surprise | Cap the judge at 200 questions on the first run, commit that, then run the full set | + +## 7. Success criteria + +- [ ] A tag that is not on `main`, or whose version disagrees with + `Cargo.toml`, cannot produce a release (59-01) +- [ ] `benchmarks/results/` contains one `locomo_llm_judge` result on the full + dataset, real backend, hardware and model recorded (60-02) +- [ ] Every "Solid" row in the README status table cites a committed quality + result (60-03) +- [ ] A pre-v3.1 store can be backfilled without data loss (61-01) +- [ ] `memory-daemon install-service` works on macOS and Linux Tier 1 (61-02) +- [ ] `memory-installer install/uninstall/status` round-trips on Claude Code + and the plugin is discovered without manual registry edits (61-05) +- [ ] No `unwrap()` on a request path that user input can reach (61-03) +- [ ] `PROJECT.md` describes the shipped system; the known gaps are GitHub + issues; no orphan `gsd/` branches (59-03, 59-02) +- [ ] `task pr-precheck` green on every PR (standing rule) + +## 8. Decisions needed from the maintainer + +Recorded 2026-09-01 (plan adopted as written; recommendations accepted): + +1. **The March branch line:** cherry-pick export/import and Claude Code + registration by feature. OpenCode converter is dropped. Conflict map: + [phase-59-orphan-branch-triage.md](phase-59-orphan-branch-triage.md). + Agent executes the cherry-picks in Phase 61, not wholesale merges. +2. **Launch timing:** blog now (maintainer); product posts after 60-02. +3. **Daemonization:** service unit files, not double-fork. See #42. diff --git a/scripts/changelog-section.sh b/scripts/changelog-section.sh new file mode 100755 index 0000000..2f47821 --- /dev/null +++ b/scripts/changelog-section.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Print the CHANGELOG.md section for a version (heading through the next ##). +# Exits 1 if the section is missing so a release cannot ship empty notes. +set -euo pipefail + +if [[ $# -lt 1 ]]; then + echo "usage: changelog-section.sh [CHANGELOG.md]" >&2 + exit 2 +fi + +VERSION="${1#v}" +FILE="${2:-CHANGELOG.md}" + +if [[ ! -f "$FILE" ]]; then + echo "error: changelog not found at $FILE" >&2 + exit 1 +fi + +awk -v ver="$VERSION" ' + BEGIN { found = 0 } + $0 ~ ("^## v" ver "([[:space:]].*)?$") { + found = 1 + print + next + } + found && /^## / { exit } + found { print } + END { + if (!found) { + printf("error: no CHANGELOG.md section for v%s\n", ver) > "/dev/stderr" + exit 1 + } + } +' "$FILE" diff --git a/scripts/release-guards-test.sh b/scripts/release-guards-test.sh new file mode 100755 index 0000000..515671d --- /dev/null +++ b/scripts/release-guards-test.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +# Local tests for scripts/release-guards.sh and scripts/changelog-section.sh. +# No Rust toolchain required — runs on every PR via the "Release Guard Scripts" job. +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +GUARDS="$ROOT/scripts/release-guards.sh" +CHANGELOG_SH="$ROOT/scripts/changelog-section.sh" +FAILS=0 + +assert_exit() { + local want="$1" + local label="$2" + shift 2 + local got=0 + "$@" >/tmp/rg-out.txt 2>/tmp/rg-err.txt || got=$? + if [[ "$got" -ne "$want" ]]; then + echo "FAIL: $label (want exit $want, got $got)" + echo " stdout: $(cat /tmp/rg-out.txt)" + echo " stderr: $(cat /tmp/rg-err.txt)" + FAILS=$((FAILS + 1)) + else + echo "ok: $label" + fi +} + +WORKDIR="$(mktemp -d)" +trap 'rm -rf "$WORKDIR"' EXIT + +# --- changelog-section --- +cat > "$WORKDIR/CHANGELOG.md" <<'EOF' +# Changelog + +## v3.1.0 — Make It True (2026-08-31) + +Body of 3.1.0. + +### Added + +- a thing + +## v2.7.0 — Older + +Old body. +EOF + +assert_exit 0 "changelog extracts v3.1.0" \ + bash "$CHANGELOG_SH" 3.1.0 "$WORKDIR/CHANGELOG.md" +if ! grep -q "Body of 3.1.0." /tmp/rg-out.txt; then + echo "FAIL: changelog body missing" + FAILS=$((FAILS + 1)) +fi +if grep -q "v2.7.0" /tmp/rg-out.txt; then + echo "FAIL: changelog leaked the next section" + FAILS=$((FAILS + 1)) +fi + +assert_exit 0 "changelog accepts leading v" \ + bash "$CHANGELOG_SH" v3.1.0 "$WORKDIR/CHANGELOG.md" + +assert_exit 1 "changelog missing section fails" \ + bash "$CHANGELOG_SH" 9.9.9 "$WORKDIR/CHANGELOG.md" + +# --- git ancestor + version --- +REPO="$WORKDIR/repo" +mkdir -p "$REPO" +cd "$REPO" +git init -q +git config user.name "guard-test" +git config user.email "guard-test@example.com" +# Default branch name: main +git checkout -q -b main + +cat > Cargo.toml <<'EOF' +[workspace] +members = ["crates/x"] + +[workspace.package] +version = "3.1.0" +edition = "2021" +EOF +git add Cargo.toml +git commit -q -m "main: version 3.1.0" +MAIN_SHA="$(git rev-parse HEAD)" + +# Feature-branch commit that is NOT on main +git checkout -q -b feature/stale +echo "stale" > extra.txt +git add extra.txt +git commit -q -m "stale local ref" +STALE_SHA="$(git rev-parse HEAD)" +git checkout -q main + +assert_exit 0 "matching version on main succeeds" \ + bash "$GUARDS" --version 3.1.0 --sha "$MAIN_SHA" --main-ref main --cargo Cargo.toml + +assert_exit 0 "leading v on version is stripped" \ + bash "$GUARDS" --version v3.1.0 --sha "$MAIN_SHA" --main-ref main --cargo Cargo.toml + +assert_exit 1 "version mismatch fails (the v3.1.0-on-2.7.0 incident)" \ + bash "$GUARDS" --version 9.9.9 --sha "$MAIN_SHA" --main-ref main --cargo Cargo.toml + +assert_exit 1 "commit not on main fails" \ + bash "$GUARDS" --version 3.1.0 --sha "$STALE_SHA" --main-ref main --cargo Cargo.toml + +# An ancestor that is not HEAD still passes (old main commit). +echo "later" >> Cargo.toml +# keep version the same so only ancestry is under test +git add Cargo.toml +git commit -q -m "later commit still 3.1.0" +assert_exit 0 "older main commit is still an ancestor" \ + bash "$GUARDS" --version 3.1.0 --sha "$MAIN_SHA" --main-ref main --cargo Cargo.toml + +if [[ "$FAILS" -ne 0 ]]; then + echo "release-guards-test: $FAILS failure(s)" + exit 1 +fi +echo "release-guards-test: all passed" diff --git a/scripts/release-guards.sh b/scripts/release-guards.sh new file mode 100755 index 0000000..7fe85ab --- /dev/null +++ b/scripts/release-guards.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# Release guards for agent-memory. +# +# Fail unless: +# 1. workspace.package.version equals --version (leading "v" stripped) +# 2. --sha is an ancestor of --main-ref (the tagged commit is on main) +# +# Intended to run in .github/workflows/release.yml *before* any platform +# build. Also exercised by scripts/release-guards-test.sh on every PR. +set -euo pipefail + +usage() { + cat <<'EOF' >&2 +usage: release-guards.sh --version --sha [--main-ref origin/main] [--cargo Cargo.toml] +EOF + exit 2 +} + +VERSION="" +SHA="" +MAIN_REF="origin/main" +CARGO_TOML="Cargo.toml" + +while [[ $# -gt 0 ]]; do + case "$1" in + --version) + VERSION="${2:-}" + shift 2 + ;; + --sha) + SHA="${2:-}" + shift 2 + ;; + --main-ref) + MAIN_REF="${2:-}" + shift 2 + ;; + --cargo) + CARGO_TOML="${2:-}" + shift 2 + ;; + -h|--help) + usage + ;; + *) + echo "error: unknown argument: $1" >&2 + usage + ;; + esac +done + +if [[ -z "$VERSION" || -z "$SHA" ]]; then + echo "error: --version and --sha are required" >&2 + usage +fi + +VERSION="${VERSION#v}" + +if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "error: version must be X.Y.Z (optional leading v), got '$VERSION'" >&2 + exit 1 +fi + +if [[ ! -f "$CARGO_TOML" ]]; then + echo "error: Cargo.toml not found at $CARGO_TOML" >&2 + exit 1 +fi + +CARGO_VERSION="$( + awk ' + $0 == "[workspace.package]" { in_pkg = 1; next } + in_pkg && /^\[/ { in_pkg = 0 } + in_pkg && $1 == "version" { + val = $3 + gsub(/"/, "", val) + print val + exit + } + ' "$CARGO_TOML" +)" + +if [[ -z "$CARGO_VERSION" ]]; then + echo "error: could not parse workspace.package.version from $CARGO_TOML" >&2 + exit 1 +fi + +if [[ "$CARGO_VERSION" != "$VERSION" ]]; then + echo "error: Cargo.toml version '$CARGO_VERSION' does not match release version '$VERSION'" >&2 + echo " A tag that disagrees with the crate version cannot produce a release." >&2 + exit 1 +fi + +if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then + echo "error: '$SHA' is not a commit in this repository" >&2 + exit 1 +fi + +if ! git rev-parse --verify "$MAIN_REF" >/dev/null 2>&1; then + echo "error: main ref '$MAIN_REF' not found (fetch origin/main first)" >&2 + exit 1 +fi + +if ! git merge-base --is-ancestor "$SHA" "$MAIN_REF"; then + echo "error: $SHA is not an ancestor of $MAIN_REF" >&2 + echo " Refusing to release a commit that is not on main." >&2 + exit 1 +fi + +echo "ok: version $VERSION matches $CARGO_TOML; $(git rev-parse --short "$SHA") is an ancestor of $MAIN_REF"