Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "libra"
version = "0.23.54"
version = "0.23.55"
edition = "2024"
license = "MIT"
description = "AI agent-native version control system with Git on-disk compatibility, SQLite-backed metadata, and tiered cloud storage"
Expand Down
18 changes: 18 additions & 0 deletions docs/development/internal/session-capture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Session Capture decision

AgentTraces ingest (`ingest_agent_traces_payload_with_scope`) asks
`session_capture::decide` for two facts: the SQLite `agent_session.state`
string, and whether the existing committed or subagent checkpoint writer
should run. `decide` is a pure match over `LifecycleEventKind`. It does not
open a repository, read a transcript, or call `transition_phase`.

`repo_path == None` still skips checkpoint writes after the decision returns
`Committed` or `SubagentBoundary`. Owner filtering for `SessionStart` and
`TurnStart`, and the `stopped_at` column, stay in `runtime.rs`. Import,
`libra agent session` stop/resume, and the coverage gate write state on
their own paths and do not call `decide`.

AgentTraces 的 session_state 与 checkpoint 类别只来自 session_capture::decide。
transition_phase 只服务 HookTarget::AiIntent 的 session_phase,本文件不修改它。
decide 不读取 SessionPhase,也不复制 Entire 的 git session 存储。
本计划不编辑 docs/development/tracing/agent.md。
76 changes: 42 additions & 34 deletions docs/development/plan/plan-20260925.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/development/plan/plan-long.md
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ MEM-03 → MEM-04;LR-09;LR-10;MEM-05 / AG-ATTR 按需;MEM-06(并行协

| 日期计划 | 主要归属 | 当前状态 | 说明 |
|---|---|---|---|
| [`plan-20260925.md`](plan-20260925.md) | B(Session Capture 决策中层) | 已排期 | 把 AgentTraces ingest 的 `agent_session.state` 与 checkpoint 类别收成 `session_capture::decide`。OpenCode、Codex、Claude Code、Pi 计划已登记该前置,并与 Entire 的解析/纯决策/I/O 分工对齐。SCAP-01 尚未实现 |
| [`plan-20260925.md`](plan-20260925.md) | B(Session Capture 决策中层) | 执行中 | 把 AgentTraces ingest 的 `agent_session.state` 与 checkpoint 类别收成 `session_capture::decide`。OpenCode、Codex、Claude Code、Pi 计划已登记该前置。SCAP-02 已核对。SCAP-01 实现中 |
| [`plan-20260923.md`](plan-20260923.md) | Cross-cutting CLI completion | 已排期 | Cover implemented Git-compatible and Libra-only capabilities; static acceptance before opt-in dynamic completion. CP-00..20 pending; capability inventory may add bounded cards. No implementation claimed. |
| [`plan-20260708.md`](plan-20260708.md) | A(LR-04/05/09 相邻基础) | 已完成 | 主线记为历史完成,活跃残留另行排期;不关闭对应 LR |
| [`plan-20260713.md`](plan-20260713.md) | B(LR-06/07/10 捕获前置) | 已完成 | 不覆盖 seal/preflight/capsule |
Expand Down
11 changes: 6 additions & 5 deletions docs/development/plan/plan-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

| 计划 | 类别 | 状态 | 一句话进度(卡片状态) |
|---|---|---|---|
| [`plan-20260925.md`](plan-20260925.md) | B(Session Capture 决策中层) | 已排期 | SCAP-02 → SCAP-01 均 `pending`。前置句已写入 OpenCode、Codex、Claude Code、Pi 计划,并与 B3-00 互斥。实现卡尚未开工 |
| [`plan-20260925.md`](plan-20260925.md) | B(Session Capture 决策中层) | 执行中 | SCAP-02 `in-progress` / `locally-accepted`。SCAP-01 `in-progress`。R9 双 `PASS`。B3-00 仍 `pending`,未与本卡同时开工 |
| [`plan-20260923.md`](plan-20260923.md) | Cross-cutting (implemented CLI completion) | 已排期 | English static-first rewrite; CP-00..20 pending; CP-00 inventory precedes implementation approval; CP-06 static acceptance blocks all dynamic work; no implementation/release claimed |
| [`plan-20260918.md`](plan-20260918.md) | 横切(`add` 命令收口) | **实施中** | OI-01..03 `done/complete`(v0.23.4/5/6);**OI-04 `in-progress`(v0.23.7)**;OI-05..WT-07 `pending` |
| [`plan-20260919.md`](plan-20260919.md) | 横切(global 配置迁 XDG) | 实施中 | GCX-01 `done/complete`(v0.23.1);GCX-02/03/04 于 2026-09-22 完成实现+测试+文档,`locally-accepted`(版本 bump 与 D 组发布未执行;本轮按操作者指示未调用 Codex review) |
Expand Down Expand Up @@ -83,7 +83,7 @@

| 计划 | 全部待执行卡 | 开工前置条件 |
|---|---|---|
| [`plan-20260925.md`](plan-20260925.md) | SCAP-02、SCAP-01 | 同一修订版 Codex 与 Claude 均为字面 `VERDICT: PASS` 且 P0/P1/P2 为 0。SCAP-01 依赖 SCAP-02 的关系表登记 |
| [`plan-20260925.md`](plan-20260925.md) | SCAP-02、SCAP-01 | R9 对同一修订版 Codex 与 Claude 均为字面 `VERDICT: PASS` 且 P0/P1/P2 为 0。SCAP-02 的登记已在 `fba6cbc`,本卡只核对。SCAP-01 依赖该登记 |
| [`plan-20260923.md`](plan-20260923.md) | CP-00..20 pending; expand bounded domain cards after inventory if needed | Audit handoff, required review PASS and DEP-CP-01..07; dynamic implementation requires CP-06 done/complete |
| [`plan-20260904.md`](plan-20260904.md) | CX-00..CX-30(35 卡) | Phase 0:Codex `PASS`;CX-30 受 DEP-CLI-mirror 三态串行约束 |
| [`plan-20260905.md`](plan-20260905.md) | CC-00..CC-06 | CC-02..06 依赖 plan-20260904 的 RG 卡完成 |
Expand Down Expand Up @@ -223,8 +223,9 @@ SBX-01..05 `done/locally-accepted`;**发布步按 DEFER-SBX-06 正式延后**

## 四、当前执行指针(next action)

- **当前正在执行:** `issues/474` → `CL-03` 发布窗口(`v0.23.49`,PR #512)。`compat-network-remotes` 因自托管 runner 掉线失败后已 `--failed` 重跑;其余 base.yml 作业此前已绿。`CL-04`..`CL-08` 已 `locally-accepted`,均未 bump。
- **下一步(CL-03 D 组落地后):** 按窗口依次 bump 并发布 `CL-04` → `CL-08`。
- **当前正在执行:** `plan-20260925` SCAP-01(发布者:本会话执行该卡的 Agent)。远端已发布 `v0.23.54`,本卡版本面是 `0.23.55`。
- **SCAP-01 与 B3-00:** B3-00 保持 `pending`,不与本卡同时 `in-progress`。
- **下一步(本卡发布之后):** `issues/474` 的 `CL-04`..`CL-08` 已 `locally-accepted`,按窗口依次 bump。
- **并行窗口(不在本执行指针):** `issues/476` WT-03 仍等 DEP-WT-08;`plan-20260918` 其余 add 卡、`plan-20260819` M2 仍登记为实施中,但不抢本卡的 `fsck.rs` 写集。

---
Expand All @@ -248,7 +249,7 @@ SBX-01..05 `done/locally-accepted`;**发布步按 DEFER-SBX-06 正式延后**
| [`plan-20260906`](plan-20260906.md) | SC-01 / SC-02(可并发) | SC-01 `base.yml` 最小权限加固;SC-02 会话入口 id 守卫 | 无 | **未定稿**(R2 PASS 已作废;R22 `FAIL`) | SC-04 受 DEP-SC-01/04/05/06;SC-07 受 DEP-SC-07 | ❌ 禁止开工 |
| [`plan-20260902`](plan-20260902.md) | OG-00 | opencode 1.18.29 Hook/export 契约探测 | 无 | **未取得双 PASS**(Claude 限额,Codex 仍在 FAIL 循环) | 无(Phase 1 与 RG 六卡解耦) | ❌ 禁止开工 |
| [`plan-20260911`](plan-20260911.md) | PI-01 | Repository-only `agent_kind=pi` migration | 无(DEP-PI-04 已满足:9/10 已收口) | **Claude Code 429 无 verdict,禁止开工** | DEP-PI-01/03 | ❌ 禁止开工 |
| [`plan-20260925`](plan-20260925.md) | SCAP-02 | 向四份采集计划登记 AgentTraces `decide` 前置与 `runtime.rs` 文件锁,并与 B3-00 互斥 | 无 | 关联段落已由 Codex 与 Claude 分别 `PASS` | 无 | 实现卡仍 `pending`,本表不标记开工 |
| [`plan-20260925`](plan-20260925.md) | SCAP-01 | AgentTraces ingest 改调 `decide`。发布者是本会话执行该卡的 Agent。B3-00 仍 `pending` | SCAP-02(登记已核对) | R9 双 `PASS` | 与 B3-00 不得同时 `in-progress` | 执行中 |
| [`issues/470`](issues/470.md) | FM-01 | 共享写入原语与 `restore` 系物化 | 无 | 尚未 Codex review | 关闭依赖 plan-20260918 FM-03/04(DEP-FM-06/07) | ❌ 禁止开工 |
| [`issues/473`](issues/473.md) | IN-01 / IN-03 / IN-02 | 空模板自引用防护 / 存储路径前置检测 / 换格式 reinit fail-closed | 无 | 尚未 Codex review | 无 | ❌ 禁止开工 |
| [`issues/474`](issues/474.md) | CL-03 | 其余历史遍历尊重 shallow 边界 | CL-02 | **R6 `PASS`** | 无 | ✅ `locally-accepted`(C 组 `v0.23.49`) |
Expand Down
2 changes: 1 addition & 1 deletion install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ $ErrorActionPreference = "Stop"
# One of the release version surfaces. `compat_version_surface_sync` pins it
# to Cargo.toml: this value is substituted verbatim into the download URL, so
# a stale value silently installs an old binary when -Version is not given.
$DefaultVersion = "v0.23.54"
$DefaultVersion = "v0.23.55"
# Public-only trust anchor for stable-manifest verification. It deliberately
# has no environment override: the install-smoke harness rewrites these
# clearly-marked constants in a temporary COPY of this script.
Expand Down
2 changes: 1 addition & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ INSTALL_DIR="${LIBRA_INSTALL_DIR:-$LIBRA_HOME/bin}"
# user opts in with LIBRA_ALLOW_FALLBACK=1. Default behaviour is fail-fast so
# offline installs cannot silently regress to a stale version. Bump this on
# every release so the opt-in fallback remains useful.
DEFAULT_VERSION="v0.23.54"
DEFAULT_VERSION="v0.23.55"
# Public-only trust anchor for stable-manifest verification. It deliberately
# has no environment override: the install-smoke harness rewrites these
# clearly-marked constants in a temporary COPY of this script, never through
Expand Down
2 changes: 2 additions & 0 deletions src/internal/ai/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! - [`runner`]: spawns hook commands and translates their exit codes into
//! [`event::HookAction`].
//! - [`runtime`]: turns stdin envelopes into recorded session updates.
//! - `session_capture`: pure AgentTraces state and checkpoint decision.
//! - `setup`: helper for materialising hook scripts on disk during `libra code`
//! bootstrap.

Expand All @@ -29,6 +30,7 @@ pub mod provider;
pub mod providers;
pub mod runner;
pub mod runtime;
mod session_capture;
mod setup;

pub use config::{HookConfig, HookDefinition, load_hook_config};
Expand Down
34 changes: 11 additions & 23 deletions src/internal/ai/hooks/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,9 @@ pub struct HookEnvelopeInvalid(pub String);
/// For [`HookTarget::AiIntent`] the function is exactly the historical
/// behaviour (1:1 byte-compatible). For [`HookTarget::AgentTraces`] the
/// function runs the external-Agent capture ingest — stdin parse, validate,
/// redact, upsert into `agent_session`, and (on `SessionEnd`) write an
/// E4-libra checkpoint commit on `refs/libra/traces`.
/// redact, and upsert into `agent_session`. Checkpoint class comes from
/// `session_capture::decide` and covers `TurnEnd`, `SessionEnd`,
/// `SubagentStart`, and `SubagentEnd`.
pub async fn process_hook_event_with_target(
command: super::provider::ProviderHookCommand,
expected_kind: LifecycleEventKind,
Expand Down Expand Up @@ -747,13 +748,7 @@ async fn ingest_agent_traces_payload_with_scope(
}
}

let new_state = match event.kind {
LifecycleEventKind::SessionStart => "active",
LifecycleEventKind::SessionEnd => "stopped",
LifecycleEventKind::Compaction => "condensed",
LifecycleEventKind::CompactionCompleted => "active",
_ => "active",
};
let new_state = super::session_capture::decide(event.kind).session_state;

// UPSERT: insert a fresh row on first sight; otherwise just bump
// `last_event_at`, `state`, and `redaction_report`. We key by
Expand Down Expand Up @@ -925,13 +920,9 @@ async fn ingest_agent_traces_payload_with_scope(
// redacted transcript blob (now the agent's full on-disk transcript, see
// the writer); events-blob inclusion remains a follow-up. Per-turn
// checkpoints give `libra agent checkpoint rewind` turn-level granularity.
if matches!(
event.kind,
LifecycleEventKind::SessionEnd
| LifecycleEventKind::TurnEnd
| LifecycleEventKind::SubagentStart
| LifecycleEventKind::SubagentEnd
) && let Some(repo) = repo_path
let checkpoint = super::session_capture::decide(event.kind).checkpoint;
if checkpoint != super::session_capture::CheckpointWrite::None
&& let Some(repo) = repo_path
{
// AG-19 owner-race closure: the pre-upsert owner check above is a
// fast path, but two providers racing on a fresh provider session
Expand Down Expand Up @@ -1005,10 +996,7 @@ async fn ingest_agent_traces_payload_with_scope(
// `doctor` surface nested runs as first-class checkpoints instead of
// leaving them as bounded `subagent_events` metadata on the main
// checkpoint. `SessionEnd` / `TurnEnd` keep the `committed` path.
if matches!(
event.kind,
LifecycleEventKind::SubagentStart | LifecycleEventKind::SubagentEnd
) {
if checkpoint == super::session_capture::CheckpointWrite::SubagentBoundary {
write_subagent_checkpoint(
conn,
repo,
Expand Down Expand Up @@ -3375,7 +3363,7 @@ impl SessionPhase {
}

#[cfg(test)]
mod tests {
pub(crate) mod tests {
use serde_json::Map;
use serial_test::serial;

Expand Down Expand Up @@ -3674,7 +3662,7 @@ mod tests {

const LEGACY_BOOTSTRAP_SQL: &str = include_str!("../../../../sql/sqlite_20260309_init.sql");

async fn ingest_fresh_conn() -> (TempDir, DatabaseConnection) {
pub(crate) async fn ingest_fresh_conn() -> (TempDir, DatabaseConnection) {
let dir = tempfile::tempdir().expect("tempdir");
// Use the canonical `libra.db` filename here so the Phase 3.5c
// object_index queue (`enqueue_agent_blob_object_index_update`)
Expand Down Expand Up @@ -3715,7 +3703,7 @@ mod tests {
(dir, conn)
}

fn ingest_envelope(
pub(crate) fn ingest_envelope(
hook_event_name: &str,
session_id: &str,
extra: serde_json::Value,
Expand Down
Loading
Loading