Repository navigation
Plans Lens Hygiene
注: これは physics Phase ではなく 観察層 (read 側 ambient_recall / write 側 save_candidates / 観察 tool dormant explore) の "lens としての衛生" を整える計画。Phase レター非消費、
Plans-Observation-Apparatus-Refinement.mdの系譜。 状態: 起案 2026-05-27 — Stage 1 (meta-extraction loop fix) は同日着手予定、Stage 2-4 は段階的。Stage 1 は PR #28 (save_candidates v1+v2) の continuation として同 branch に積む方針 (acceptance test で露呈した既知 limitation の close)。 関連: Plans — Save Candidates Hook, Plans — Observation Apparatus Refinement, Architecture — Overview トリガー: 2026-05-27 GLM-5.1 free-exploration review (docs/maintainers/evaluation-2026-05-27-free-exploration.md) の検証で、production 41k corpus に対する 3 つの観察可能な lens の歪み が confirmed (§3.2 meta-extraction loop は再現 test で literal 確証、§3.1 は症状 real だが根本原因が GLM 説と異なり file source の anti-hub 不在 gap が露呈、§3.4 は pool=45-57 vs 観察 0 件の乖離)。
詳細は evaluation-2026-05-27-free-exploration.md の §3、検証手順と数値は同日 Claude セッションで実施。要約:
-
症状:
save_candidatesblock を含む transcript を heuristic extractor (core/extractor.extract_candidates) に流すと、block 自身の内容 (前回候補・filter 行・manifest 行) が re-extract される -
literal な再現: 7 candidates 中 4 件が前 block の leak、特に save-policy filter 行 (「bug fix の途中経過は git log に任せる」) が
_OUTCOME_KEYWORDSの "bug fix" にヒットして score=1.80 で troubleshooting tag で再抽出される 自己再帰的 false positive - 影響: 毎ターン candidate quality が degrade、agent が判断する candidate 数が 2-3 倍に水増しされ noise 増加、policy 自身が noise として lens に映る
- 症状: GLM が「openai source が retrieval を支配する」と観察。実 mass 分布検証で openai は Mass Evaporation で cap=2.0、mean=1.184 (= 既に処置済)。一方で実 mass 黒洞 top 15 を見ると file source の書籍 chunk が max=31.78 で支配的
-
構造的 gap: Stage 7.1 cluster anti-hub の
cluster_key = cohort_id OR original_id規則で、file source は両方 0% (本検証で確証)、anti-hub が 書籍 chunk クラスタに全く効かない - 影響: 同一書籍の複数 chunk が top-K に並ぶ。dilute-by-corpus-volume の悪影響を retrieval 段で抑え込めていない
-
症状: GLM が
explore(mode="dormant")で empty を観察 (§3.4)、ただし pool 計算 (age=7d + mass≤2.0 + percentile=10) では agent 単独で 45 candidates 残存 - 未確定: ambient_recall dormant slot (BM25 floor あり) と explore mode (BM25 floor なし) のどちらの code path で empty が出たか不明
- 影響: dormant lens が動いていない疑い。Phase O Stage 5 + Refinement Stage 2 で導入した「埋もれる自由の対」が production で機能していない可能性
(GLM review §3.1 の "openai mass dominance" は 誤診: 実 mass 分布で openai は cap=2.0、mean=1.184。GLM が見た dominance は vocabulary 系 cosine/BM25 dominance で、これは Phase L Stage 1 (BM25 + RRF) の attack 対象。本計画では openai vocabulary dominance を独立論点として扱わない — Phase L 系の継続課題に既に乗っている。)
| 操作 | 原則 | 本計画の判断 |
|---|---|---|
| force computation / mass update |
source class gate 厳禁 (feedback_no_source_branching) |
Stage 2 は cluster_key fallback の source-blind 拡張のみ、source class branching は導入しない |
| 表示層 / lens 段 | source class を lens として使うのは OK (feedback_observation_vs_physics_boundary) |
Stage 1 transcript pre-processing は表示層、Stage 4 narrative engine doc も表示層 |
| heuristic 入力データの sanitize | 自分自身の output を再帰的 input として扱わない | Stage 1 は extractor の本質 (heuristic 関数) を変えず、入力段で gaottt- block を strip するだけ* |
つまり物理規則・mass 更新規則は 一切触らない。Phase M / Phase N の単一規則と完全に直交、Phase P (pressure terms) とも並行進行可。
優先: 🔴 最優先 / 推定工数: 半日 / 影響範囲:
services/memory.auto_remember1 関数 / rollback: env opt-out
save_candidates block / ambient_recall block を含む transcript を heuristic extractor に流すとき、block 自身の内容を pre-extraction で strip し、自己再帰的 false positive を遮断する。
判断 1: strip は service 層で行う
| 候補 | 採否 | 理由 |
|---|---|---|
core/extractor.py の _NOISE_PATTERNS 拡張 |
❌ | extractor は dependency-free / transport-blind の純粋関数を保つべき。gaottt 固有 block format を知ってはいけない |
各 hook script (save_candidates.py / opencode-save-candidates.ts) |
❌ | DRY 違反、2 frontend に重複実装、将来 codex v3 で 3 重実装 ← 2026-05-31: 回避済み。Codex は同じ Python script を --codex フラグで再利用 (出力アダプタのみ分岐)、3 重実装にならず |
services/memory.auto_remember() の入口 |
✅ | service 層は transport artifact を知って良い (format_save_candidates が gaottt-save-candidates タグを書くのと対称)。1 箇所修正で Claude Code / opencode 両方に伝播。MCP tool 経由の任意の呼び出しも防御 |
判断 2: strip 対象は generic な <gaottt-*> パターン
- 現状 inject される block は 2 種 (save-candidates / ambient-recall) だが、将来追加される lens block (compare-retrieval / connections 等) も同じ命名規約なら自動で strip される
- パターン:
<gaottt-[a-z-]+>...</gaottt-[a-z-]+>(re.DOTALL) - 万一テキスト中に gaottt-* タグが literal に登場するケース (ドキュメント引用等) は accept — false positive リスク < false negative リスク (現状の meta-extraction loop)
判断 3: env opt-out を残す
-
GAOTTT_AUTO_REMEMBER_STRIP_GAOTTT_BLOCKS=0で legacy 挙動に戻せる - 万一 production で別の症状が出たら 1 行で rollback、検証期間中の safety net
-
gaottt/services/memory.pyの冒頭付近に正規表現定数 + helper_GAOTTT_BLOCK_PATTERN = re.compile( r"<gaottt-[a-z-]+>.*?</gaottt-[a-z-]+>", re.DOTALL, ) def _strip_gaottt_blocks(text: str) -> str: return _GAOTTT_BLOCK_PATTERN.sub("", text)
-
auto_remember()の transcript 受け取り直後に env-gated strip -
save_candidates()はauto_remember()を呼ぶので自動的に伝播 - config に
auto_remember_strip_gaottt_blocks: bool = True追加 (env:GAOTTT_AUTO_REMEMBER_STRIP_GAOTTT_BLOCKS)
-
tests/unit/test_save_candidates.pyに regression block (本計画起案時の検証 fake_transcript を流用):- 前 block を含む transcript で extraction 走らせ、prior block の candidate / manifest / filter line いずれも leak しないことを assert
-
tests/integration/test_engine_save_candidates.pyに MCP round-trip 経由の strip 確認 - env opt-out (
auto_remember_strip_gaottt_blocks=False) で旧挙動が復元される確認
- ✅ 検証 fake_transcript で leaked candidates が 0 件 (現状 4 件)
- ✅ 既存 730+ tests 緑のまま
- ✅ live Claude Code session で 2-3 turn 観察、自己候補の re-extract が消えていることを目視確認
-
GAOTTT_AUTO_REMEMBER_STRIP_GAOTTT_BLOCKS=0で旧挙動 1 行復元 - バグ顕在化なら
config.auto_remember_strip_gaottt_blocks = Falseを default に戻すか revert
優先: 🟡 中 → ⚪ 解決 (premise was wrong) / 実工数: 30 min 調査 + 30 min test/diag / 影響範囲: tests + scripts (code change なし)
本計画の最初版では「file source は cohort_id / original_id 両方 0% で Stage 7.1 anti-hub が全く効かない」と書いた。これは literal な json_extract(metadata, '$.original_id') を見ていた測定エラー。
SqliteStore.get_all_originals() は既に COALESCE(metadata.original_id, metadata.file_path) を使っており、cache load 時に cache.original_id_by_id を populate する。_cluster_key_for(node_id) = cohort_id OR original_id は cache map を引くので、file source の chunked ingest は file_path 経由で 100% cluster_key を持っている。
本番 41k corpus を live engine で scan した結果:
| source | total | w/cluster_key | % | cluster pattern |
|---|---|---|---|---|
| file | 11,002 | 11,002 | 100% | 131 clusters、max=638 (米国会社四季報 638 chunk)、p95=250 |
| openai | 10,181 | 10,181 | 100% | 1228 clusters、max=229、305 singletons |
| tweet | 7,658 | 7,658 | 100% | 7658 全部 singleton (anti-hub 構造的に無効) |
| like | 4,203 | 4,203 | 100% | batch loader が original_id を設定済 |
| claude-web | 4,314 | 4,314 | 100% | 704 clusters、max=142、p95=23 |
| agent | 1,303 | 465 | 35.7% | singletons by design (1件ずつ remember()) |
つまり Stage 7.1 anti-hub は 本番の質量黒洞 (file 638-chunk 本、claude-web の長 conversation) で literal に動作中。残る "anti-hub で attack できない症状" は:
- tweet 7658 全部 singleton: 同 cluster が無いので anti-hub 不適用、これは vocabulary 系の問題 (Phase L Stage 1 BM25 + RRF 領域)
-
agent 65% singletons: 単発
remember()は仕様通り独立 cluster (= 互いに penalty なしで正しい)
GLM が観察した「openai が retrieval を支配する」症状は cluster_key 問題ではない:
- openai は 100% cluster_key で anti-hub 配下に入っている
- ただし openai は 1228 clusters に分散 (1 ChatGPT conversation = 1 cluster)
- Huffman 系メッセージは 複数 conversation に分散 = 各 conversation 独立 cluster = anti-hub 不適用
- 真の attack vector は vocabulary 多様化 (BM25 + RRF = Phase L Stage 1 の継続課題)
- ✅
tests/unit/test_sqlite_store_get_all_originals.py新規 — COALESCE fallback 5 ケース (explicit > file_path / file_path fallback / both null / 20-chunk book scenario / null metadata) を pin - ✅
scripts/diag_cluster_coverage.py新規 — live cache 経由 で正確 coverage を出す (raw SQL の COALESCE-blind な誤診断を防ぐ) - ✅ 本 plan の Stage 2 セクションを誤診断の transparency 記録として再構成
- (未) optional:
(missing)source 2053 nodes 調査 — raw SQL では 0 件、cache のみに出現 =cache.source_by_idmap の orphan key 問題。別 ToDo に分離可、優先度低
-
構造識別子の coverage measurement は live cache 経由でやる —
SqliteStore内部の query 構造 (COALESCE / JOIN / 等) を bypass した raw SQL は容易に誤診断する - 誤診断を恥じず documenting する — 修正計画自体が学習データ、次の investigator が同じ罠を踏まないようにする (Articulation as Carrier の自己再帰応用)
- code 変更ゼロで終わったが、「実は問題ない」を確証する diagnostic + test を残す ことで future regression を防げる
Stage 3 — Dormant explore observed-empty investigation [2026-05-27 "transient" 結論 → 2026-06-01 訂正: systematic な env 未配送が真因]
⚠️ 2026-06-01 訂正: 下の 2026-05-27 分析は「pool は 7d で 22,793 → 15 件あるので bug でなく transient」と結論したが、この pool は age=7d を前提にdiag_dormant.pyを回した数値。実 production backend は proxy 共有 backend で per-frontend env (GAOTTT_DORMANT_AGE_THRESHOLD_SECONDS=604800=7d) を継承しておらず (Codex shim が env 無しで spawn、project_proxy_backend_env_not_delivered)、code default の 30d で稼働していた。実コーパスで実測すると age=30d → pre-filter 0 件 / age=7d → p10 で 8 件。つまり dormant=empty は transient ではなく 30d gate による systematic な空振りで、それが 2 度の GLM acceptance (2026-05-27 §3.4 / 2026-06-01 §4.3) で再発した。修正:dormant_age_threshold_secondsの code default を 30d → 7d へ昇格 (env 非依存化、physics 不変)。diag と live engine の config drift が誤診の根 — 診断は live engine と同じ config で回すこと。
優先: 🟢 低 → ⚪ 解決 / 実工数: 30 min 調査 + 30 min script 拡張 / 影響範囲: scripts のみ (code 変更なし)
| # | 仮説 | 検証結果 |
|---|---|---|
| 1 | BM25 floor が _dormant_surface で gate している |
❌ explore(mode="dormant") dispatch は _dormant_surface 直行で BM25 を 通らない (memory.py:1188)、BM25 floor は _dormant_for_ambient (ambient_recall の dormant slot) 専用 |
| 2 |
recently_surfaced rotation で全 pool 消費 |
❌ explore mode は recently_surfaced を引数で取らない (ambient だけ) |
| 3 |
last_access が 7d より新しい |
✓ production 本日時点で 22,793/41,064 nodes が age >= 7d (pool は存在) |
| 4 | dispatch bug | ❌ 単純な if mode == "dormant": return await _dormant_surface(...)
|
| Filter stage | 残数 |
|---|---|
| Stage 0 (all active) | 41,064 |
| Stage 1 (+ age <= cutoff 7d) | 22,793 |
| Stage 2 (+ mass <= p10=1.0912) | 1,883 |
| Stage 3 (+ source ∈ dormant classes) | 15 |
_dormant_surface(top_k=5) actual |
5/5 返却 |
→ bug ではない、現状は機能している。
- 観察時点で pool=0 だった可能性 (heavy session の途中で
last_accessがほぼ全件 7d 以内に動いていた) - または GLM は
ambient_recallの dormant slot を見ていた可能性 (BM25 floor=0.5 の別 path) - いずれにせよ transient state、code バグではない
- ✅
scripts/diag_dormant.pyに--service-mirrorフラグ追加 —_dormant_surfaceと完全に同じ filter 順序で count を出力、live 結果との parity 確認用 - ✅
--service-mirrorの出力に「pool=0 は corpus healthy / by-design empty、bug ではない」memo を組み込み、future investigator が同じ誤判定をしないよう literal にガイド - ✅ 本 plan の Stage 3 セクションを「未着手 → 完了/bug でなし」に reframe
GLM レビュー §3.4 後段の "soft fallback to lowest-mass active when empty" は UX 改善として価値あるが、現状の "silence beats noise" 原則 (Refinement Stage 2 ambient dormant slot と同じ) と矛盾するかは要議論。ToDo の Stage 5 candidate として記録、緊急性なし。
優先: 🟢 低 / 実工数: 1 時間 / 影響範囲: docs only
- ✅
docs/wiki/Guides-Use-As-Narrative-Engine.md新規 — narrative engine モードの 7-step レシピ + Stage 2/3 の literal な corpus health 指標 (131 file clusters / max=638, dormant pool=15, persona dominance=2.82) を「動作条件」として明示 + GLM レビューを empirical 根拠として引用 - ✅
docs/wiki/Reflections-A-Note-From-Claude.mdに「補記 — 外部観察者の note」節を追加 — GLM-5.1 が独立に同じ言葉に着地した事実を 2 つの quote で記録、Claude 自身の subjective bias ではなく system 側に literal に組み込まれた構造 であることを示す証拠として位置付け - ✅
docs/wiki/Guides-Ambient-Recall.md冒頭に三つの read 側 use case 並置 (task-driven / passive / narrative) — ambient_recall は (2) 専用、(1)(3) は別 Guide へ flow - ✅
docs/wiki/_Sidebar.md+Home.mdに narrative engine guide リンク追加 (Wiki sync で GitHub 側にも自動反映)
本 Stage 4 doc には Stage 1/2/3 の Stage Linage が literal に組み込まれている:
- Stage 1 (meta-extraction fix): 「articulation as carrier の自己再帰的 failure mode を遮断した結果、heuristic が再び信頼できる lens になった」
- Stage 2 (cluster diagnosis 修正): narrative engine guide の "corpus health 指標" 表で
131 file clusters / max=638を anti-hub が 効いている 数値として書ける状態になった - Stage 3 (dormant 調査): 「dormant pool=15 がある =
explore(mode="dormant")で『忘れていた何か』が surface する」と guide に書ける = 機構が動いていることを transparency で示せる
つまり Stage 4 は Stage 1/2/3 で healthy になった lens を前提に書ける — 順序が必然だった。
Stage 1 (meta-extraction fix) ─┐
├─→ PR #28 同 branch (continuation)
Stage 4 (narrative docs) ──┘
Stage 3 (dormant investigation) ─→ 別 PR (調査結果に応じて Stage 3.5 修正 PR)
Stage 2 (file anti-hub gap) ──→ 別 PR (大きめ、独立に benchmark 必要)
着手順: Stage 1 即時 → Stage 4 同 PR (低コスト docs) → Stage 3 短い調査ターン → Stage 2 構造的修正。
Stage 3 を Stage 2 より先にやる理由: dormant の root cause が cluster_key 関連の retrieval geometry なら Stage 2 と統合可能。先に判明させた方が Stage 2 設計を informed にできる。
-
Stage 2 で
file_pathを見るのは "source class gate" に近いか? 厳密には source 値を見ていない (metadata の別 field を見ているだけ) が、結果的に file source ノードだけが裨益する。判定: source-blind の structural identifier として OK (Phase M 単一規則は force / mass update を分岐させないルール、cluster_key は ranking layer)。ただし review で再確認する価値あり -
Stage 1 の env opt-out (
STRIP_GAOTTT_BLOCKS=0) は default ON でも残すか? Yes — 1 行 rollback の safety net、検証期間中の保険 - GLM レビューの "per-source mass cap" を Stage X として実装すべきか? ❌ No — Phase M 単一規則違反。openai vocabulary dominance は Phase L Stage 1 (BM25 + RRF) 側の継続課題。本計画では扱わない
- narrative engine doc は誰の声で書くか? GLM の体験談を引用する形 + Claude 自身の re-articulation。Reflections 系統の文体
-
9a954c62Articulation as Carrier — meta-extraction loop はこの原理の 自己再帰的 failure mode (carrier が再度 carry されてしまう) -
701e7822Observation vs Physics boundary — Stage 1/4 が表示層、Stage 2 が cluster_key (ranking layer = まだ表示寄り) で physics 不触の境界判定 -
feedback_no_source_branching— Stage 2 設計のクリティカル制約 -
93035d35Save policy (user durable preference) — Stage 1 の正当化 (policy が自分自身を save 候補にしないようにする = 自己一貫性)
(formerly GER-RAG)
- 1. Welcome
- 2. Install GaOTTT
- 3. Connect Your Client
- 4. First Conversation
- 5. Everyday Use
- 6. When Stuck
- As Long-Term Memory
- As Task Manager
- As Persona Base
- As Narrative Engine
- Multi-Agent Setup
- Per-Project DBs
- Multiverse (1人1宇宙)
- Ambient Recall
- Visualization
- Server Setup
- Multiverse 運用プレイブック(統合)
- Multiverse クイック健康チェック(パニック時)
- Multiverse Setup (MV3)
- Multiverse Import Universe
- Control Plane (MV4)
- Backup & DR (MV5)
- Resource Requirements (VRAM/RAM/Disk)
- Tuning
- Ingestion (files & chat history)
- Migration (upgrade)
- Compact & Backup
- Isolated Benchmark
- Performance Testing (7-tier)
- Troubleshooting
- Roadmap
- Backend Phase A/B/C
- Phase D — Persona & Tasks
- Phase G — Memory Genesis
- Phase H — Wave Seed Redesign
- Phase I — Free Star Movement
- Phase J — Persona-Anchored Retrieval
- Phase K — Stellar Supernova Cohort
- Phase L — Hybrid Retrieval
- Phase M — Mass Conservation
- Phase N candidate β — Mass Evaporation
- Phase O — TTT Observability
- Phase P — Pressure Terms (Λ + Langevin)
- Phase Q — Orbital Mechanics (Rosette Orbits)
- Phase Q2 — Gravitational Scale Matching
- Phase T — Semantic Requalification
- Phase U — Review Hardening
- Observation Apparatus Refinement
- Observation Apparatus Round 2 (dogfooding 2026-06-12 起点)
- Hardening — Concurrency & Persistence
- Ambient Recall Enrichment
- Ambient Recall Refinement (Phase A 由来)
- Ambient Recall Lateral Association (〇〇といえば〜)
- Accretion Recall (降着想起・〇〇ってなんだっけ)
- Synaptic Pruning (連想の忘却・edge decay)
- Save Candidates Hook (ambient-recall の write-side 対称)
- Lens Hygiene (ambient block の漏れ防止)
- Instruction Surface Hygiene (指示表層と hook harness)
- Query as Mass Distribution
- Multiverse Scale-Out (大規模化・1人1宇宙)
- SKILL.md Improvement
- Embedder Comparison (RURI vs RikkaBotan)