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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## [0.30.31] — 2026-10-07

### Memory core projection schema (plan-20260926 DM-01)

- Add the internal `2026092901_memory_core` forward-only migration creating
three zero-authority, rebuildable projection tables (`memory_episode`,
`memory_episode_evidence`, `memory_projection_state`) that back the upcoming
`libra memory` determinism surface. No public CLI behavior changes; this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

via Codex

[P1] Document the old-binary compatibility boundary in the release notes

Although this adds no new CLI command, applying 2026092901 changes the repository-open contract: binaries whose registry ends at 2026092701 (including the preceding release) reject the repository as a future schema. Reinstalling the old binary does not undo the receipt. This consequence is acknowledged in ADR-DM-13 and the internal SQL comments, but this release entry says No public CLI behavior changes and gives users no downgrade/recovery guidance.

Please explicitly state the minimum compatible version after migration, that recovery uses a compatible newer binary/forward fix rather than binary downgrade alone, and that users needing a return to the old version must retain a consistent pre-upgrade backup. Reflect the boundary in the user-facing compatibility documentation as well.

releases the internal schema seam ahead of the `libra memory` commands.

## [0.30.30] — 2026-10-06

### Skip-worktree entry points (issues/490 SW-07)
Expand Down
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.30.30"
version = "0.30.31"
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
30 changes: 15 additions & 15 deletions docs/development/plan/plan-20260926.md
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ flowchart TB

**Task type:** `migration`

**Lifecycle / Acceptance:** `pending` / 空
**Lifecycle / Acceptance:** `in-progress` / `locally-accepted`

**Description:** 迁移 `2026092901_memory_core`,建立 `DM-02` 派生所需的 3 张**零权威、可重建**投影表,并按 `ADR-DM-13` 以 `forward-only` 姿态交付。路径/搜索两张表由 `DM-10` 承接(按 `G-03` 拆卡,本计划无活动 waiver)。

Expand All @@ -622,23 +622,23 @@ flowchart TB

**Acceptance criteria:**

- [ ] `memory_episode` 的列、类型、可空性、CHECK 词表与 `UNIQUE` 约束逐项等于「Schema 规范」块的对应行。
- [ ] `memory_episode_evidence` 的列、CHECK 词表(`kind` / `link_confidence` / `resolution_status`)、PK 与 FK CASCADE 逐项等于「Schema 规范」块的对应行。
- [ ] `memory_projection_state` 的列与 PK 逐项等于「Schema 规范」块的对应行。
- [ ] `sql/migrations/2026092901_memory_core_down.sql` 按 FK 反序 `DROP TABLE IF EXISTS` 这 3 张表。
- [ ] 迁移在同一库上第二次运行是 no-op,不报错、不改变 `schema_versions`。
- [ ] `builtin_runner_registers_current_builtin_migrations` 断言长度比开工日读数大 1,tip 为 `Some(2026092901)`。
- [ ] `sql/migrations/README.md` 的 Current registry 表新增该迁移的一行。
- [ ] `memory_core_is_repository_role_only` 证明本迁移只注册到 Repository 角色,配置库版本回执不变,用例标注 `#[serial(env)]`。
- [x] `memory_episode` 的列、类型、可空性、CHECK 词表与 `UNIQUE` 约束逐项等于「Schema 规范」块的对应行。
- [x] `memory_episode_evidence` 的列、CHECK 词表(`kind` / `link_confidence` / `resolution_status`)、PK 与 FK CASCADE 逐项等于「Schema 规范」块的对应行。
- [x] `memory_projection_state` 的列与 PK 逐项等于「Schema 规范」块的对应行。
- [x] `sql/migrations/2026092901_memory_core_down.sql` 按 FK 反序 `DROP TABLE IF EXISTS` 这 3 张表。
- [x] 迁移在同一库上第二次运行是 no-op,不报错、不改变 `schema_versions`。
- [x] `builtin_runner_registers_current_builtin_migrations` 断言长度比开工日读数大 1,tip 为 `Some(2026092901)`。
- [x] `sql/migrations/README.md` 的 Current registry 表新增该迁移的一行。
- [x] `memory_core_is_repository_role_only` 证明本迁移只注册到 Repository 角色,配置库版本回执不变,用例标注 `#[serial(env)]`。

**Verification:**

- [ ] `source .env.test && cargo test --test db_migration_test memory_core_creates_three_tables` `(new)`
- [ ] `source .env.test && cargo test --test db_migration_test memory_core_check_vocabularies` `(new)`
- [ ] `source .env.test && cargo test --test db_migration_test memory_core_second_run_is_noop` `(new)`
- [ ] `source .env.test && cargo test --test db_migration_test memory_core_down_drops_all` `(new)`
- [ ] `source .env.test && cargo test --test db_migration_test memory_core_is_repository_role_only` `(new)`
- [ ] `source .env.test && cargo test --lib internal::db::migration::tests::builtin_runner_registers_current_builtin_migrations`
- [x] `source .env.test && cargo test --test db_migration_test memory_core_creates_three_tables` `(new)`
- [x] `source .env.test && cargo test --test db_migration_test memory_core_check_vocabularies` `(new)`
- [x] `source .env.test && cargo test --test db_migration_test memory_core_second_run_is_noop` `(new)`
- [x] `source .env.test && cargo test --test db_migration_test memory_core_down_drops_all` `(new)`
- [x] `source .env.test && cargo test --test db_migration_test memory_core_is_repository_role_only` `(new)`
- [x] `source .env.test && cargo test --lib internal::db::migration::tests::builtin_runner_registers_current_builtin_migrations`

**不计入 G-03 的强制门:** `source .env.test && cargo test --test compat_serial_registry`。registry 行与 `sh tests/NEXTEST_GROUPS.sh` 无 diff 由这道表面门守住。`plan-status.md` 随写集同步,不单列 AC。

Expand Down
12 changes: 6 additions & 6 deletions docs/development/plan/plan-status.md

Large diffs are not rendered by default.

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.30.30"
$DefaultVersion = "v0.30.31"
# 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.30.30"
DEFAULT_VERSION="v0.30.31"
# 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
67 changes: 67 additions & 0 deletions sql/migrations/2026092901_memory_core.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- Memory core projection schema (plan-20260926 DM-01, migration A).
--
-- These tables are ZERO-AUTHORITY and fully REBUILDABLE (GC-DM-01): every row is
-- a pure function of the repository's durable facts (commit/change, agent
-- session, agent run, bridge operation). They hold no authoritative state and
-- can be re-derived at any time via `libra memory rebuild`. A stale index never
-- answers (freshness is validated on read, mirroring 2026070301_revision_ordinal).
--
-- This migration is delivered `forward-only` (ADR-DM-13): once applied, an older
-- binary cannot reopen the repository database (future-schema rejection is
-- exercised by DM-10's simulated-old-runner test). The `_down.sql` is provided
-- and tested but is only a controlled test/ops tool, not the published rollback
-- path (progression by patching forward).
--
-- Table layout is frozen verbatim by plan-20260926 "Schema 规范" (DM-01 rows only).
-- `memory_episode_path` / `memory_episode_search_doc` belong to DM-10.
-- DM-01 deliberately does NOT create the FTS5 virtual table (that is DM-08).

CREATE TABLE IF NOT EXISTS `memory_episode` (
`episode_id` TEXT PRIMARY KEY,
`repo_id` TEXT NOT NULL,
`source_kind` TEXT NOT NULL CHECK (`source_kind` IN
('commit','agent_session','agent_run','bridge_operation')),
`source_key` TEXT NOT NULL,
`outcome` TEXT NOT NULL CHECK (`outcome` IN
('succeeded','failed','aborted','partial','unknown')),
`actor` TEXT,
`started_at` INTEGER NOT NULL,
`ended_at` INTEGER NOT NULL,
`anchor_commit` TEXT,
`change_id` TEXT,
`title` TEXT NOT NULL,
`body` TEXT NOT NULL,
`content_digest` TEXT NOT NULL,
`producer` TEXT NOT NULL DEFAULT 'derived-v1',
`rules_version` INTEGER NOT NULL,
UNIQUE(`repo_id`, `source_kind`, `source_key`)
);

CREATE TABLE IF NOT EXISTS `memory_episode_evidence` (
`episode_id` TEXT NOT NULL,
`ordinal` INTEGER NOT NULL,
`kind` TEXT NOT NULL CHECK (`kind` IN
('commit','checkpoint','review_run','operation')),
`ref_id` TEXT NOT NULL,
`link_confidence` TEXT NOT NULL CHECK (`link_confidence` IN
('identity','operation','temporal')),
`resolution_status` TEXT NOT NULL DEFAULT 'resolved' CHECK (`resolution_status` IN
('resolved','unresolved')),
PRIMARY KEY (`episode_id`, `ordinal`),
FOREIGN KEY (`episode_id`) REFERENCES `memory_episode`(`episode_id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `memory_projection_state` (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

via Codex

[P1] Validate pre-existing Memory table shapes before accepting this migration

CREATE TABLE IF NOT EXISTS silently keeps an existing table even when it does not have the frozen DM-01 shape, and the migration runner then commits the new schema receipt. This has a concrete branch-upgrade reproducer: create the Memory tables using PR #579's 2026092601_memory_core.sql at c4d5f749ac7b9dfc7b07b27a59885f761f1c99df, then apply this SQL. It succeeds, but memory_projection_state still has fts_synced_fingerprint and lacks revoked_count and aged_out_count; SELECT revoked_count, aged_out_count FROM memory_projection_state fails with no such column: revoked_count. The old evidence table also lacks this migration's resolution_status default.

Repositories that tried the earlier Memory branch are therefore certified as upgraded without the schema expected by subsequent Memory cards. Please inspect all three existing tables inside the migration transaction and either reject incompatible shapes with an actionable error or explicitly convert them. Add a regression fixture proving that a mismatched shape cannot commit the 2026092901 receipt; silently dropping existing tables is not a safe substitute.

`repo_id` TEXT NOT NULL,
`source_kind` TEXT NOT NULL CHECK (`source_kind` IN
('commit','agent_session','agent_run','bridge_operation')),
`cursor_json` TEXT NOT NULL,
`fingerprint` TEXT NOT NULL,
`rules_version` INTEGER NOT NULL,
`schema_version` INTEGER NOT NULL,
`horizon_truncated` INTEGER NOT NULL CHECK (`horizon_truncated` IN (0,1)),
`revoked_count` INTEGER NOT NULL DEFAULT 0,
`aged_out_count` INTEGER NOT NULL DEFAULT 0,
`rebuilt_at` INTEGER NOT NULL,
PRIMARY KEY (`repo_id`, `source_kind`)
);
8 changes: 8 additions & 0 deletions sql/migrations/2026092901_memory_core_down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- Memory core projection schema down (plan-20260926 DM-01 migration A).
--
-- `forward-only` (ADR-DM-13): this down is a controlled test/ops tool, not the
-- published rollback path. Drop in FK-reverse order (children before parents):
-- `memory_episode_evidence` references `memory_episode` and must be dropped first.
DROP TABLE IF EXISTS `memory_episode_evidence`;
DROP TABLE IF EXISTS `memory_episode`;
DROP TABLE IF EXISTS `memory_projection_state`;
2 changes: 2 additions & 0 deletions sql/migrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ helpers in `db.rs`. Subsequent CEXes have populated this directory.
| `2026090803` | `change_identity_prefix_index_repair` | `2026090803_change_identity_prefix_index_repair.sql` (CH-02 compatibility repair: adds the repository-scoped Change ID prefix index for databases that already recorded 0802 before that index was shipped; forward-only.) |
| `2026091801` | `operation_v1_retirement` | `2026091801_operation_v1_retirement.sql` (OL-15 forward-only retirement of the isolated legacy operation namespace after the v2 runtime cutover.) |
| `2026091802` | `operation_v2_dedup_index` | `2026091802_operation_v2_dedup_index.sql` (OL-15 follow-up repair for the v2 five-second duplicate-operation lookup.) |
| `2026092701` | `ai_task_run_base_commit_ref` | `2026090701_ai_task_run_base_commit_ref{,_down}.sql` (B3-16: additive nullable `base_commit_ref` on `ai_index_task_run`; the SQL filename keeps the #456-era `2026090701` while the registered version is `2026092701`, which must sit above the then-current tip `2026091901` so `run_pending` replays it.) |
| `2026092901` | `memory_core` | `2026092901_memory_core{,_down}.sql` (plan-20260926 DM-01 / migration A: zero-authority, rebuildable Episode projection schema — `memory_episode`, `memory_episode_evidence`, `memory_projection_state`; forward-only per ADR-DM-13; the `_down.sql` is a controlled test/ops tool, not the published rollback path.) |

All registered migrations are loaded via `include_str!`. New migrations must
follow the same pattern — inline SQL strings in `builtin_migrations()` are no
Expand Down
16 changes: 14 additions & 2 deletions src/internal/db/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1895,6 +1895,18 @@ pub(crate) fn repository_migrations() -> Vec<Migration> {
include_str!("../../../sql/migrations/2026090701_ai_task_run_base_commit_ref.sql"),
include_str!("../../../sql/migrations/2026090701_ai_task_run_base_commit_ref_down.sql"),
),
// plan-20260926 DM-01 (migration A): core Episode projection schema.
// Zero-authority, rebuildable side tables (GC-DM-01); forward-only
// (ADR-DM-13). `memory_episode` / `memory_episode_evidence` /
// `memory_projection_state`. Registered above the current tip (2026092701)
// so `run_pending` applies it; the `_down.sql` is a controlled test/ops
// tool, not the published rollback path.
sql_migration(
2026092901,
"memory_core",
include_str!("../../../sql/migrations/2026092901_memory_core.sql"),
include_str!("../../../sql/migrations/2026092901_memory_core_down.sql"),
),
]
}

Expand Down Expand Up @@ -2355,9 +2367,9 @@ mod tests {
// `builtin_migrations()` so silent registry regressions surface
// here in addition to `tests/db_migration_test.rs`.
let runner = builtin_runner().expect("CEX-12.5 builtin registry must build clean");
assert_eq!(runner.len(), 66);
assert_eq!(runner.len(), 67);
assert!(!runner.is_empty());
assert_eq!(runner.max_registered_version(), Some(2026092701));
assert_eq!(runner.max_registered_version(), Some(2026092901));
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions src/internal/mutable_state_ownership.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ pub const MIGRATION_ONLY_TABLES: &[&str] = &[
"legacy_operation_view_workspace__staging",
"layer__down_guard_2026072303",
"layer__legacy_rows_need_explicit_adopt_2026072303",
// plan-20260926 DM-01 projection tables (zero-authority, rebuildable;
// repository-scoped, not worktree-scoped => no MUTABLE_STATE_OWNERSHIP entry).
"memory_episode",
"memory_episode_evidence",
"memory_projection_state",
"operation__down_guard_2026073003",
"operation__down_guard_2026073004",
"operation_scope_provenance_down_guard",
Expand Down
2 changes: 1 addition & 1 deletion tests/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
| `compat_help_flag_descriptions` | 1 | Every visible flag and positional under `Options:` / `Arguments:` carries a non-empty description; covers 42 root commands + 53 sub/sub-sub-commands (110 surfaces) | `src/cli.rs`, `src/command/**` |
| `compat_help_no_impl_meta_leak` | 1 | No `libra <cmd> --help` body leaks contributor-facing rustdoc into clap's long_about; forbids 6 phrase classes (e.g. `Codex pass-`, raw markdown headings, code fences) | `src/cli.rs`, `src/command/**` |
| `verify_pack_multi_test` | 1 | Guards `verify-pack <idx>...` multi-index verification, JSON wrapping, and `--pack` argument rejection | `src/command/verify_pack*.rs` |
| `db_migration_test` | 1 | SQLite schema bootstrap + migration round-trip, including role-scoped manifests/ledgers, config-only bootstrap, future/Derived zero-write, atomic configuration upgrade failure, attested repair ledger-only preservation and test-upgrade-gated atomic rollback, 1,000-row no-value-read inspection, isolated global/system fixture restoration, M4 import identity/tombstone, M5 subagent content empty up→down→up, non-empty recovery-state rollback refusal, the §C.8 workspace-lease down guard (non-terminal rows refuse, settled rows roll back, live leases block deeper W3 rollbacks transitively), and uniqueness/state failure matrix | `src/internal/db.rs`, `src/internal/db/schema.rs`, `src/utils/test.rs`, `sql/` |
| `db_migration_test` | 1 | SQLite schema bootstrap + migration round-trip, including role-scoped manifests/ledgers, config-only bootstrap, future/Derived zero-write, atomic configuration upgrade failure, attested repair ledger-only preservation and test-upgrade-gated atomic rollback, 1,000-row no-value-read inspection, isolated global/system fixture restoration, M4 import identity/tombstone, M5 subagent content empty up→down→up, non-empty recovery-state rollback refusal, the §C.8 workspace-lease down guard (non-terminal rows refuse, settled rows roll back, live leases block deeper W3 rollbacks transitively), uniqueness/state failure matrix, and plan-20260926 DM-01 memory core projection schema (three-table creation, frozen column/CHECK/UNIQUE/PK/FK vocabulary, second-run no-op, FK-reverse down drops, Repository-role-only with untouched configuration ledgers) | `src/internal/db.rs`, `src/internal/db/schema.rs`, `src/utils/test.rs`, `sql/`, `sql/migrations/2026092901_memory_core{,_down}.sql` |
| `workspace_lease_test` | 1 | plan-20260714 §C.8 W4 workspace association/lease store: DB-arbitrated single winner per linked `(repo_id, worktree_id)` including a proven two-connection overlap (contender with a 50ms busy timeout must hit the uncommitted writer's lock, then lose to the index on retry) and failpoint-windowed takeovers (a parked doctor reports only the fence it wrote), canonical-path alias refusal (`.`/`..`, trailing separator, symlink, symlinked-parent `..` traversal, dangling-symlink parent) across kinds, repository identity resolved from `libra.repoid` (never the caller; padded/empty values refused as corrupt, write and read paths pinned to the same value, a rewrite with live rows fails closed) and cross-repository isolation, owner+monotonic-fence conditional renew/release/activate/abandon with stale-owner refusal (`LBR-AGENT-023`), no implicit steal of an expired lease, doctor reclaim only after expiry (`LBR-AGENT-022`) with successive cross-connection fence advancement and superseded-holder release refusal, provisioning→active publication (an `active` record requires an existing directory), released/orphaned identity release, foreign-identity recovery (bounded keyset listing plus adopt, with identity-drift refusals), bounded expired-lease sweep, keyset listing, and the association-IDs-only column pin | `src/internal/workspace.rs`, `sql/migrations/2026072501_workspace_record.sql` |
| `zeroize_buffers_test` | 1 | plan-20260921 GC-VG-01 / VG-03 G8: a scanning global allocator proves the imported GPG passphrase never survives in a freed heap block while the real CLI runs in-process; a calibration test fails if the detector is blind | `src/command/config.rs`, `src/internal/vault.rs` |

Expand Down
1 change: 1 addition & 0 deletions tests/SERIAL_REGISTRY.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -912,3 +912,4 @@ opencode_export_rejects_wrong_native_session_without_export_claim lane:opencode_
opencode_export_whole_session_idempotent lane:opencode_export_bridge shares environment and repository state with OpenCode export bridge integration tests
opencode_historical_import_e2e_uses_trusted_export_bytes lane:opencode_export_bridge shares environment and repository state with OpenCode export bridge integration tests
opencode_registered_failure_releases_dirty_job_claim_and_marker lane:opencode_export_bridge shares environment and repository state with OpenCode export bridge integration tests
memory_core_is_repository_role_only lane:env uses the shared config database fixture to prove DM-01 registers to Repository role only
Loading
Loading