| perf(dev): a self-contained build and a two-tier test loop on every platform The edit-to-result loop was ~380s for the workspace on macOS and needed an environment variable on every command. This makes `cargo t` the whole story on macOS, Linux, and Windows, with numbers measured along the way. Build - `[profile.dev]` keeps only line tables (full debuginfo put ~190 MB of DWARF in each test binary and made the build linker-bound); dependencies build at opt-level 1 with no debuginfo; proc macros and build scripts at opt-level 3, since they are run once per dependent crate. - Test binaries: 78 to 11 in the everyday loop (13 under `--workspace`). Each one is a link and, on macOS (Gatekeeper) and Windows (Defender), a first-run malware scan of the whole file, paid serially by nextest's list phase before the first test starts. Integration tests now live in `tests/suite/` and compile into their crate's own test harness (`mod.rs`, included from `src/lib.rs` under `#[cfg(test)]`, with `extern crate self` so they keep addressing the public API by crate name). Only the CLI keeps a separate `suite` target, because its tests run the built executable. The evals harness leaves `default-members`, so a bare `cargo t` skips its two binaries while `--workspace` (CI, the hook, `cargo tf`) still builds them. A repo-layout test fails on an undeclared suite file, a stray top-level `tests/*.rs`, or a `mod.rs` that `lib.rs` never includes. - `ai-memory-cli` gains a lib target; `main.rs` is a shim. 806 tests that lived in the bin are reachable, and `--lib` runs skip the 127 MB binary. - The web crate's vendored `static/tailwind.css` is the default on every build, so nothing needs `TAILWIND_SKIP=1` any more: every release, Docker, and CI path already used the vendored file, and the download branch only ever ran for developers who forgot the flag (and then rewrote the source tree as a side effect). `TAILWIND_BUILD=1 cargo build -p ai-memory-web` regenerates it explicitly. CI runs that on Linux and fails if the committed file is stale, a check that did not exist before; the committed file reproduces byte for byte today. - `tokenizers` aligned on one version instead of the 0.21 pin plus the 0.22 candle pulled in. Test tiers - `.config/nextest.toml`: the `default` profile skips any test whose module path has a segment starting with `slow` or `stress` (`packaging::slow::*` drives real wrapper scripts and fake container engines at 10-20s each; `stress_*` modules hammer concurrency), reports every failure in one run, and marks anything over 5s in its summary so a new slow test is visible the day it lands. `full` runs everything. `ci` keeps its retries and writes JUnit. - `.cargo/config.toml` holds two aliases and nothing else: `cargo t` (default members) and `cargo tf` (`--workspace -P full`). `cargo t -p <crate>` builds just that crate. Neither passes `--all-targets`: there are no examples or benches, and it only added harnesses for two `test = false` targets. - `scripts/install-git-hooks.sh` installs an opt-in pre-push hook that runs the full tier, touching only its own marked block. Two independent things run the skipped tier: that hook, and CI, which uses `cargo test` and never reads the nextest config. Slow tests fixed rather than tiered - `project_observations` in the consolidator trimmed an over-budget projection one observation at a time, re-rendering the whole text and re-scoring every remaining candidate after each removal. Each score scans the body, so 256 observations of 4k chars cost ~65k body scans per prompt: 14s in production consolidation, exactly as in the unit test. Scores and per-block sizes are now computed once and the prune subtracts; output is unchanged and pinned by the existing tests. 13.9s to 0.18s. - Windows takes ~2s to refuse a loopback connect, so every hook test that posted to a closed port paid 2s per request. `dead_http_endpoint()` in the new `ai-memory-test-support` crate accepts and closes instead, with a fallback to the closed port where binding is denied. devin hook tests: 4.2s to 0.15s each. - The store unit fixture opened a file-backed SQLite with the default rollback journal and synchronous=FULL, so ~120 parallel fixtures fsynced every transaction. journal_mode=MEMORY + synchronous=OFF: 242s to 89s of test time, p90 1.6s to 0.5s. - Windows-only tests resolve `powershell.exe` or `pwsh.exe` once per process and the auto-improve eval fixtures are `.ps1` scripts instead of cmd.exe batch files; a post-bind settle sleep is gone; the two unpinned multi-thread tokio tests pin `worker_threads = 4`. The four copies of the PowerShell resolver and the mcp suite's duplicated `post`/`get` helpers are now one each. Not done, with the numbers in AGENTS.md: nextest vs in-process libtest is a wash per crate and a rout for the workspace (20s vs 309s); the `local-embeddings` default feature costs ~50s of cold build and ~27 MB per binary but under a second per relink, so it stays a product default. Measured: workspace loop ~380s to ~150s on macOS; on a 32-thread Windows box the warm everyday run is 20s of test time across 2919 tests in 11 binaries, and the rebuild after a core edit is 13s of cargo with lld plus the first-run scans. | 5 天前 |
| perf(dev): a self-contained build and a two-tier test loop on every platform The edit-to-result loop was ~380s for the workspace on macOS and needed an environment variable on every command. This makes `cargo t` the whole story on macOS, Linux, and Windows, with numbers measured along the way. Build - `[profile.dev]` keeps only line tables (full debuginfo put ~190 MB of DWARF in each test binary and made the build linker-bound); dependencies build at opt-level 1 with no debuginfo; proc macros and build scripts at opt-level 3, since they are run once per dependent crate. - Test binaries: 78 to 11 in the everyday loop (13 under `--workspace`). Each one is a link and, on macOS (Gatekeeper) and Windows (Defender), a first-run malware scan of the whole file, paid serially by nextest's list phase before the first test starts. Integration tests now live in `tests/suite/` and compile into their crate's own test harness (`mod.rs`, included from `src/lib.rs` under `#[cfg(test)]`, with `extern crate self` so they keep addressing the public API by crate name). Only the CLI keeps a separate `suite` target, because its tests run the built executable. The evals harness leaves `default-members`, so a bare `cargo t` skips its two binaries while `--workspace` (CI, the hook, `cargo tf`) still builds them. A repo-layout test fails on an undeclared suite file, a stray top-level `tests/*.rs`, or a `mod.rs` that `lib.rs` never includes. - `ai-memory-cli` gains a lib target; `main.rs` is a shim. 806 tests that lived in the bin are reachable, and `--lib` runs skip the 127 MB binary. - The web crate's vendored `static/tailwind.css` is the default on every build, so nothing needs `TAILWIND_SKIP=1` any more: every release, Docker, and CI path already used the vendored file, and the download branch only ever ran for developers who forgot the flag (and then rewrote the source tree as a side effect). `TAILWIND_BUILD=1 cargo build -p ai-memory-web` regenerates it explicitly. CI runs that on Linux and fails if the committed file is stale, a check that did not exist before; the committed file reproduces byte for byte today. - `tokenizers` aligned on one version instead of the 0.21 pin plus the 0.22 candle pulled in. Test tiers - `.config/nextest.toml`: the `default` profile skips any test whose module path has a segment starting with `slow` or `stress` (`packaging::slow::*` drives real wrapper scripts and fake container engines at 10-20s each; `stress_*` modules hammer concurrency), reports every failure in one run, and marks anything over 5s in its summary so a new slow test is visible the day it lands. `full` runs everything. `ci` keeps its retries and writes JUnit. - `.cargo/config.toml` holds two aliases and nothing else: `cargo t` (default members) and `cargo tf` (`--workspace -P full`). `cargo t -p <crate>` builds just that crate. Neither passes `--all-targets`: there are no examples or benches, and it only added harnesses for two `test = false` targets. - `scripts/install-git-hooks.sh` installs an opt-in pre-push hook that runs the full tier, touching only its own marked block. Two independent things run the skipped tier: that hook, and CI, which uses `cargo test` and never reads the nextest config. Slow tests fixed rather than tiered - `project_observations` in the consolidator trimmed an over-budget projection one observation at a time, re-rendering the whole text and re-scoring every remaining candidate after each removal. Each score scans the body, so 256 observations of 4k chars cost ~65k body scans per prompt: 14s in production consolidation, exactly as in the unit test. Scores and per-block sizes are now computed once and the prune subtracts; output is unchanged and pinned by the existing tests. 13.9s to 0.18s. - Windows takes ~2s to refuse a loopback connect, so every hook test that posted to a closed port paid 2s per request. `dead_http_endpoint()` in the new `ai-memory-test-support` crate accepts and closes instead, with a fallback to the closed port where binding is denied. devin hook tests: 4.2s to 0.15s each. - The store unit fixture opened a file-backed SQLite with the default rollback journal and synchronous=FULL, so ~120 parallel fixtures fsynced every transaction. journal_mode=MEMORY + synchronous=OFF: 242s to 89s of test time, p90 1.6s to 0.5s. - Windows-only tests resolve `powershell.exe` or `pwsh.exe` once per process and the auto-improve eval fixtures are `.ps1` scripts instead of cmd.exe batch files; a post-bind settle sleep is gone; the two unpinned multi-thread tokio tests pin `worker_threads = 4`. The four copies of the PowerShell resolver and the mcp suite's duplicated `post`/`get` helpers are now one each. Not done, with the numbers in AGENTS.md: nextest vs in-process libtest is a wash per crate and a rout for the workspace (20s vs 309s); the `local-embeddings` default feature costs ~50s of cold build and ~27 MB per binary but under a second per relink, so it stays a product default. Measured: workspace loop ~380s to ~150s on macOS; on a 32-thread Windows box the warm everyday run is 20s of test time across 2919 tests in 11 binaries, and the rebuild after a core edit is 13s of cargo with lld plus the first-run scans. | 5 天前 |
| Merge PR #645: self-contained build + two-tier dev test loop gb's dev-experience overhaul: Tailwind is now vendored-by-default (the network download runs only under TAILWIND_BUILD=1, still checksum-pinned) so plain cargo build needs no network; a new CI staleness gate diffs the regenerated CSS. Integration tests move into each crate's in-crate harness with a repo_layout guard against silently-dropped suites, and a local two-tier nextest loop (fast default; slow/stress via pre-push hook) — CI and bin/release still run the full 'cargo test --workspace --all-targets', so the merge gate is unchanged. Also de-dups tokenizers to a single 0.22.2 and fixes a quadratic consolidation projection hot path (byte-identical output, verified: total_chars tracking provably equals the old re-render since render_projection concatenates per-block text from an empty string). Maintainer follow-up pins the test-support dep version and restores the installer's exec bit. # Conflicts: # CHANGELOG.md | 5 天前 |
| fix: forward gemini keys in wrapper (#698), skip _pending sidecars in OKF scan (#695) #698: the Docker wrapper's -e forwarding allowlist carried every provider credential except GEMINI_API_KEY / GOOGLE_API_KEY, so a gemini provider or embedder selected inside the container never saw its key and failed with "provider not configured". Add both to the allowlist; guard with a packaging test naming every forwarded provider key. #695: the OKF conformance scan that feeds the pre-migration backup gate flagged auto-improve `_pending/` staging sidecars (no frontmatter, never migrated) as nonconformant, so once the backup receipt's archive was deleted every boot re-archived the whole data dir. Skip the `_pending/` subtree, matching the watcher indexer and the #669 ledger skip. Closes #698 Closes #695 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 3 小时前 |
| feat(importer): replay external conversations (#507) Co-authored-by: lihuiyang1024 <249777924+lihuiyang1024@users.noreply.github.com> Co-authored-by: AkitaOnRails <fabioakita@gmail.com> | 13 天前 |
| Merge PR #703: SIGINT+SIGTERM graceful shutdown on both transports (#699) Supersedes #702's stdio-only Ctrl-C stopgap with a complete handler: SIGINT and SIGTERM on both transports (SIGTERM is what docker stop / systemctl stop send), a bounded 5s grace drain, and a manual runtime with shutdown_timeout(ZERO) so the process exits gracefully after run() drops its guards in order — instead of the abrupt process::exit(0) that skipped the writer drain. Keeps #688's active-project seed. Both contributors' shutdown tests retained. | 3 小时前 |
| Merge main into release/2.1: pick up the 2.0.4 fix batch Forward-merge of the nine PRs that landed on main (the 2.0.4 batch: #642 auth stale-bearer, #646/#640 LoginLimiter, #644 Cursor attribution, #650/#647 reindex manifest, #638 MCP routing, #652 CI docs, #645 dev-loop/build) into the 2.1 feature train, so release/2.1 carries every fix before 2.1.0 is cut. Conflicts resolved: - crates/ai-memory-wiki/src/wiki.rs: 2.1's per-page write lock (page_locks, #607) and main's manifested_scopes memo (#650) are independent additions to the same struct/imports/constructor — kept both; imports merged to {HashMap, HashSet}. - CHANGELOG.md: [Unreleased] now carries 2.1's ### Added features above main's ### Changed + ### Fixed (the 2.0.4 fixes), Keep-a-Changelog order, single [2.0.3] section preserved. - crates/ai-memory-llm/tests/extra_headers_on_the_wire.rs (2.1's #606 test) relocated into tests/suite/ and declared in mod.rs to satisfy #645's one-test-binary-per-crate harness convention (caught by the repo_layout guard). fmt, clippy -D warnings, llm harness, and the repo_layout guard all green. | 5 天前 |
| Merge PR #703: SIGINT+SIGTERM graceful shutdown on both transports (#699) Supersedes #702's stdio-only Ctrl-C stopgap with a complete handler: SIGINT and SIGTERM on both transports (SIGTERM is what docker stop / systemctl stop send), a bounded 5s grace drain, and a manual runtime with shutdown_timeout(ZERO) so the process exits gracefully after run() drops its guards in order — instead of the abrupt process::exit(0) that skipped the writer drain. Keeps #688's active-project seed. Both contributors' shutdown tests retained. | 3 小时前 |
| feat(llm): send operator headers and identify ai-memory on every request OpenCode Zen/Go notified operators that requests missing an `x-opencode-session` header may start erroring, and reported ai-memory's traffic as "Unknown client — your requests carry no user agent, so we can't tell what sends them". Both halves are real: `reqwest` sends no `User-Agent` unless one is configured, and nothing in the crate could attach a caller-supplied header. Add `AI_MEMORY_LLM_HEADERS` (`llm_headers` in config.toml): comma-separated `Name=Value` / `Name: Value` entries, parsed and validated once at the configuration boundary into a typed `ExtraHeaders`, then sent on every chat request. This follows the rule provider auth already obeys — providers consume typed material and never re-parse operator strings — and means a malformed entry fails at startup rather than on the first consolidation pass. Headers ai-memory sets itself are refused rather than duplicated: `RequestBuilder::header` appends, so a second `authorization` would break the request instead of overriding it. Values are marked sensitive and never logged; `Debug` prints names only. Two defaults ride on the same mechanism, layered *under* the operator's so an explicit entry always wins: - `User-Agent: ai-memory/<version>` on every provider. Not opencode-specific: an unattributable request is the one a rate limiter throttles first, and any gateway benefits from knowing what called it. Copilot is excluded — it keeps `GitHubCopilotChat/<version>`, the agent GitHub's API expects. - `x-opencode-session` on the `opencode` provider, one id per process, since that header is Zen/Go's own request-correlation field. Zen/Go permits this. Its documentation ("Where can I use it?", docs/go.mdx) says Go "is designed to be used with OpenCode and other popular coding agents that produce a similar types of requests", documents the `https://opencode.ai/zen/go/v1/...` endpoints for direct use, and asks that the calling tool "does not generate abusive traffic" and "properly identifies itself (no broad user agents)". Hence naming ai-memory in the agent string rather than copying OpenCode's own — identifying the caller is the requirement, and impersonation would defeat it. Integration tests drive `build_provider` against wiremock: asserting the header is on the struct is not the same claim as asserting the right single value is on the wire. | 7 天前 |
| fix(marker): a capture-only marker no longer resets scope to default (#668) A .ai-memory.toml whose only content is a [capture] section shadowed an ancestor marker's workspace/project (and the other forwarded settings) because resolution used the nearest marker unconditionally — so a subdirectory marker added just to exclude paths from capture silently dropped the outer scope, filing pages under default/basename. A pure capture-only marker is now SCOPE/SETTINGS-TRANSPARENT: scope, project_strategy, drop_subagent_captures, default_global, and the [briefing] keys resolve from the nearest ancestor marker that declares at least one of them; [capture]/ignore_paths still comes from the nearest marker. Fixed across all three front doors — shell (hooks/_lib.sh), native (marker.rs/hook_capture.rs), and the generated TS integrations (shared applyMarkerParams / findSettingsMarker, all five adapters). The audit's premise that the TS adapters don't resolve scope was wrong; they do, via applyMarkerParams. Closes #668 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 2 天前 |
| fix(packaging): AUR PKGBUILD survives constrained builders (#677) Disable release LTO (`options=('!debug' '!lto')`) so the final link no longer gets OOM-killed on low-memory AUR build hosts, and pin CARGO_HOME to the registry that build() already populated before check() repoints HOME at an empty test home, so the --frozen test run can resolve the packages it fetched instead of failing offline. Guarded by a packaging test that asserts both properties. Closes #677 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 1 天前 |
| Merge main into release/2.1: pick up the 2.0.4 fix batch Forward-merge of the nine PRs that landed on main (the 2.0.4 batch: #642 auth stale-bearer, #646/#640 LoginLimiter, #644 Cursor attribution, #650/#647 reindex manifest, #638 MCP routing, #652 CI docs, #645 dev-loop/build) into the 2.1 feature train, so release/2.1 carries every fix before 2.1.0 is cut. Conflicts resolved: - crates/ai-memory-wiki/src/wiki.rs: 2.1's per-page write lock (page_locks, #607) and main's manifested_scopes memo (#650) are independent additions to the same struct/imports/constructor — kept both; imports merged to {HashMap, HashSet}. - CHANGELOG.md: [Unreleased] now carries 2.1's ### Added features above main's ### Changed + ### Fixed (the 2.0.4 fixes), Keep-a-Changelog order, single [2.0.3] section preserved. - crates/ai-memory-llm/tests/extra_headers_on_the_wire.rs (2.1's #606 test) relocated into tests/suite/ and declared in mod.rs to satisfy #645's one-test-binary-per-crate harness convention (caught by the repo_layout guard). fmt, clippy -D warnings, llm harness, and the repo_layout guard all green. | 5 天前 |
| fix(wrapper): reconcile Docker manifest-list digests and split local inspects | 1 天前 |
| fix: exclude deployment secrets from Docker context | 1 个月前 |
| fix(routing): pin managed skill payloads to LF (#502) | 13 天前 |
| feat(embeddings): in-process local embeddings - no key, no server 2.0 item 5 (docs/local-embeddings.md). AI_MEMORY_EMBEDDING_PROVIDER= local runs all-MiniLM-L6-v2 (384-dim) in-process via candle - pure Rust, so it builds on every release target with no onnxruntime native library (the roadmap's ort build-weight/licensing watch item resolved by not using ort). The tokenizer uses the fancy-regex backend to keep the tree C-free. The ~87 MB model is NOT bundled: serve fetches the three files once into <data_dir>/models/all-MiniLM-L6-v2/ with source-pinned sha256s (atomic tmp+verify+rename; a drifted or tampered file fails loudly), and offline installs drop them in manually - the loader re-verifies the same pins on every start. No key handling at all for this provider. Coexistence unchanged by design: (provider, model, dim) is stored per embedding row and hybrid search already ignores mismatched triples, so local vectors sit beside provider vectors; embed --force re-embeds opt-in. Feature-gated (local-embeddings, default on) so a slim build can drop the ML tree. Inference runs on spawn_blocking; mean-pool + L2-normalise per the sentence-transformers contract (unit vectors, dot = cosine). Eval harness gains --embeddings local (model fetched once into gitignored evals/models/, seeded into the eval server's data dir). Tests: presence probe, tampered-file refusal, missing-file message with the offline fix, and an #[ignore]d real-model inference test asserting unit norm and semantic ordering (run against the fetched files; passes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 8 天前 |
| test(sanitize): exempt the new credential fixtures from the secret scan The fixtures added in #408 are key-shaped by construction — that is the point of a sanitizer test — so gitleaks flagged the Stripe restricted-key and Telegram bot-token cases and failed CI. Exempt exactly those literals, per the fail-closed rule this file already states: specific strings with a rationale, never a path exclusion. The Telegram example is listed twice because gitleaks matches an allowlist against the secret a rule extracted, and `generic-api-key` extracts only the tail after the colon. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 23 天前 |
| chore(gitleaks): allowlist #598's sanitize test fixtures The full-history secret scan flagged two auth-header test fixtures added by PR #598 (sanitize.rs:631,633) — a realistic-looking UUID and a base64 token, which have high enough entropy to trip gitleaks' generic-api-key rule. They are synthetic values in the test that asserts NON-secret headers are left alone, not real secrets. Two changes: add their historical fingerprints to .gitleaksignore (the repo's mechanism for known test-fixture findings, matching the existing sibling entries), and lower the current fixtures to the low-entropy "obvious fake" shape the other sanitize fixtures use (per .gitleaks.toml) so future copies of the pattern do not re-trip the scan. The test is name-based, so the value shape does not change what it asserts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 7 天前 |
| feat: stage auto-improve proposals | 2 个月前 |
| docs: preserve canonical commit attribution | 1 个月前 |
| docs(routing): repo-native decision records own the why, keep them out of capture (#700) The routing snippet distinguishes a reviewed decision record in the repository (an ADR directory, a Keep the Why context/ tree) from a harness-local memory store: decisions go there under the project's convention, ai-memory keeps recall, handoffs and session history and does not duplicate the record as a page. AGENTS.md managed block regenerated to match. docs/usage.md: the ADR section becomes "Repo-native decision records" and names both shapes; it and docs/marker-file.md say to list the directory in [capture] ignore_paths, and why. | 3 小时前 |
| Merge PR #703: SIGINT+SIGTERM graceful shutdown on both transports (#699) Supersedes #702's stdio-only Ctrl-C stopgap with a complete handler: SIGINT and SIGTERM on both transports (SIGTERM is what docker stop / systemctl stop send), a bounded 5s grace drain, and a manual runtime with shutdown_timeout(ZERO) so the process exits gracefully after run() drops its guards in order — instead of the abrupt process::exit(0) that skipped the writer drain. Keeps #688's active-project seed. Both contributors' shutdown tests retained. | 3 小时前 |
| docs(routing): CLAUDE.md must import AGENTS.md to load it (#680) The managed routing snippet directs agents to write durable project rules into "the project's canonical agent instruction file", and both the CLI hint and the docs steer that file toward AGENTS.md. Claude Code loads CLAUDE.md and does not read AGENTS.md, so a project that follows the recommendation without a bare `@AGENTS.md` import line in CLAUDE.md keeps its canonical rules out of context at session start. They stay reachable, since an agent acting on a prose "read AGENTS.md" pointer opens the file, which makes adherence contingent on the agent choosing to read them. State the precondition in SNIPPET_BODY, mirror it beside the `--target AGENTS.md` guidance in docs/install.md and docs/usage.md, and switch this repository's own CLAUDE.md from a prose pointer to the import. The committed AGENTS.md managed block is regenerated to match SNIPPET_BODY, as committed_agents_md_matches_snippet_body requires. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KqE9rQpsjqNK5mmpqmggL7 | 1 天前 |
| perf(dev): a self-contained build and a two-tier test loop on every platform The edit-to-result loop was ~380s for the workspace on macOS and needed an environment variable on every command. This makes `cargo t` the whole story on macOS, Linux, and Windows, with numbers measured along the way. Build - `[profile.dev]` keeps only line tables (full debuginfo put ~190 MB of DWARF in each test binary and made the build linker-bound); dependencies build at opt-level 1 with no debuginfo; proc macros and build scripts at opt-level 3, since they are run once per dependent crate. - Test binaries: 78 to 11 in the everyday loop (13 under `--workspace`). Each one is a link and, on macOS (Gatekeeper) and Windows (Defender), a first-run malware scan of the whole file, paid serially by nextest's list phase before the first test starts. Integration tests now live in `tests/suite/` and compile into their crate's own test harness (`mod.rs`, included from `src/lib.rs` under `#[cfg(test)]`, with `extern crate self` so they keep addressing the public API by crate name). Only the CLI keeps a separate `suite` target, because its tests run the built executable. The evals harness leaves `default-members`, so a bare `cargo t` skips its two binaries while `--workspace` (CI, the hook, `cargo tf`) still builds them. A repo-layout test fails on an undeclared suite file, a stray top-level `tests/*.rs`, or a `mod.rs` that `lib.rs` never includes. - `ai-memory-cli` gains a lib target; `main.rs` is a shim. 806 tests that lived in the bin are reachable, and `--lib` runs skip the 127 MB binary. - The web crate's vendored `static/tailwind.css` is the default on every build, so nothing needs `TAILWIND_SKIP=1` any more: every release, Docker, and CI path already used the vendored file, and the download branch only ever ran for developers who forgot the flag (and then rewrote the source tree as a side effect). `TAILWIND_BUILD=1 cargo build -p ai-memory-web` regenerates it explicitly. CI runs that on Linux and fails if the committed file is stale, a check that did not exist before; the committed file reproduces byte for byte today. - `tokenizers` aligned on one version instead of the 0.21 pin plus the 0.22 candle pulled in. Test tiers - `.config/nextest.toml`: the `default` profile skips any test whose module path has a segment starting with `slow` or `stress` (`packaging::slow::*` drives real wrapper scripts and fake container engines at 10-20s each; `stress_*` modules hammer concurrency), reports every failure in one run, and marks anything over 5s in its summary so a new slow test is visible the day it lands. `full` runs everything. `ci` keeps its retries and writes JUnit. - `.cargo/config.toml` holds two aliases and nothing else: `cargo t` (default members) and `cargo tf` (`--workspace -P full`). `cargo t -p <crate>` builds just that crate. Neither passes `--all-targets`: there are no examples or benches, and it only added harnesses for two `test = false` targets. - `scripts/install-git-hooks.sh` installs an opt-in pre-push hook that runs the full tier, touching only its own marked block. Two independent things run the skipped tier: that hook, and CI, which uses `cargo test` and never reads the nextest config. Slow tests fixed rather than tiered - `project_observations` in the consolidator trimmed an over-budget projection one observation at a time, re-rendering the whole text and re-scoring every remaining candidate after each removal. Each score scans the body, so 256 observations of 4k chars cost ~65k body scans per prompt: 14s in production consolidation, exactly as in the unit test. Scores and per-block sizes are now computed once and the prune subtracts; output is unchanged and pinned by the existing tests. 13.9s to 0.18s. - Windows takes ~2s to refuse a loopback connect, so every hook test that posted to a closed port paid 2s per request. `dead_http_endpoint()` in the new `ai-memory-test-support` crate accepts and closes instead, with a fallback to the closed port where binding is denied. devin hook tests: 4.2s to 0.15s each. - The store unit fixture opened a file-backed SQLite with the default rollback journal and synchronous=FULL, so ~120 parallel fixtures fsynced every transaction. journal_mode=MEMORY + synchronous=OFF: 242s to 89s of test time, p90 1.6s to 0.5s. - Windows-only tests resolve `powershell.exe` or `pwsh.exe` once per process and the auto-improve eval fixtures are `.ps1` scripts instead of cmd.exe batch files; a post-bind settle sleep is gone; the two unpinned multi-thread tokio tests pin `worker_threads = 4`. The four copies of the PowerShell resolver and the mcp suite's duplicated `post`/`get` helpers are now one each. Not done, with the numbers in AGENTS.md: nextest vs in-process libtest is a wash per crate and a rout for the workspace (20s vs 309s); the `local-embeddings` default feature costs ~50s of cold build and ~27 MB per binary but under a second per relink, so it stays a product default. Measured: workspace loop ~380s to ~150s on macOS; on a 32-thread Windows box the warm everyday run is 20s of test time across 2919 tests in 11 binaries, and the rebuild after a core edit is 13s of cargo with lld plus the first-run scans. | 5 天前 |
| fix(admin): log the failures the server owns instead of only returning them (#692) `bootstrap_error_response` and `auto_improve_error_response` picked a status, serialized `e.to_string()` into JSON, and told the log nothing. An upstream provider error could therefore break every bootstrap while the server log showed only the run starting — the sole record of the cause was the CLI's stdout, which lives as long as the client process. A scheduled auto-improve tick has no client at all, so its provider failures left no operator-visible trace anywhere. A 5xx says the request was fine and the server could not serve it, so it now emits a `warn!` naming the status, the operation, and the error. A 4xx stays quiet: the caller was told and the caller was at fault, and logging those would let any client fill the log at will. The regression test drives the real router with a provider that fails the way a misdirected base URL does — HTTP 404, plain-text `404 page not found` — and asserts both halves: the body reaches the log, and a rejected request does not. Claude-Session: https://claude.ai/code/session_01FDaxUG5YY7Kx9UmoC3aLkn | 21 小时前 |
| release: v2.1.1 Bump workspace 2.1.0 -> 2.1.1 (all crates + Cargo.lock). CHANGELOG [Unreleased] becomes [2.1.1] - 2026-09-07 with a fresh [Unreleased]; compare links updated. 2.1.1 is a patch collecting the fixes on main since 2.1.0: BOM on frontmatter- less pages (#663), wiki commits no longer re-hash the whole tree (#665), typed relations preserved in multi-page batches (#667), serve stops re-archiving the data dir every start (#669), promptless sessions no longer synthesize wiki pages (#662), a capture-only marker no longer resets scope across shell/native/ TS (#668), and a routing-snippet note that ai-memory is the cross-harness memory of record (#671). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm | 2 天前 |
| release prep: MIT license, wiki migration framework, release scaffolding - LICENSE (MIT) + workspace license = MIT (down from MIT OR Apache-2.0) - Wiki-structure migration framework: V06 wiki_migrations table, WikiMigration trait, registry, and run_pending runner (registry starts empty; v1 ships per-project layout natively) - CHANGELOG.md, SECURITY.md, CONTRIBUTING.md - bin/release (fmt/clippy/test/deny/audit -> bump -> tag; never pushes) - .github release workflow + issue/PR templates - README: bootstrap example defers to default workspace/project - evals: inherit version/edition/rust-version from workspace Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> | 3 个月前 |
| Merge PR #649: design doc for transient provider fallback chains (#648) fcoalcantarajr's design proposal (docs-only) for ordered provider fallback on transient failures. Retargeted from main onto release/2.1 because the feature it specifies (#648) is an additive capability that belongs on the 2.1 train, not a 2.0.x patch. The doc is faithful to the current seams (LlmError:: is_transient, build_provider, ProviderConfig) and secret-free (env-var names only). #648 stays open as the accepted-but-unimplemented feature; the eventual implementation must add an [Unreleased] Added entry and address the latency-amplification footgun (failover x per-provider internal retries with no global deadline). Refs #648. | 5 天前 |
| fix(serve): warn instead of refusing an unauthenticated bind in a container The v1.27.0 bind guard reads a non-loopback bind as evidence of network exposure and refuses without a token. That inference holds on a host but not inside a container: publishing a port with `-p` requires binding 0.0.0.0 in the namespace, and whether that port reaches the network is decided by the host-side publish spec, which the process cannot observe. So the guard refused every container started from the documented Quick start — which publishes to loopback and was therefore safe — and with the documented `--restart unless-stopped` that became a restart loop. Verified against the published image: 1.28.0 exits(1) on the README command, and starts when only an auth token is added. Containers now warn, naming the publish spec as the thing to check. The host rule is unchanged: `validate_http_exposure` still refuses an unauthenticated non-loopback bind outside a container, and a test asserts that identical inputs refuse on a host and warn in a container. The Host allowlist deliberately does not back this up. It defends against DNS rebinding, where a browser sets the header; a client that can route to the port sets `Host` freely, confirmed by reaching a container's IP directly with a forged `Host: localhost`. Refs #407 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 23 天前 |
| fix(deny): check the all-features graph locally, matching CI CI runs cargo-deny with --all-features, while deny.toml set `[graph] all-features = false`. A command-line --all-features overrides the config value, so CI checked the all-features graph while the documented local gate `cargo deny check` (AGENTS.md, CONTRIBUTING.md) checked only the default-features graph. A license or advisory problem reachable only under a non-default feature passed locally and surfaced first in CI. Set `all-features = true` so the documented local command builds the same graph CI enforces. `cargo deny check` stays green after the change (advisories ok, bans ok, licenses ok, sources ok). Every other unflagged invocation (downstream, ad hoc) also widens to all features; if the narrower default-features graph was intentional the right fix is the opposite direction (drop --all-features from CI) and this can be discarded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016svpVgSxCEZfEbJomSCbaG | 23 小时前 |
| build(nix): pin flake inputs and verify the flake in CI Two gaps in the packaging as submitted. Inputs floated: `github:NixOS/nixpkgs/nixos-unstable` resolves to whatever that branch points at today, so two people — or the same person a week apart — could get different builds from identical source. A flake's whole value is reproducibility. Normally `flake.lock` pins this; the tree has no lock, and a contributor without Nix installed cannot generate one, so the revisions are pinned in `inputs` directly instead. Same determinism, no tooling required to keep it honest. Nothing executed it: ai-memory has no other Nix coverage, so `flake.nix` was source no job ran. It could break through a dependency bump, a toolchain change, or a new build script and stay green forever, and the first person to notice would be a NixOS user. Adds a `nix` workflow that runs `nix build` and then executes `./result/bin/ai-memory --version`, so a package that builds but cannot run still fails. It is scoped to changes in flake.nix / Cargo.lock / Cargo.toml / rust-toolchain.toml plus a weekly schedule and manual dispatch, rather than every pull request: a full release build under Nix costs more wall-clock than the rest of the matrix combined and almost no PR can affect it. Refs #405 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 22 天前 |
| M0: bootstrap workspace, CI, config loader, and init command Sets up the foundation: an 8-crate Cargo workspace, GitHub Actions CI (fmt + clippy -D warnings + test + deny + audit), the typed identity 3-tuple in ai-memory-core, the figment-based single-read config loader, and the `ai-memory init` / `status` subcommands. Design and research that drove these choices live in docs/; CLAUDE.md holds the per-session operating rules. See design-decisions.md §14 for the cross-cutting invariants (single config read path, typed identity, atomic writes, no global singletons, …) that every milestone must respect. Verification: - cargo build --workspace clean - cargo clippy --workspace --all-targets -- -D warnings clean - cargo fmt --all -- --check clean - cargo test --workspace: 12 passed - ai-memory --version, init, status --json all working - AI_MEMORY_DATA_DIR override honoured - Second init leaves config untouched (idempotent) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> | 3 个月前 |