update: memoryシステムの"Phase"表記を撤廃

This commit is contained in:
2026-05-11 01:55:28 +09:00
parent a8a6e049bc
commit a2aecbf029
34 changed files with 282 additions and 227 deletions
+7 -7
View File
@@ -333,7 +333,7 @@ async fn mid_turn_compact_success_broadcasts_start_and_done() {
}
/// Regression: `Pod::compact()` must reset the in-memory
/// `extract_pointer` so Phase 1 keeps firing on the new compacted
/// `extract_pointer` so extract keeps firing on the new compacted
/// session.
///
/// Without the reset, the pointer's `processed_through_history_len`
@@ -341,7 +341,7 @@ async fn mid_turn_compact_success_broadcasts_start_and_done() {
/// session starts with a much shorter history (`[summary, ...]`).
/// `cumulative_input_tokens_since` would then filter every new
/// usage record out (their `history_len` is below the stale pointer)
/// and Phase 1 would never re-fire for the rest of the process.
/// and extract would never re-fire for the rest of the process.
const EXTRACT_PLUS_COMPACT_MANIFEST: &str = r#"
[pod]
name = "test-pod"
@@ -385,7 +385,7 @@ fn write_extracted_tool_use_events(call_id: &str) -> Vec<LlmEvent> {
}
#[tokio::test]
async fn compact_resets_extract_pointer_so_phase1_can_fire_again() {
async fn compact_resets_extract_pointer_so_extract_can_fire_again() {
// Mock LLM responses, in call order:
// [0] first run with usage(1000) so extract threshold (=1) fires.
// [1] extract worker invokes write_extracted with empty payload.
@@ -403,7 +403,7 @@ async fn compact_resets_extract_pointer_so_phase1_can_fire_again() {
pod.run_text("first").await.unwrap();
// Phase 1 fires; pointer becomes Some.
// extract fires; pointer becomes Some.
pod.try_post_run_extract().await.unwrap();
assert!(
pod.extract_pointer().is_some(),
@@ -420,8 +420,8 @@ async fn compact_resets_extract_pointer_so_phase1_can_fire_again() {
}
/// `extract_threshold = 0` is treated as "disabled" — without this, a
/// raw `>=` comparison against `tokens_since` would fire Phase 1 on
/// every post-run regardless of activity. Mirrors the Phase 2
/// raw `>=` comparison against `tokens_since` would fire extract on
/// every post-run regardless of activity. Mirrors the consolidation
/// zero-threshold convention so users have a single way to opt out
/// without removing the `[memory]` section.
const EXTRACT_THRESHOLD_ZERO_MANIFEST: &str = r#"
@@ -446,7 +446,7 @@ permission = "write"
#[tokio::test]
async fn extract_threshold_zero_is_disabled() {
// Mock provides exactly one response — the first run. If Phase 1
// Mock provides exactly one response — the first run. If extract
// were treated as "fire on any change" because of `tokens_since >= 0`,
// it would call into the extract worker and exhaust the mock.
let client = MockClient::new(vec![text_events_with_usage("hi", 1000)]);
+6 -6
View File
@@ -1,4 +1,4 @@
//! Phase 2 (memory.consolidation) post-run trigger.
//! consolidation (memory.consolidation) post-run trigger.
//!
//! Covers the gating, lock and cleanup behaviour without exercising the
//! full sub-worker tool loop:
@@ -203,7 +203,7 @@ async fn no_thresholds_is_a_noop() {
let mut pod = make_pod_with(MEMORY_NO_THRESHOLDS_TOML, pwd.path().to_path_buf(), client).await;
pod.try_post_run_consolidate()
.await
.expect("phase 2 disabled when both thresholds are None");
.expect("consolidation disabled when both thresholds are None");
// No staging entries removed.
assert_eq!(memory::consolidate::list_staging_entries(&layout).len(), 5);
@@ -212,7 +212,7 @@ async fn no_thresholds_is_a_noop() {
#[tokio::test]
async fn zero_thresholds_treated_as_disabled() {
// Without the `Some(0) → None` collapse, `total_files >= 0` and
// `total_bytes >= 0` would always evaluate true and Phase 2 would
// `total_bytes >= 0` would always evaluate true and consolidation would
// fire on every post-run with any staging activity.
let pwd = tempfile::tempdir().unwrap();
let layout = WorkspaceLayout::new(pwd.path().to_path_buf());
@@ -265,7 +265,7 @@ async fn fires_on_threshold_and_cleans_up_consumed_entries() {
let layout = WorkspaceLayout::new(pwd.path().to_path_buf());
write_n_staging(&layout, 2); // threshold is 2 — fires.
// Sub-worker is given a single text-only response. The Phase 2 prompt
// Sub-worker is given a single text-only response. The consolidation prompt
// tells it to call memory tools; the mock skips those, but `Worker::run`
// returns Ok regardless once the LLM closes with a final text.
let client = MockClient::new(vec![done("ok")]);
@@ -343,7 +343,7 @@ async fn coalesce_loop_terminates_with_one_iteration_when_snapshot_drains_stagin
// Coalesce semantics from `docs/plan/memory.md` §並走防止: a single
// run consumes the snapshot taken at acquire time; the loop
// re-evaluates against any post-snapshot Phase 1 additions. With no
// re-evaluates against any post-snapshot extract additions. With no
// concurrent additions, the second iteration sees an empty staging
// and bails out — exercised here by counting LLM calls.
let pwd = tempfile::tempdir().unwrap();
@@ -380,7 +380,7 @@ async fn live_lock_held_by_other_pod_skips() {
write_n_staging(&layout, 3);
// Pre-acquire lock with this test's PID — definitely alive — and
// *don't* release it. The Phase 2 path must skip without error.
// *don't* release it. The consolidation path must skip without error.
let _live_lock = memory::consolidate::StagingLock::acquire(
&layout,
std::process::id(),