Repository navigation
スプリント lflow2-5 - #2513
スプリント lflow2-5#2513
Conversation
- 使用量の行の組み立てを context_decisions.usage_call へ寄せ、read_calls と ledger_calls から使う(行 1・15) - read_calls から自動圧縮・最初の発言・呼び出しの登録を抜き出す(行 16) - 時刻の読み取りを clock.epoch へ寄せる(行 6)。正の整数の判定を context_policy.positive_int にする(行 17) - session_parts と report_work から区間・サブエージェント・帳簿・合算・数え上げを抜き出す(行 2・3) - 記録の行の組み立てを context_decisions.record_row へ寄せ、cmd_record と record_restart で共有する(行 21) - token_guard の試行方式の句を既存の定数で比べ、計画の案内の git の根を context_decisions.toplevel で取る(行 5・10) - 作業の報告・呼び出し・記録の行の現状固定テストを足す Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- upkeep_research: 時刻の読み取りを clock.epoch へ寄せ、run_research から持ち主の印と空きの待ちを抜き出す(行 6・7) - upkeep_depth: 「その深さを実行した」行の判定と最後の位置を 1 か所にし、diffs_since と _due_overhaul から使う(行 11) - upkeep_overhaul: count_types を型・部品・月ごとの数え上げに分ける。戻す辞書のキーと順は保つ(行 19) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- run_selection から、選べる課題が無いときの止まり方と、周回の行を作って記録する部分を抜き出す(行 18) - 直しの周回の印の現状固定テストを足す Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- aggregate_by_project から、利用者の発言 1 件のトリガーとヒットの数え上げを抜き出す(行 4。深さ 5 → 3) - 一緒に渡る 6 つの値を AgentReport にまとめ、emit_json と emit_markdown が受ける(行 14) - 数え上げと結果 JSON のキーの順の現状固定テストを足す Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
read_codex から、記録 1 本を 1 行ずつ読む部分と、呼び出しごとの値から使用量を組む部分を抜き出す(行 12)。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- clock.epoch を clock.epoch_seconds にする(lib/claude_usage.py の epoch と名前が衝突した) - context_policy.positive_int を is_positive_int にする(supervise_lib/new_args.py と名前が衝突した) - context_decisions.parse_ts を clock.epoch_seconds の別名にし、upkeep_research の _iso_epoch を消す(本体が同じだった) - read_calls と usage_call・record_row を詰め、context_decisions.py を 500 行に収める Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2422 を実装する(スプリント lflow2-5)
…resolve_policy 方針名の重ね合わせ(既定 < config < env < CLI と無視した環境変数)を _resolve_policy_name へ、 判断開始・運用上限・余白とその出所の重ね合わせを _resolve_thresholds へ抜き出す。 resolve_policy には環境変数と設定の読込み、sources の結合、AppliedPolicy の生成だけを残す。 sources のキーの順序・設定が空でないときの config の記録・current 時の margin・無効値の無視は変えない。 Item-Id: I-001 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pts/upkeep_research.py#research_items needs.usage の行を使える行と飛ばした側面に分ける部分を _usage_rows へ、 宣言の無い側面を補う末尾のループを _undeclared へ抜き出した。 research_items は抽出した 2 つと項目の追加だけを並べる形になる。項目と飛ばした側面の順は変えていない。 Item-Id: I-002 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kill-stats.py#agent_report agent_report が argparse の Namespace に args.limit_meta を書き込み、emit_json がそれを読んでいた隠れた依存をなくす。 AgentReport に limit_meta を加えて上限のメタデータを戻り値で返し(--agents 無効時は空の dict)、emit_json は report.limit_meta を使う。 Item-Id: I-003 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pts/upkeep_research.py#research_one 上限内か・出典があるかの合否の式を accepted として 1 回だけ計算し、 log_call へ渡す値と、記録を書かずに戻る分岐の両方でそれを使う。 否定形の式は元の式のド・モルガン変形で、振る舞いは変わらない。 Item-Id: I-004 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…#calibrate 較正の節(_median_of・_mark_times・_restore_sample・_handoff_sample・_stage_segments・ calibrate・calibrate_repo と CACHE_1H)を lib/context_calibrate.py へ移した。 会話の記録の全体を読む較正と、hook が使う記録の追記・小さな JSON の読み書きを別の モジュールに分ける。record_restart は循環を避けて関数の中で context_calibrate を読む。 context-policy.py の cmd_calibrate とテストの参照先を新しいモジュールへ変えた。 Item-Id: I-005 Impl-Runtime: claude Impl-Model: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
改修計画 — devbasex/ai-plugins #2513
改善項目I-001 —
|
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| long_method | extract_method | major | high | claude / codex / kiro | 採用 | 1 |
なぜ: 認知的複雑度 18・CC 12・分岐 12・34 文。既定 < config < env < CLI の重ね合わせが policy・margin・decide_from/limit で別々に書かれ、出所(sources)の更新と値の更新が絡み合う
手順: 1. setting・env・cli から方針名とその出所および ignored を返す関数を抽出する。
2. policy・setting・env・cli から閾値とその出所を返す関数を抽出する。各関数の引数は4個以内とする。
3. resolve_policy には環境変数と設定の読込み、sources の結合、AppliedPolicy の生成を残す。設定が空でないだけで config を記録する現在の条件、current 時の margin、無効値の無視も変えない。
4. test_context_policy.py の優先順位・無効な環境変数・上限による補正・壊れた設定のテストで AppliedPolicy と sources を確認する。
I-002 — plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#research_items
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| long_method | extract_method | major | high | claude / kiro / codex | 採用 | 1 |
なぜ: 認知的複雑度 30・分岐 11・37 行で対象範囲の本体の最大。needs.usage の aggregate_only の選別、needs/seeds/environment の項目化、method.* の派生という別々の段階が 1 関数に通しで並ぶ
手順: 1. needs.usage の行を (使える行, 飛ばした側面) に分ける部分を _usage_rows(needs) として抽出する
2. 宣言の無い側面を補う末尾のループを _undeclared(items, skipped) として抽出する
3. research_items は抽出した 2 つと項目の追加だけを並べる形にする
4. test_upkeep_depths.py・test_upkeep_depth_report.py の plan の項目の順と skipped_aspects を確かめるテストを通す
I-003 — plugins/ndf/skills/skill-stats/scripts/skill-stats.py#agent_report
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| hidden_dependency | change_signature | major | high | claude / codex | 採用 | 1 |
なぜ: agent_report が argparse の Namespace に args.limit_meta を書き込み、emit_json がそれを読む。戻り値の AgentReport を見ても割る候補の上限の出所が分からず、emit_json は agent_report を先に呼んだことを暗黙に前提にする
手順: 1. AgentReport に limit_meta のフィールドを加え、agent_report から上限のメタデータも明示的に返す。--agents 無効時は空のメタデータを返す。
2. args.limit_meta への代入を除き、emit_json は report.limit_meta を使う。
3. test_agents_report.py のメタデータのキー順・--window-limit・--agents 無効時のJSONを既存の期待値で確認し、報告を作る前後で入力 Namespace に属性が増えないことも確認する。
I-004 — plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#research_one
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| duplication | extract_method | major | high | claude / kiro | 採用 | 1 |
なぜ: 上限を超えたか・出典があるかの判定(got["ok"] and got["cost"] <= lim["item_usd"] and got["seconds"] <= lim["item_seconds"] and valid_record(got["data"]))が ok の計算と if not ... の両方に完全に重複して書かれている。片方だけ直すと記録に残す ok と実際に書く・書かないの判定が食い違う
手順: 1. 対象を通る test_upkeep_depths.py の run_research のテストが通ることを確認する
2. 合否の式を accepted = got["ok"] and ... として 1 回だけ計算し ok に束ねる
3. log_call へ渡す ok と、記録を書かずに return する分岐の両方でその 1 つの変数を使う
4. テストを実行する
I-005 — plugins/ndf/scripts/lib/context_decisions.py#calibrate
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| large_class | split_module | major | high | claude | 採用 | 1 |
なぜ: モジュールが判定の記録・見込みのファイル・窓と適用値の受け渡し・会話の記録の読み・較正の 5 つの理由で変わり、構造の検査の上限 500 行にちょうど達している(1 行も足せない)。較正(_median_of・_mark_times・_restore_sample・_handoff_sample・_stage_segments・calibrate・calibrate_repo)は会話の記録の全体を読む重い側で、hook が使う記録の追記と小さな JSON の読み書きと別の理由で変わる
手順: 1. 較正の節を lib/context_calibrate.py へ移す(context_decisions の read_decisions・sessions_of・attach_marks・read_calls・fill_work を import する)
2. record_restart の calibrate_repo の呼び出しは関数の中の import にして循環を避ける
3. context-policy.py の cmd_calibrate と、cd.calibrate を呼ぶテストの参照先を新しいモジュールへ変える
4. check-script-structure.py・check-ndf-contracts.py・test_context_policy_hook.py を通す
レビューで確かめるテストの差分: plugins/ndf/scripts/tests/test_context_policy_hook.py(機械で期待値が変わったか決まらなかった)
I-006 — plugins/ndf/skills/skill-stats/scripts/skill-stats.py#extract_triggers
| 兆候 | 手法 | 重要度 | 等級 | 提案元 | 状態 | コミット |
|---|---|---|---|---|---|---|
| long_method | extract_method | major | medium | claude / codex / kiro | 取り消し | 2 |
なぜ: 末尾の全角括弧から明示した語を取り出す処理と、宣言がない場合に本文から候補を拾う処理が同居する。両者は日本語の必須条件・ストップワード・件数上限・重複の扱いが異なり、一つのループ構造として理解しにくい。指定範囲のテストでは、この抽出自体の境界値を直接固定していない。
手順: 1. 両フィールドの宣言、末尾以外の括弧、日本語を含まない括弧、大小文字の重複、fallback の有効無効と10語境界を extract_triggers の現状固定テストにする。
2. 明示語の抽出とフォールバック候補の抽出を、それぞれ独立した関数へ移す。
3. extract_triggers は明示語を優先し、なければ include_fallback に従って呼び分ける。fallback 内の大文字小文字を区別する seen と最後の _dedupe_ci の順序を維持する。
4. 公開関数の戻り値の語順と explicit・fallback・none を変更前後で比較する。
取り消した理由: 静的解析 lint が plugins/ndf/skills/skill-stats/tests/test_skill_stats_wrappers.py で落ち、修正に使える時間の内に通らなかった
指標の測定
- 状態: written / 言語とツールの対応: 既定(.ndf/code-metrics.json は無い) / 所要: 51.2 秒(使えた時間 186 秒 / 上限 186 秒)
- 指標のファイル: /tmp/ndf-worktrees/devbasex--ai-plugins/rf2513/work/.cross_refactoring/code-metrics-rf2513.md
| 言語 | ツール | 版 | ランナー | ファイル | 秒 | 結果 |
|---|---|---|---|---|---|---|
| python | ruff-complexipy | ruff 0.16.9 / complexipy 8.0.1 | uvx | 281 | 1.1 | 測った |
| 重複: python | symilar | pylint 4.0.9 | uvx | 281 | 48.4 | 測った(2 箇所) |
時間の上限
| 値 | 中身 |
|---|---|
| 提案の枠の終わり(監視の上限 = 残り + 余裕) | 2026-11-04T23:40:35+00:00 |
| 改修計画の枠の終わり(同上) | 2026-11-04T23:46:47+00:00 |
| テストの追加の終わり = 実装の終わり − Σ(採っていて未検証の項目の実装の見積り) | 2026-11-04T23:46:56+00:00 |
| 実装の終わり = 最終ゲートの修正の打ち切り − バッファ − Σ(採っていて未検証の項目の検証の見積り) | 2026-11-04T23:47:49+00:00 |
| 直しの試行の打ち切り | 2026-11-05T00:01:19+00:00 |
| 想定最大時間の終わり H(子プロセスはすべてここまでに止まる) | 2026-11-05T00:18:17+00:00 |
| 確かめの開始の締め切り = H − 確かめの見込み(最終ゲート修正と打ち切りの後の取り消しもここまで) | 2026-11-05T00:02:55+00:00 |
| 確かめの見込み(秒。最終ゲートの確かめ 1 回。バッファの最終ゲートの全体テスト) | 922 |
| 最終ゲート修正 1 回の見込み(秒。バッファの final_fix。起動は今 + この値が確かめの開始の締め切り以前のときだけ) | 96 |
| 指標の測定の上限(秒。提案の枠の中から割く) | 186 |
| 着手前のテスト 1 回の上限(秒) | 4644 |
| 範囲テスト 1 回の上限(秒) | 2145 |
| 手元の全体テスト 1 回の上限(秒) | 4644 |
| CI の待ちの上限(秒) | 2766 |
| 余裕(秒。手順の上限と CLI の上限に足す) | 186 |
入力: 予算 62 分 / 全体テストの所要 w 1548.0(ci-steps) / 着手前の実測 x 714.7 / CI の壁時計 c 922.0 / 着手前のテストの所要の見込み s 1548.0(whole) / 戦略 local-scoped-ci-whole
無音の打ち切りは手順の監視の上限と同じ値である。項目ごとの期限は持たない(実装を止めるのは実装の終わりだけ)。
見送った提案
| 対象 | 兆候 | 理由 | 根拠(MVV) | 補足 |
|---|---|---|---|---|
plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#log_call |
duplication | rank | Value 7 / Value 8 | — |
plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#masked_usage |
duplication | rank | Value 7 / Value 8 | — |
plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#run_research |
long_method | rank | Value 7 | — |
plugins/ndf/skills/skill-stats/scripts/skill-stats.py#format_agents_markdown |
long_parameter_list | rank | Value 7 | — |
plugins/ndf/skills/skill-stats/scripts/skill-stats.py#layer_totals |
one_by_one_iteration | rank | Value 7 | — |
plugins/ndf/skills/skill-stats/scripts/skill-stats.py#main |
long_method | rank | Value 7 | — |
scripts/token-usage.py#Role |
feature_envy | rank | Value 7 | — |
scripts/token-usage.py#Usage.add |
duplication | rank | Value 7 | — |
scripts/token-usage.py#main |
magic_value | rank | Value 8 | — |
scripts/token-usage.py#read_claude |
long_method | rank | Value 7 | — |
scripts/token-usage.py#read_codex |
duplication | rank | Value 7 | — |
scripts/token-usage.py#scan_file |
long_method | rank | Value 7 | — |
plugins/ndf/skills/backlog-refinement/scripts/upkeep_research.py#research_items |
deep_nesting | duplicate | Value 7 / Value 1 / Value 5 | C-003 と同じ変更 |
plugins/ndf/scripts/lib/context_decisions.py#calibrate |
long_method | duplicate | Value 7 | C-012 と同じ変更 |
plugins/ndf/scripts/lib/sprint_loop_select.py#exclusion_reason |
long_method | duplicate | Value 7 | C-017 と同じ変更 |
scripts/token-usage.py#_codex_lines |
divergent_change | duplicate | Value 7 / Value 1 / Value 5 | C-021 と同じ変更 |
plugins/ndf/scripts/lib/context_decisions.py#calibrate |
divergent_change | budget | Value 7 / Value 1 / Value 5 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#exclusion_reason |
divergent_change | budget | Value 7 / Value 1 / Value 5 | 見積り 12.8 分が残りに入らない |
scripts/token-usage.py#_codex_lines |
long_method | budget | Value 7 | 見積り 12.8 分が残りに入らない |
scripts/token-usage.py#render_md |
long_method | budget | Value 1 / Value 7 / Value 2 / Value 5 | 見積り 13.9 分が残りに入らない |
plugins/ndf/scripts/hook_lib/token_guard.py#guard_context |
long_method | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/context-policy.py#session_parts |
duplication | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#_select_candidate_rows |
long_method | budget | Value 7 / Value 1 / Value 5 | 見積り 12.8 分が残りに入らない |
plugins/ndf/skills/skill-stats/scripts/skill-stats.py#aggregate_by_project |
data_clump | budget | Value 7 | 見積り 15.9 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#exclusion_reason |
conditional_chain | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/hook_lib/token_guard.py#_judge |
magic_value | budget | Value 8 | 見積り 13.6 分が残りに入らない |
plugins/ndf/scripts/lib/context_decisions.py#append_decision |
duplication | budget | Value 8 / Value 7 | 見積り 14.3 分が残りに入らない |
plugins/ndf/skills/backlog-refinement/scripts/upkeep_overhaul.py#count_types |
duplication | budget | Value 7 | 見積り 14.3 分が残りに入らない |
plugins/ndf/skills/skill-stats/scripts/skill-stats.py#extract_user_text |
duplication | budget | Value 7 | 見積り 15.3 分が残りに入らない |
scripts/token-usage.py#_scan_assistant |
data_clump | budget | Value 1 / Value 5 | 見積り 15.9 分が残りに入らない |
plugins/ndf/scripts/tests/test_release_approved_commit.py#run_release |
long_method | budget | Value 3 / Value 1 / Value 5 | 見積り 12.5 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#_select_candidate_rows |
duplication | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/hook_lib/token_guard.py#_config_notice |
duplication | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/hook_lib/token_guard.py#last_context |
duplication | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#run_selection |
duplication | budget | Value 7 | 見積り 12.8 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#_stop_without_issue |
one_by_one_iteration | budget | Value 7 | 見積り 12.9 分が残りに入らない |
plugins/ndf/scripts/tests/test_supervise_design_match.py#pr_repo |
duplication | budget | Value 7 | 見積り 13.1 分が残りに入らない |
plugins/ndf/scripts/tests/test_supervise_new.py#design_match fixture / pr create の偽の gh |
duplication | budget | Value 7 | 見積り 13.1 分が残りに入らない |
plugins/ndf/scripts/context-policy.py#_empty_totals |
magic_value | budget | Value 8 | 見積り 13.6 分が残りに入らない |
plugins/ndf/scripts/context-policy.py#_mark_bounds |
duplication | budget | Value 7 | 見積り 14.3 分が残りに入らない |
plugins/ndf/scripts/lib/context_policy.py#is_positive_int |
duplication | budget | Value 7 | 見積り 14.3 分が残りに入らない |
plugins/ndf/scripts/lib/sprint_loop_select.py#candidates_of |
duplication | budget | Value 7 | 見積り 14.3 分が残りに入らない |
plugins/ndf/scripts/lib/context_decisions.py#read_decisions |
duplication | budget | Value 7 | 見積り 15.3 分が残りに入らない |
plugins/ndf/scripts/context-policy.py#session_parts |
long_parameter_list | budget | Value 7 / Value 6 | 見積り 15.9 分が残りに入らない |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | codex | REQUEST_CHANGES
会話ログの全オブジェクト保持と追加走査を除き、較正・集計の処理量を従来の1回の走査に戻してください。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 1 | kiro | APPROVE
リファクタリング(抽出メソッド・モジュール分割・リネーム)の PR。17 ファイルを確認した。抽出・移動した関数はいずれも元の振る舞いに忠実で、現状固定のテストが parts・JSON キー順・記録の行・calibrate の標本・集計件数を留めている。リネーム(_positive_int→is_positive_int)と移動(calibrate/calibrate_repo→context_calibrate)はリポジトリ全体で一貫して適用され、古い呼び出しは残っていない。モジュール分割の逆参照は関数内 import でトップレベルの循環は無い。parse_ts=clock.epoch_seconds は実入力(文字列・naive→local)で等価。plan_hint の subprocess 置換は cd.toplevel が同じ git rev-parse を同じ 5 秒の timeout で 1 回だけ呼ぶため処理回数は増えない。critical / major の基準に当たる指摘は無い。
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🔧 /ndf:fix サマリ | round 1 | commit 2311b27対応件数: critical=0 / major=1 / minor=0(合計 1 件) |
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | claude | APPROVE
critical / major に当たる指摘は無い。round 1 の指摘(会話の記録の全行保持と追加の走査)は 2311b27 で 1 回の走査に戻っている。そのほかの抽出・移動・改名(resolve_policy の分割、research_items / research_one、agent_report の limit_meta、calibrate の context_calibrate への移動、parse_ts → clock.epoch_seconds、plan_hint → cd.toplevel、token-usage の _codex_lines / _codex_usage)は元の振る舞いと同じで、CLI の起動や git の呼び出しの回数も増えていない。
takemi-ohama
left a comment
There was a problem hiding this comment.
🤖 cross-review | round 2 | kiro | APPROVE
リファクタリング PR。round 1 で codex が指摘した会話ログの全オブジェクト保持と追加走査(context_decisions.py)は、_json_lines のジェネレータ化と read_calls の1回走査(2311b2779)で解消され、較正・集計の処理量は従来に戻っている。17 ファイルすべてを確認。critical / major の基準に当たる指摘は無い。
🔧 /ndf:fix サマリ | commit (なし)対応件数: critical=0 / major=0 / minor=0(合計 0 件) |
スプリント lflow2-5 の課題を develop へ取り込む。
利用者向けの変化
移行の手順
課題と設計
コミット
変更の統計
テスト(supervise.py の run のステップ)
集めた実装の PR
閉じる課題
Closes #2422
モード: standard / 通した工程: 実装 → Pull Request
🤖 Generated with Claude Code
24 行の判定と改修の前後(#2422 の受け入れ条件 1・4)
判定は設計文書(
issues/issue-2422-design.mdの「24 行の判定表」。確定仕様はdocs/specifications/ndf-script-shared-helpers.md)の写しである。改修する 17 行、採らない 7 行(8・9・13・20・22・23・24)で、採らない行には理由を 1 つずつ書いた。前の値は #2511 のマージの直前(
600c4bb16)、後の値はタグndf--v10.27.18で、astを使い設計文書と同じ方法で測った(測ったのはリリース後テスト #2521 (comment) )。後の値は長い関数・深い入れ子・データの塊の行だけに書く。context-policy.py#ledger_callscontext_decisions.usage_callへ寄せる(行 15 と同じ重複。決定 1)context-policy.py#report_workcontext-policy.py#session_partsskill-stats.py#aggregate_by_projecttoken_guard.py#_trial_cause"trial"・"容量"・"費用"を既存のcontext_policy.TRIAL・context_policy.REASON_CAPACITY・context_policy.REASON_COSTに置き換えるcontext_decisions.py#parse_tsclockの時刻の読み取りへ寄せ、同じ本体のupkeep_research.py#_iso_epochも寄せる(決定 2)upkeep_research.py#run_researchcontext-policy.py#IDLE_CAPplugins/の中に重複の相手が無い。相手は配布の外のscripts/token-usage.py:60だけ(要求の前提 3)upkeep_research.py#research_onetoken_guard.py#plan_hintcontext_decisions.toplevelの呼び出しに置き換える(context_decisionsは関数の中で import する)upkeep_depth.py#diffs_since_ran・_due_overhaulからも使うscripts/token-usage.py#read_codexupkeep_research.py#run_researchskill-stats.py#emit_jsonemit_markdownも同じ型を受けるcontext_decisions.py#read_callsusage_callを新しく作り、両方から使うcontext_decisions.py#read_callscontext_policy.py#_positive_intpositive_intにし、context_decisions.py#read_windowの同じ判定を置き換えるsprint_loop_select.py#run_selectionupkeep_overhaul.py#count_typesterminal.py#Terminalrelay_lib全体の約束で、同じ読み方が他に 12 か所ある。1 クラスだけ引数にすると揃いが崩れ、終了の待ちを生成の時点で読むと読む時刻が変わるcontext-policy.py#cmd_recordcutと再起動の付与)をcontext_decisions.pyの関数へ寄せ、record_restartと共有する。context-policy.py#cli_rowは消すcontext_decisions.py#append_decisioncontext_decisions.py#attach_marksreport_workは帳簿にあるセッションを除くなど意図して違うcontext_decisions.py#write_applied*.applied.jsonも書き込みの式から拾われる)