Commit Graph
100 Commits
Author SHA1 Message Date
AkitaOnRailsandClaude Opus 4.8 754690e241 docs(providers): don't assert OpenRouter serves embeddings
The merged #951 stated OpenRouter exposes an OpenAI-compatible /v1/embeddings
endpoint as fact; that is unverified (historically OpenRouter has not) and
would silently fail for a user who configured it. Reworded to a conditional
'verify it exists first' pointer and made the multilingual-embedder
recommendation provider-agnostic.

Follow-up to #951 (#949).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-28 15:07:47 -03:00
AkitaOnRails cd06133677 Merge PR #951 into main 2026-09-28 15:06:53 -03:00
AkitaOnRails c8a3dbc8c4 Merge PR #958 into main
# Conflicts:
#	CHANGELOG.md
2026-09-28 15:06:53 -03:00
AkitaOnRails f2dc0caff3 Merge PR #955 into main 2026-09-28 15:06:20 -03:00
AkitaOnRailsandClaude Opus 4.8 954548ffe1 fix(mcp): union _global for single-project queries, not just unscoped ones
memory_query gated the reserved _global preferences union on 'no named
workspace/project'. The routing doctrine tells static MCP clients to pass
workspace+project on every call, which set that gate false, so static clients
never received global_scope_hits despite the documented contract (#930). The
union now keys on single-project resolution (scopes empty); an explicit
multi-scopes set is the only opt-out, and global=true/as_of are unaffected. The
double-search guard now resolves the queried project (named or active) rather
than the active-project default. The union remains keyed strictly to the
reserved _global scope and never leaks another project's pages (adversarial
test + security-boundaries row 1b).

Closes #930

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-28 15:02:38 -03:00
AkitaOnRails 85c9ba36d7 Merge PR #946 into main
fix(hooks): apply capture ignore_paths to shell commands (#946)

Native (ai-memory hook) path only; TS integrations parity tracked in #948.
2026-09-28 02:23:09 -03:00
AkitaOnRails 49147a5d17 Merge PR #923 into main
fix(restore): stage and verify the tarball before replacing the live data dir
2026-09-27 13:41:15 -03:00
AkitaOnRailsandClaude Opus 4.8 9746eba640 fix(hooks): capture Grok tool observation bodies
Grok Build CLI posts Claude Code's snake_case tool fields (tool_name /
tool_input / tool_use_id), but AgentKind::Grok was absent from both
closed_tool_agent (payload.rs) and the tool_observation_metadata agent
match (capture_policy.rs), so tool body extraction returned None and
every Grok PostToolUse observation was stored with an empty body while
still being captured. Grok now shares the Claude Code tool mapping.

Closes #931

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-27 13:04:37 -03:00
AkitaOnRails 6d389a5121 Merge PR #926 into main
fix(consolidate): unique session titles without starving the input floor (#926)

# Conflicts:
#	CHANGELOG.md
2026-09-27 12:46:59 -03:00
AkitaOnRails 9078dec50f Merge PR #935 into main
fix(consolidate): skip multi-page updates to pinned pages (#934)

# Conflicts:
#	CHANGELOG.md
2026-09-27 12:46:24 -03:00
AkitaOnRails 75ac107c26 Merge PR #940 into main
fix(bootstrap): drop empty chunk rationales from the manifest (#939)

# Conflicts:
#	CHANGELOG.md
#	crates/ai-memory-consolidate/src/bootstrap.rs
2026-09-27 12:45:05 -03:00
AkitaOnRails c0c137ca08 Merge PR #938 into main
fix(bootstrap): leave headroom for the token estimate (#937)

# Conflicts:
#	CHANGELOG.md
2026-09-27 12:44:06 -03:00
AkitaOnRails d2e75897e5 Merge PR #936 into main
fix(bootstrap): cap a lone chunk's output like any chunk (#928)
2026-09-27 12:43:34 -03:00
AkitaOnRailsandClaude Opus 4.8 433a19f3d5 chore(release): 2.4.1 — patch of accumulated fixes
Fixes-only patch on the 2.4.x line; additive items (input_token_safety_margin,
HTTP-exposure status field, status --workspace/--project scoping, jev adapter
docs) are reverted here and live on the release/2.5 feature line to keep the
2.5.0 version reserved for it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 18:01:14 -03:00
AkitaOnRails 42467259c3 Revert "Merge PR #911 into main"
This reverts commit b18cb1a3c4, reversing
changes made to 0e91c05b9b.
2026-09-25 17:59:27 -03:00
AkitaOnRailsandClaude Opus 4.8 e45db18a0e Revert jev-reranker-adapter docs (#873) for the 2.4.1 patch line
The additive jev adapter docs move to the release/2.5 (feature) line; the 2.4.1
patch stays fixes-only. Removes the doc, the example shim, and the
llm-providers pointer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 17:59:27 -03:00
AkitaOnRails 2c4fa06747 Revert "Merge PR #904 into main"
This reverts commit dfc7b6dc2b, reversing
changes made to 172f23085a.
2026-09-25 17:56:18 -03:00
AkitaOnRails 0fc60ffc24 Revert "feat(consolidate): add input_token_safety_margin to bound approximate token budget (#884)"
This reverts commit 7ff429935f.
2026-09-25 17:56:18 -03:00
AkitaOnRailsandClaude Opus 4.8 6c5692f0fa docs: add #913 CHANGELOG entry and the #919 occurred_at boundary row
#913 landed without the required CHANGELOG entry (merge gate); #919 added the
client-supplied event-time bound + its adversarial tests but not the
security-boundaries inventory row. Record both.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 16:56:40 -03:00
AkitaOnRails b18cb1a3c4 Merge PR #911 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 16:55:11 -03:00
AkitaOnRails 0e91c05b9b Merge PR #919 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 16:55:10 -03:00
AkitaOnRailsandClaude Opus 4.8 ced70b8e72 Merge PR #913 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 16:55:10 -03:00
AkitaOnRailsandClaude Opus 4.8 d5ebec30a9 Merge PR #915 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 16:55:10 -03:00
AkitaOnRailsandClaude Opus 4.8 ac0a2bd381 Merge PR #918 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 16:55:10 -03:00
AkitaOnRailsandClaude Opus 4.8 d227e422be Merge PR #916 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 16:55:10 -03:00
AkitaOnRailsandClaude Opus 4.8 1417119eec docs(changelog): add [Unreleased] entries for #903, #904 and credit #910
#903/#904 landed without the required CHANGELOG entries (merge gate); add them
(#903 under Changed, #904 under Added), and credit #910 alongside #886 on the
rule-slug word-boundary fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 11:25:47 -03:00
AkitaOnRailsandClaude Opus 4.8 dfc7b6dc2b Merge PR #904 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 11:24:27 -03:00
AkitaOnRailsandClaude Opus 4.8 172f23085a Merge PR #903 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 11:24:27 -03:00
AkitaOnRails b69120e8d6 Merge PR #906 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 11:24:27 -03:00
AkitaOnRails e5a4a0ffee Merge PR #910 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 11:24:27 -03:00
AkitaOnRails 25ce9109a6 Merge PR #908 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 11:24:27 -03:00
AkitaOnRails 9951eac64a Merge PR #897 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 11:24:27 -03:00
AkitaOnRailsandClaude Opus 4.8 919a90d77f Merge PR #896 into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 11:24:27 -03:00
AkitaOnRailsandClaude Opus 4.8 8629adc665 fix(consolidate): do not append .md to an empty path component (#885)
Appending the extension to an empty final component fabricated `.md` from a
missing path, which slipped past auto-improve's empty-path rejection and
surfaced as `unsupported_path_prefix` instead of `invalid_path`. Skip the
append when the final component is empty so a missing/invalid path stays empty
and is rejected upstream as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 00:11:56 -03:00
AkitaOnRails fe5b6ca789 Merge fix/885-886-884-consolidation into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 00:07:00 -03:00
AkitaOnRails ff3b515947 Merge fix/895-894-synth-log into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-25 00:05:53 -03:00
AkitaOnRailsandClaude Opus 4.8 b7e980e702 Merge fix/890-consolidate-job-reconcile into main
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 00:04:36 -03:00
AkitaOnRailsandClaude Opus 4.8 7ff429935f feat(consolidate): add input_token_safety_margin to bound approximate token budget (#884)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 00:03:30 -03:00
AkitaOnRailsandClaude Opus 4.8 22866c2e5f fix(consolidate): fold diacritics and truncate rule slugs at word boundaries (#886)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-25 00:03:30 -03:00
AkitaOnRailsandClaude Opus 4.8 1aad7a5d4b fix(logging): quiet the 30s reconcile summary and the rmcp SDK in the default log (#894)
Two routine INFO lines made up most of the default server log:

- the wiki watcher's "reconciliation pass complete" summary fired every
  RECONCILE_INTERVAL (30s) regardless of activity; drop it to debug. Its
  failure signals stay loud (the per-page warn!, the watcher_degraded
  error!, and the info! recovery transition).
- the external rmcp MCP SDK logs per-request lifecycle at info, which the
  default filter did not cap. Prepend `rmcp=warn` to the default filter so
  an operator can restore it via log_level (e.g. "info,rmcp=info") or
  RUST_LOG, while `tracing_appender=warn` stays appended and thus
  non-overridable — the invariant #15 feedback-loop guard.

Extract the filter string into a pure `default_filter` helper and unit-test
the ordering: the default suppresses both targets, log_level can restore
rmcp, and log_level cannot lower tracing_appender below warn.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 23:22:57 -03:00
AkitaOnRailsandClaude Opus 4.8 67574ecd27 fix(hooks): stop tool-family labels leaking into handoffs and titles, fix file-activity warning (#895)
Every closed-tool agent stores a call's title as `tool file` / `tool
non-file` / … (a partition of the calls, not a tool name), while the
reserved-protocol path uses the bare `file` / … spelling. Three readers
handled only one spelling or none:

- automatic handoffs listed the labels verbatim as `Tools used: tool
  file, tool non-file`;
- the "session ended without a normal stop while working with files"
  warning matched only the bare `file` spelling, so it never fired for a
  real (closed-tool) session — the heuristic was effectively dead;
- a session whose only non-prompt observation was such a call took the
  label as its page title.

Add one shared recognizer, `tool_family_from_title`, that maps both
spellings to a `ToolFamily`, and use it to drop the labels from the
handoff tool list and to drive the file-activity warning from either
spelling; reject `is_safe_tool_title` labels in the title fallback.
Synthesis-only; no page-read filtering (invariant #16 untouched).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 23:22:47 -03:00
AkitaOnRailsandClaude Opus 4.8 18e7936ca2 fix(consolidate): reconcile the session job row after a manual memory_consolidate (#890)
A manual memory_consolidate MCP call wrote the page directly through the
consolidator and never touched session_consolidation_jobs, so a session
whose automatic SessionEnd job had reached the terminal `failed` state
(which claim_next never re-picks) kept showing `failed` even though the
operator had just consolidated it — a two-sources-of-truth inconsistency.

Add a writer method reconcile_session_consolidation_completed(session_id)
that flips a `failed`/`pending`/`superseded` row for the session to
`completed`. It deliberately never touches a `running` row: that is an
active worker lease, and stomping it would violate invariants #2/#16, so
the automatic path's claim-guarded complete/fail stays the only lease
transition. The memory_consolidate handler calls it best-effort after a
successful, non-dry consolidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 23:11:27 -03:00
AkitaOnRailsandClaude Opus 4.8 385e865dd5 fix(consolidate): append .md to sanitized page paths so multi-page consolidation writes portable paths (#885)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 23:01:42 -03:00
AkitaOnRails 1c9bc40fcb Merge PR #887 into main
fix(install-hooks): Grok hook PowerShell call operator on Windows (#893)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 22:58:04 -03:00
AkitaOnRails 3a0887cc5e Merge PR #882 into main
fix(workstream): match OpenCode forward-slash directories on Windows (#891)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 22:57:38 -03:00
AkitaOnRailsandClaude Opus 4.8 e584271f37 Merge PR #879 into main
fix(hooks): url-encode bytes >= 0x80 on bash 3.2 (#877)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 22:57:14 -03:00
AkitaOnRails 3659121b13 Merge PR #880 into main
fix(run): import the session linked during a managed run (#820)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 22:57:14 -03:00
AkitaOnRailsandClaude Opus 4.8 d0a1448778 Merge PR #889 into main
fix(run): keep an existing session-aware Claude Code MCP bridge on auto-wire (#888)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 22:56:09 -03:00
AkitaOnRailsandClaude Opus 4.8 20e5055b7c docs(agents): make cargo clean a mandatory post-release step (#758)
The multi-worktree/multi-target-dir release flow leaves stale 100-180 MB test
binaries that have exhausted disk; record cargo clean after every release as a
mandatory maintenance rule alongside the Homebrew tap bump.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 20:16:07 -03:00
AkitaOnRailsandClaude Opus 4.8 ed0a28da39 docs(windows): add the Experimental→Supported tier exit-criterion checklist (#758)
Adds a delimited "Support Tier: Experimental → Supported Exit Criteria"
section enumerating what native Windows support requires and its current
status from repository evidence: CI trigger coverage (done), the hook-bundle
Windows job (done), the #[cfg(windows)] regression coverage (in-progress),
.exe code-signing (deferred-pending-policy — cert + CI-secret decision, App
Control/Smart App Control implications), and a native upgrade path (#801/#802).
It is the checklist a maintainer uses to decide promotion; it does not claim one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 17:56:22 -03:00
AkitaOnRailsandClaude Opus 4.8 c38c5c20f9 ci(windows): auto-run on platform-sensitive paths, keep label as manual override (#758)
The Windows tier promise no longer depends on a human remembering the
`windows` label. A leading `changes` job (dorny/paths-filter, SHA-pinned)
detects pull requests touching path handling, file locking, git plumbing,
and the hook bundle, and each Windows job runs when that path gate OR the
`windows` label fires. The `pull_request` trigger keeps no `paths:` filter
so all PRs still enter the workflow and the `labeled` override keeps working
for PRs outside those paths; schedule and workflow_dispatch are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 17:55:45 -03:00
AkitaOnRails 8ee81bede4 Merge PR #868 into main
fix(install-hooks): hide git console windows and memoize repo-root lookups in ts integrations (#863)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 17:24:58 -03:00
AkitaOnRails 4551b0b5b7 Merge PR #876 into main
fix(hooks): find payload keys in linear time (#870)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 17:24:25 -03:00
AkitaOnRails ed6a834fd3 Merge #871 and #872 Windows fixes into main
fix(hooks): derive project name from raw cwd so Windows casing does not split projects (#871)
fix(windows): document owner-account service guidance and surface wiki git owner failures (#872)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 16:04:11 -03:00
AkitaOnRailsandClaude Opus 4.8 93814c389c fix(windows): document owner-account service guidance and surface wiki git owner failures (#872)
A LocalSystem Windows service over a user-owned data dir trips libgit2's
dubious-ownership guard (CVE-2022-24765): every wiki commit fails with
code=Owner, but the failure was WARN-only, so capture kept working while
the wiki git history silently stopped advancing.

- Map an Owner-code git2 error to a distinct WikiError::GitOwner (the git
  CLI fallback is skipped: it enforces the same guard and would refuse
  identically). The owner check itself stays enabled (disabling it is
  unsafe and reopens the CVE).
- Surface the startup baseline-checkpoint owner failure at ERROR with the
  remedy (run the service as the owning user), classified through a small
  testable seam.
- docs/windows.md Scenario E: recommend a <serviceaccount>, correct the
  "only the data directory is account-sensitive" claim, and note the
  WinSW error-1069 / stale-password gotcha for Microsoft-account / PIN /
  Hello users.

A doctor wiki-git probe was considered but not added: doctor is
HTTP-only and never opens the store directly, so a probe would need a new
server endpoint — out of scope for a targeted fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:51:22 -03:00
AkitaOnRailsandClaude Opus 4.8 48c7d36392 fix(hooks): derive project name from raw cwd so Windows casing does not split projects (#871)
The hook router derived a project's name from the cwd after
normalize_project_path_key had ASCII-lowercased the entire Windows
drive-letter/UNC path (basename included), so a session in
`D:\...\Default Project` was captured under `default project` while the
CLI kept `Default Project`. get_or_create_project matches names
case-sensitively, so one folder minted two projects.

Take the name from the raw cwd; the cache key and cwd-prefix match keep
the case-folded path so #806 handoff stickiness is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:45:32 -03:00
AkitaOnRailsandClaude Opus 4.8 069b8baca9 docs(security-boundaries): add the session-purge scope+owner-bound row (#862)
Per the AGENTS.md mandatory-boundary-test rule, #866 touched purge/ownership
selection (a per-project/session isolation guard), so record the guard, its
enforcing code, and the adversarial cross-scope tests that would fail if it
regressed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:45:09 -03:00
AkitaOnRailsandClaude Opus 4.8 1c8907a4f8 Merge PR #866 into main
fix(store): purge every session-owned page version by frontmatter owner (#862)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:44:10 -03:00
AkitaOnRailsandClaude Opus 4.8 311fe87f31 chore(docs): drop exec bit on jev shim example and attribute its benchmark (#873)
Post-merge polish per audit: the example is stdlib-only and not meant to be
executed in place (100644), and the golden-set numbers are the contributor's
own measurement over a private wiki, so attribute rather than state as a
project benchmark.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:44:04 -03:00
AkitaOnRailsandClaude Opus 4.8 b55e7847f3 Merge PR #873 into main
docs(reranker): Jev judge-endpoint adapter for AI_MEMORY_RERANKER=llm

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:43:34 -03:00
AkitaOnRails 21fc32800c Merge PR #861 into main
fix(mcp): embed memory_query search text as a query

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 15:43:34 -03:00
AkitaOnRails e8d105a1cb Merge PR #824 into main
fix(dev): preserve pre-push hooks across worktree installs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm

# Conflicts:
#	CHANGELOG.md
2026-09-24 15:42:45 -03:00
AkitaOnRailsandClaude Opus 4.8 773e3a3b57 Merge PR #875 into main
fix(wrapper): keep native client and hook bundle out of the cache (#874)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-24 15:42:07 -03:00
AkitaOnRails 24ae5dd0b8 Merge branch 'test/boundary-adversarial' 2026-09-23 15:37:08 -03:00
AkitaOnRailsandClaude Opus 4.8 e297f9d3b6 test: five adversarial security-boundary regressions across handoff, page-sharing, message, and lifecycle-guard invariants
Each test actively attempts a boundary violation and asserts refusal, with
a legitimate control case, so a future regression that removes the guard
fails CI:

- handoff_admission: a non-admin proxied caller's `any_owner: true` on
  memory_handoff_accept is refused by require_admin_capability and does not
  claim the baton; root's any_owner accept is the control.
- multi_session: a page with a non-null author_id is still readable by a
  different operator via both search_pages_for_project and
  page_body_by_ids, pinning that author_id is attribution and never a read
  filter (invariant #16).
- agent_messages: the recipient cannot cancel the sender's message by exact
  id (the specific-id sibling of the existing whole-outbox test), and two
  concurrent pop_message calls on one message deliver it exactly once,
  pinning the state='pending' CAS in pop_message_in_transaction.
- removal: reset/restore/reindex/uninstall --purge-data each refuse and
  leave the data dir untouched when a sibling ai-memory process is
  detected. Adds a minimal, test-only injection seam to
  process_guard::sibling_processes() (AI_MEMORY_TEST_FORCE_SIBLING_PIDS)
  so the refusal path is deterministically testable without spawning a
  real sibling process; production behavior is unchanged since the
  variable is never set outside a test harness.

Each test was verified to fail when its guard is removed and pass when
restored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-23 15:35:42 -03:00
AkitaOnRailsandClaude Opus 4.8 4a58cb8b1d docs: security-boundary inventory + mandatory adversarial-test rule
Add docs/security-boundaries.md: the source-of-truth map of every isolation/
security guard (per-project + workspace isolation, auth ladder, handoff single-
claim + any_owner gate, invariant-#16 pages-shared/author_id-never-a-filter +
supersession, active-project pointer, sanitizer boundary, messaging scope,
scope-resolution fail-closed, destructive-op guards, hook backpressure, network
posture, + #708 as FUTURE) → the adversarial test that fails if the guard is
removed, with a keep-current protocol. Add the AGENTS.md standing rule: touching
boundary code (or adding a raw-id/unscoped/cross-scope entry point) requires an
adversarial boundary-breaking test proven to bite, and a matching inventory
update, in the same change; subsumes the older scope/permissions test bullets.
Also record that CI now runs doctests (--all-targets excludes them).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-23 15:17:31 -03:00
AkitaOnRailsandClaude Opus 4.8 fbef4b6f9a fix(setup-agent): fence the docker example so its doctest compiles; run doctests in CI
The `//!` doc comment in commands/setup_agent.rs had an indented `docker run`
block, which rustdoc treats as a Rust code block and tried to compile —
"unknown start of token: \" — a broken doctest on both main and release/2.5.
`cargo test --workspace --all-targets` (what the gates and CI ran) excludes
doctests, so it slipped through. Fence the block as ```text, and add a
`cargo test --workspace --doc` step to CI so a broken doctest can't ship again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-23 14:59:35 -03:00
AkitaOnRailsandClaude Opus 4.8 a38d3b3a54 docs(authz): close the enforcement-gap in the per-project authz design (#708)
The single authorize_project choke point at scope resolution is necessary but
not sufficient: unscoped/cross-project reads (memory_query global, global
recent, web search) and raw-id entry points (session/run/page id,
page_evidence_counts) never resolve a single scope and would bypass it. Document
that unscoped reads must filter by readable project in SQL before LIMIT (post-
filter leaks hit existence/counts) and that every bare-id path must resolve
id->project then authorize; recommend making unguarded lookups crate-private so
new call sites are compiler-forced through the gate. Add ship-inert / never-
fail-closed safeguards (empty grants + access_mode 'open' = no-op; restricted
with zero grants still admits root+creator; unreadable grants table degrades to
open with a warning) and extend the verification plan with unscoped-read-leak,
raw-id-authz, and ship-inert tests. Fix the stale release/2.3 -> release/2.5
migration target. Still design-only; no code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-23 14:54:45 -03:00
AkitaOnRails 248729497e Merge branch 'pr-850'
# Conflicts:
#	CHANGELOG.md
2026-09-23 14:08:33 -03:00
AkitaOnRails 09a85d724a Merge branch 'pr-856' 2026-09-23 14:08:04 -03:00
AkitaOnRails f7ec2eda6e Merge branch 'pr-852'
# Conflicts:
#	CHANGELOG.md
2026-09-23 14:08:04 -03:00
AkitaOnRailsandClaude Opus 4.8 4b6341b183 fix(messages): diagnose an empty inbox read under an inferred scope (#854)
A no-scope memory_message_pop/list resolves the shared active-project slot
(whichever project published last), so two same-operator agents with no
session id can have a pop land on a different inbox than the on-start notice
counted — "you have mail" then a silent {"message": null}. Add
ScopeSource::is_inferred() (broader than is_fallback: includes SharedSlot),
and when a message read is empty AND the scope was inferred, return the
resolved_scope (workspace+project), scope_source, and a hint to re-run with
explicit scope. Explicit/session-scoped empty reads are unchanged; the
mis-scoped pop consumes nothing. Regression tests reproduce the divergence
(mail in B, no-scope pop resolves A -> diagnosed null + hint; explicit pop of
B delivers) for both pop and list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-23 12:09:14 -03:00
AkitaOnRails f0bfaeb3fb Merge branch 'docs/comparison-2026-new-entrants' 2026-09-22 18:07:12 -03:00
AkitaOnRails c0a71f0306 Merge branch 'issue/848-consolidator-portable-path' 2026-09-22 17:49:18 -03:00
AkitaOnRailsandClaude Opus 4.8 734e96268a docs: add Engram, Caura, TencentDB Agent Memory, memU, EverOS to comparison docs (#810)
Resolve issue #810 and supersede the stub PR #828 with fair, first-party-sourced
assessments of five agent-memory projects, kept in sync across all three
comparison docs per the AGENTS.md rule.

Each project was researched from its own repo/README (and, where the name could
mislead, its LICENSE and the GitHub metadata endpoint) on 2026-09-22, not from a
name search:

- Engram (MIT, Go, SQLite+FTS5, MCP, single binary) — closest new sibling;
  agent-driven MCP capture and SQLite-as-truth vs our hook capture + git wiki.
- EverOS (Apache-2.0, Python, Markdown truth + SQLite/LanceDB) — file-first
  sibling, but LLM-required for the core flow.
- memU (Apache-2.0, Python, Markdown skill distillation, no MCP) — file-first
  LLM-leaning; hosted option.
- Caura (Apache-2.0 + managed, Postgres+pgvector) — governed multi-agent fleet
  memory; different buyer; its trust-tier governance is an honest gap for us.
- TencentDB Agent Memory (MIT, Node, SQLite default, proxy fan-in) — needs no
  Tencent DB despite the name.

comparison.md: 4 sourced camp-table rows (replacing the vague PR #828 rows),
maturity rows, and migration notes. research-2026-landscape.md: §3 camp-table
rows + inline entries per the no-standalone-doc convention + §6 sources +
popularity rows. competitive-parity.md: migration verdicts + a fleet-governance
honest-gap note. All benchmark numbers attributed to their named benchmark and
flagged self-reported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 17:49:07 -03:00
AkitaOnRailsandClaude Opus 4.8 5a13993479 fix(consolidate): sanitize LLM page paths in per-session consolidation
consolidate_session_multi's build_update built each WritePageRequest.path
straight from LLM output with no portability sanitize. PagePath::new is
deliberately tolerant, so a path with a Windows-illegal character (e.g. a
`:` copied from a conventional-commit subject) passed construction, entered
the atomic apply_batch call, and only failed ensure_portable at write time
- aborting the whole per-session consolidation batch and losing every other
page. This is the same class of bug already fixed for bootstrap in #847.

Factor slugify_page_path (+ PATH_ILLEGAL_CHARS) out of bootstrap.rs into a
new shared crate::path_sanitize module, and call it from build_update
before PagePath::new so rule-routing, per-user slot placement, and the
req.path == anchor comparison in consolidate_session_multi all see the same
sanitized path. Add an ensure_portable() final guard where the batch is
assembled that skips (warns on) a page slugify couldn't fix, instead of
aborting the batch, mirroring bootstrap's #847 fix.

Fixes #848.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 17:48:08 -03:00
AkitaOnRails ed48ddfda1 Merge branch 'pr-849' 2026-09-22 17:47:21 -03:00
AkitaOnRailsandClaude Opus 4.8 f500f5476e docs(run): export native store env (CLAUDE_CONFIG_DIR) before ai-memory run
Document that ai-memory run resolves the native session dir and installs
hooks from its own environment, so a custom CLAUDE_CONFIG_DIR set only
inside a harness wrapper causes a split-brain and "native transcript
import failed" (#820). Export per-account config dirs before invoking
ai-memory run. The launch-configuration ergonomics half of #820 remains a
separate design-first feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 17:43:42 -03:00
AkitaOnRails 601a0d04da Merge branch 'issue/792-tcp-keepalive' 2026-09-22 14:50:26 -03:00
AkitaOnRailsandClaude Opus 4.8 00aa6ee863 fix(serve): enable TCP keepalive on accepted connections (#792)
ai-memory serve leaked one file descriptor per dead hook/MCP peer.
A client whose connection dies without sending FIN (laptop sleep, a
VPN/Tailscale flap, an abrupt kill) leaves the accepted socket
ESTABLISHED forever, since the OS keepalive default is off. Over ~2-3
days of normal churn that exhausts the 1024-fd default and breaks the
healthcheck -- an unauthenticated availability/DoS. The rmcp
session-table half of this leak was already fixed in 2.4.0 by the
rmcp 2.x bump; this closes the remaining half-open-socket half.

Accepted sockets now get TCP keepalive via socket2, wired through
axum::serve::ListenerExt::tap_io (a hand-rolled axum::serve::Listener
newtype was tried first, but into_make_service_with_connect_info's
Connected<IncomingStream<'_, L>> bound is only implemented by axum for
its own TcpListener and, generically, for TapIo<L, F> -- never for an
arbitrary third-party L, and the orphan rule blocks implementing it
ourselves since neither Connected, SocketAddr, nor IncomingStream is
local to this crate). tap_io keeps the real peer SocketAddr flowing to
ConnectInfo while still touching every accepted stream.

New tcp_keepalive_secs config field (default 60s; AI_MEMORY_TCP_KEEPALIVE_SECS
env override; 0 disables keepalive entirely), read once through the
existing Config::load path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 14:48:48 -03:00
AkitaOnRailsandClaude Opus 4.8 668c9a9472 docs(llm-providers): note LLM and embedding base URLs are independent
Clarify that AI_MEMORY_LLM_BASE_URL redirects only the LLM endpoint;
AI_MEMORY_EMBEDDING_BASE_URL must be set separately or embedding traffic
keeps going to the embedding provider default. Both env vars already exist
and are consumed (config.rs figment mapping); this addresses the confusion
in #843 (the vars themselves were already present and documented).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 14:40:53 -03:00
AkitaOnRails 3c5b923839 Merge branch 'issue/847-bootstrap-portable-path' 2026-09-22 14:38:12 -03:00
AkitaOnRailsandClaude Opus 4.8 53d784ea28 fix(bootstrap): sanitize Windows-illegal chars in LLM page paths
`ai-memory bootstrap` returned a 500 when the LLM emitted a page path
containing a character Windows refuses (e.g. `:` copied verbatim from a
conventional-commit subject like `build(sandbox): orchestrate`). The
write loop validated model-produced paths with the deliberately
tolerant `PagePath::new` only; the bad path entered the batch and only
failed later at `ensure_portable` inside `Wiki::apply_batch`, which is
atomic — one bad page aborted every page in the run.

Add `slugify_page_path`, which replaces Windows-illegal filename
characters and ASCII control bytes with `-` in each `/`-separated path
component, preserving the directory shape. Run it before
`PagePath::new`, then call `ensure_portable` as a final guard; a path
that still fails after sanitizing is skipped with the existing `warn!`
rather than aborting the batch.

Checked the other LLM -> PagePath write funnels: `memory_write_page`
(server.rs) validates a single explicit write and returns a clear
error to the caller, not a batch, so it isn't the same failure mode.
`consolidator.rs::consolidate_session_multi` builds `PagePath`s from
LLM output via `build_update` and also calls `Wiki::apply_batch`, so it
has the same atomic-abort exposure — flagged for a follow-up ticket
since fixing it safely means threading sanitization through
`build_update`'s slot-placement/rule-routing logic and several test
call sites, which is a bigger, separate change.

Regression test `bad_windows_path_is_sanitized_not_aborted` fails on
the prior write loop and passes with the fix; unit test
`slugify_page_path_replaces_illegal_chars_and_keeps_slashes` covers the
helper directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 14:37:00 -03:00
AkitaOnRails 16e4f1c1c1 Merge branch 'pr-838'
# Conflicts:
#	CHANGELOG.md
2026-09-22 14:28:58 -03:00
AkitaOnRails 5a485edc8e Merge branch 'pr-845' 2026-09-22 14:28:02 -03:00
AkitaOnRailsandClaude Opus 4.8 3f522a2fe4 docs(windows-ci): record the CoW-off re-measure (Phase 1)
Disabling btrfs CoW on the VM storage dir cut the I/O-bound warm suite
~25% (1600s->1193s), confirming fsync-on-CoW was the bottleneck, but the
full suite still doesn't beat windows-latest (~1000s). Verdict unchanged:
the dockur VM is a focused-iteration / full-local-coverage tool, not a
faster full gate; no Phase 2 full-suite automation on this hardware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 14:25:27 -03:00
AkitaOnRailsandClaude Opus 4.8 b4933d7151 Merge release/2.4 into main: main becomes the 2.4.x trunk
2.4.0 shipped from release/2.4; bring main up to it so post-release fixes
(2.4.1) cut from main and features branch off a 2.4.0 base, per AGENTS.md
trunk-based releases. main keeps the #844 Windows cross-build gate on top;
CHANGELOG [Unreleased] is empty (its pre-release entries are in [2.4.0]);
workspace version is 2.4.0. release/2.4 now goes dormant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 14:15:13 -03:00
AkitaOnRailsandClaude Opus 4.8 a2b195d47c docs: Windows-CI study + measured Phase 0/1 results on marvin
Land the design study that ci.yml's windows-cross job references, and
append the measured results: Phase 0 (cross-build gate) shipped and green;
Phase 1 (dockur Windows Server 2025 VM) runs the full suite green but the
warm full run (1600s) is slower than windows-latest (~1000s) because the
I/O-heavy tests hit btrfs CoW — so the VM's value is on-demand focused
iteration, not a faster full gate. Records the host-specific dockur
accommodations (SELinux :Z + label:disable, Defender-off, QEMU-monitor
provisioning) and revises the recommendation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-22 03:37:01 -03:00
AkitaOnRailsandClaude Opus 4.8 efd08cae7b test: account for the windows-cross fixed-toolchain job
workflows_keep_fixed_rust_jobs_on_the_fixed_toolchain counts ci.yml jobs
pinned to Rust 1.95. windows-cross is now the second (after source-install),
so bump the expected count from 1 to 2. The guard's structural checks
(# 1.95 -> with: -> toolchain: "1.95") already pass for the new job.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 21:14:31 -03:00
AkitaOnRailsandClaude Opus 4.8 ac5dba606e ci: pin windows-cross to 1.95 so the msvc target std is found
rust-toolchain.toml pins 1.95 and overrides the active toolchain inside
the repo, so `cargo xwin build` runs under 1.95. dtolnay/rust-toolchain
had added the msvc target to `stable` instead, so the build failed with
"can't find crate for `core`" (the target's std was on the wrong
toolchain). Pin the job to 1.95 and add the target there, mirroring the
source-install job.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 21:02:36 -03:00
AkitaOnRailsandClaude Opus 4.8 93f148ccef ci: cross-build the Windows target per merge (build-only gate)
A #[cfg(windows)] compile or link break currently surfaces only in
windows.yml (nightly / label-gated, ~1000s) or at release time. Add a
Linux job that cross-builds the whole workspace --all-targets for
x86_64-pc-windows-msvc via cargo-xwin (clang-cl + lld-link against an
auto-downloaded MSVC CRT/SDK), so bundled SQLite and vendored libgit2
build for the target and the #[cfg(windows)] test binaries compile — at
Linux CI speed, on every PR.

Build-only by design: it proves the code compiles and links for Windows,
not that it behaves correctly there. Wine is deliberately not used to
fake a runtime (native PowerShell, NTFS case-folding, Win32 file-locking,
and verbatim \\?\ path handling are not faithfully reproduced); runtime
correctness stays with windows.yml and the local dockur VM loop
(docs/design-windows-ci.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 20:52:30 -03:00
AkitaOnRails b1b25219b5 release: v2.4.0 2026-09-21 19:22:36 -03:00
AkitaOnRails e804a31025 Merge main into release/2.4: bug batch + windows flake fix + auto-improve claim fix (V66)
# Conflicts:
#	crates/ai-memory-store/src/api_credentials.rs
#	crates/ai-memory-store/src/lib.rs
2026-09-21 18:58:26 -03:00
AkitaOnRails 63750e525d Merge main into #835 (resolve CHANGELOG after the bug batch landed)
# Conflicts:
#	CHANGELOG.md
2026-09-21 18:41:23 -03:00
AkitaOnRailsandClaude Opus 4.8 94057581e1 fix(tests): widen the PowerShell-hook connect deadline for slow Windows CI
powershell_utf8::powershell_hook_posts_json_as_utf8_bytes flaked on
windows-latest: a cold PowerShell start (spawn + JIT + dot-sourcing the hook
lib) exceeded the receiver's 10s accept deadline while output.status.success()
still passed — i.e. the hook worked, the mock server just gave up too early.
Raised the deadline to 60s. It only bounds failure detection (a working hook
connects in seconds; a broken one is caught by the status assertion), so this
removes the false negative without masking a real regression. Test-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 18:40:04 -03:00
AkitaOnRailsandClaude Opus 4.8 deb64063dd ci(windows): gate the hook-bundle job behind the windows label
Keeps it consistent with the project's fast-CI-per-merge rule (Windows off
per-PR feedback by default; opt in with the `windows` label, same as `test`).
Still runs nightly and on manual dispatch. The PowerShell hook-branch coverage
this job adds is real; it just follows the same opt-in gate as the rest of the
Windows workflow rather than running a windows-latest runner on every PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 16:38:46 -03:00
AkitaOnRailsandClaude Opus 4.8 15683d635c fix(migrations): bump schema-version pin to 66 for the renumbered claim migration
Companion to the V65->V66 rename: the pin test asserts MAX(refinery version),
which is now 66 on main (V64 + V66).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 16:37:19 -03:00
AkitaOnRailsandClaude Opus 4.8 2b04c00e7a fix(auto-improve): exclude sessions/ from the reviewer's recent-page context (#834)
The auto-improve reviewer only loads `_rules/`/`procedures/` page bodies,
and its recent-page context is a recency-ordered, one-line-per-page list
drawn from the shared project briefing. That list is dominated by
`sessions/` pages, so durable pages in `decisions/`/`gotchas/` outside
`_rules/` are effectively invisible to the reviewer, which causes
duplicate proposals.

Filter `sessions/` pages out of the recent-page list the reviewer builds
its prompt, patchable set, and existing-page index from. This is scoped
to the auto-improve reviewer only: it operates on the already-fetched
`briefing.recent_pages` and does not touch the shared
`briefing_for_project` reader, so the SessionStart briefing and
`memory_briefing` — where session pages legitimately belong — are
unchanged.

Also document the reviewer's context limits in
docs/auto-improvement-loop.md, with configurable patchable prefixes and
embedding-nearest dedup called out as deferred future work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 16:07:23 -03:00
AkitaOnRailsandClaude Opus 4.8 be7d6c7571 fix(auto-improve): skip misclassified proposals instead of failing the run (#832)
The proposal-staging loop returned `StoreError::InvalidState` for a
`Create` whose target already exists and for an `Update`/patch whose
target is missing. Because those returns fire inside the staging
transaction, one misclassified proposal discarded the entire run — every
sibling proposal and the run row. Create/update misclassification is an
ordinary probabilistic LLM error, not corrupt state.

Convert both arms to the existing skip machinery (push a `SkippedProposal`
with an accurate reason and `continue`), matching how a pending-target
UNIQUE collision is already handled and surfaced. The self-contradicting
case (two proposals in one run targeting the same path) stays a hard
error, and a create-on-existing is never coerced to an update — the page
could be pinned, so auto-applying would violate auto-improvement Safety
Invariant #10.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 16:07:23 -03:00
AkitaOnRailsandClaude Opus 4.8 f29451ed6f fix(migrations): renumber auto-improve claim migration V65 -> V66
release/2.4 already ships V65__page_compacted_marker (A2). Keeping this fix at
V65 would collide when main forward-merges into release/2.4 (two different V65
migrations -> refinery version conflict, a missing column on 2.4 stores, and a
broken 2.3->2.4 upgrade path). Renumbered to V66 so the forward-merge yields a
contiguous V65 (compacted) + V66 (claim attempts); the schema-version pin is
bumped to 66. main carries a harmless V64->V66 gap (it never ships a 2.3.x with
this migration; it reaches users via release/2.4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm
2026-09-21 15:59:02 -03:00