excavate は何をしますか?
レガシーリポジトリが自身について既に知っている情報を、最初の機能開発で手探りで進む前に復元します。出力はオフツリードシエ(ホットスポット、結合、復元された判断、誰に質問すべきかのマップ、さらに履歴が何を教えてくれ何を教えてくれなかったかを示すカバレッジブロック)と、docs/solutions/エントリのオプトインPR(/compoundのフォーマットに従い、/research、/write-a-prd、/executeが既に実行しているキーワードgrepで読み取れるようにします)です。
これを正直に保つための2つの原則があります。Tornhillの手法は、バージョン管理を行動記録として分析します。ホットスポットとは、変更頻度と複雑性の交点であり、どちらか一方の軸だけではなく、固定されたウィンドウに制限され、検査するための確率であり、行動に移すべき評決ではありません。そして、グラウンディングルール(references/visual-rendering-core.md § 1)はすべての成果物を分割します。SHA、PR番号、パス、カウント、引用された根拠はgitとghの出力からコピーされ、再入力されることはありません。モデルはその周辺の散文のみを記述します。「なぜ」がモデルの推測である判断は復元されたのではなく、発明されたものであり、リポジトリには含まれません。
呼び出し位置
サイドルート、ユーザー呼び出しのみ。 人間が/excavateと入力したときに起動します。disable-model-invocation: trueにより、その説明は他のすべてのセッションのコンテキストから除外されます。これはリポジトリごとにオンボーディング時に一度だけ入力され、自己トリガーする理由がないためです。計画モード、全行程で人間が関与(HITL)。無人実行(AFK)パスはありません。コミットに紐づくすべての項目は、人間がその根拠となる引用を読む必要があるためです。
これは独立したメッセージとして送信してください。新しいワークスペースの最初のメッセージとしては送信しないでください。ホストが前置きを追加する最初のメッセージに入力された隠しスキルは散文として読み込まれ、ロードされません。/lfgの呼び出し位置に、このフィールドインシデント(chrislacey89/skills#383)が記録されています。2番目のメッセージとして再入力してください。
/helpのStep 2に、このスキルから始めるための合図が記載されています。パイプラインが既に複合化しているリポジトリ(そこでは/compoundを実行してください)、誰かのパフォーマンスレビュー(§ 5参照)、または欠陥発見(/qaと/triage-issueが担当)には使用しないでください。
これはメインパイプラインと並行して動作し、/shapeで再接続します。最初の機能は、ドシエとエントリを手にして形作られます。トップのホットスポットが作業そのものである場合は/request-refactor-planに、履歴が修正ラベルの付いた未解決のクラスターを示している場合は/qaに引き継ぐこともあります。
メソッドルール
以下は、以下のプロセスが運用するルールです。それぞれがどこから来たのかを示しています。このファイル内の他の場所では再説明されません。
- リビジョン数でランク付けし、コード行数で評価せよ。どちらか一方の軸だけではない。 頻度だけをサイズなしに見ると設定ファイルをフラグ立てします。サイズだけを頻度なしに見ると、何年も前にデバッグされて正しくなり、その後一度も変更されていないコードをフラグ立てします(Tornhill、第1-4章)。
wc -lによるLOCは複雑性のプロキシです。clocは想定されておらず、LOCはこの本がデフォルトで使用するプロキシです。 - 固定されたウィンドウに制限せよ。 生のリビジョン数は、参照期間なしでは無意味です。12ヶ月がデフォルトです。高頻度のリポジトリでは短縮してください。実際のウィンドウを表示してください。
- 冪乗則を予期し、膝でカットせよ。 ごく一部のファイルにほとんどのコストが集中しています。曲線が横ばいになるところで止めてください。切りの良い数字で止めてはいけません。
- トレンドには複雑性とサイズが必要である。 悪化(Deteriorating)とはインデントの複雑性がLOCよりも速く上昇していることを意味します。リファクタリング済み(Refactored)とは両方が低下していることです。安定(Stable)とは両方が横ばいであることです(Tornhill、第5-6章)。LOCだけではこれらのラベルを導き出せません。
- 結合前に非ドメインファイルをフィルタリングせよ。報告前にすべての結合を分類せよ。 ロックファイル、マニフェスト、生成コード、ベンダーコードは誤検出です。テストがその対象に結合しているのは意図的であり、除外します。コピーペースト、サポートしない境界、プロデューサー・コンシューマー結合は保持し、ラベルを付けます(Tornhill、第8-9章)。スカッシュされた履歴はコミットレベルの結合を破壊します。PRレベルの変更セットを使用するか、そのセクションが利用できないと明記してください。
- ホットスポットは確率である。 メカニズムに名前を付ける前にファイルを開き、開かなかったファイルのエントリは提供しないでください。
- 所有権データの正当な使用法は4つある。 レビューアの発見、オンボーディング、テストの配置場所の決定、構造がチームに適しているかの判断。人をランク付けしたり評価したりするためには決して使用されず、
.mailmapを通じて読み取られ、ボットと初期インポートは除外されます(Tornhill、第12-14章)。 - 既存のドキュメントは理想像である。 ADR、README、CHANGELOGの主張は、現在のツリーと照合して検証された後、有効な判断として記録されます(Spinellis、『Code Reading』)。
- ホットスポットへの最初の動きは、ピンチポイントでの特性テストであり、リファクタリングではありません(Feathers、『Working Effectively with Legacy Code』)。ドシエの「Suggested first moves」セクションでは、ホットスポットごとにこのように記載されています。
- ホットスポットは極端であるために選択されるため、そのランクの一部はノイズである。 平均への回帰は帰無仮説です。あるウィンドウでトップだったファイルは、何もしなくても次のウィンドウでは平均的になる可能性があり、リファクタリング後に冷めたファイルは、何もしなくても冷めていたでしょう(Galton; Kahneman)。ウィンドウの両方の半分での持続性に基づいてランク付けし、各ホットスポットに
persistentまたはsingle-windowのタグを付け、持続的なものだけを最初の動きのリストに回します。ランキングは診断であり、決して目標ではありません。それに目標を設定するチームは、品質ではなくゲーミングを得ます(Goodhart)。 - 判断の隣に前提を記録せよ。 根拠は最も早く忘れられ、記録されていない前提は誰も変更しようとしない数字へと硬化します(Leveson、『Engineering a Safer World』、第10章)。復元された各判断は、その引用が示す制約(「YだからXを選択、Zを前提とした」)を伴い、Zがまだツリーに当てはまるかどうかが反転検出器となります。
- 判断エントリはADRの形状とコンプライアンスラインを持つ。 タイトル、ステータス、コンテキスト、なぜを含む判断、結果、そしてそれがどのように検証されるか。最後のものがなければ、記録は統治ではなく考古学になります(Richards & Ford、『Fundamentals of Software Architecture』、第19章)。ここでの検証は、現在のツリーに対して実行されるgrepまたはパスチェックです。
- ドシエは、専門知識の呪いの下にある新規参入者によって読まれる。 短い用語集と膝のホットスポットを先頭に置き、完全なテーブルはその後ろに隠し、最初の歓迎タスクはホットスポットの復元された判断を理解して要約することであり、修正することではありません(Hermans、『The Programmer's Brain』)。
プロセス
以下のフェンスで囲まれた各ブロックは、記述された通りに実行されます。各 Bash ツール呼び出しは新しいシェルであるため、変数は呼び出し間で保持されません。Step 0 の変数ブロックは一度実行されます。その後のブロックはすべての解決済みの値を $WORK/vars.sh に書き込みます。その後のすべてのシェル(あなたのものかマイナーのもの)は、Step 0 を再実行する代わりに . "$WORK/vars.sh" で始まります。Step 0 を再実行すると SINCE がデフォルトにリセットされ、--since や NONDOMAIN の拡張が破棄されるためです。ファイルをスキップしたシェルはエラーなしで失敗します。git log --since="" はコミットを返さず、grep -Ev "" は何も表示しません。空の出力は「リバートなし」という有効な回答として読み取られます。WORK はリポジトリから導出されたパスです。そのため、新しいシェルは Step 0 の WORK= 式でそれを再導出し、その配下のファイルをソースとして読み込みます。マイナーには、変数を継承するのではなく、ブリーフ内で vars.sh の絶対パスが渡されます。<path> は唯一のプレースホルダーであり、ホットスポットごとに置き換えられます。
フラグのセマンティクスはツール自身のドキュメントです(git-log、git-shortlog、git-rev-parse、gh pr list)。このファイルではそれらを言い換えません。scripts/test-documented-git-commands.sh は各 git ブロックを植えられたフィクスチャに対して実行するため、有効な呼び出しでなくなったブロックは CI で失敗します。
0. 事前確認
引数を解析します:--since <日付>(デフォルトは 12 months ago。git log --since が受け入れる任意の形式)および --paths <パススペック>...(以下のすべてのブロックの . を置き換えます)。次に、共有変数を設定します:
SINCE='12 months ago'
WORK="${TMPDIR:-/tmp}/excavate-$(git rev-parse --show-toplevel | cksum | cut -d' ' -f1)"
mkdir -p -m 700 "$WORK"
START=$(git log --since="$SINCE" --no-merges --format=%cs HEAD </dev/null | tail -1)
NONDOMAIN=(':(exclude)*.lock' ':(exclude)*package-lock.json' ':(exclude)*pnpm-lock.yaml' ':(exclude)*yarn.lock' ':(exclude)*.min.*' ':(exclude)*.snap' ':(exclude)*.generated.*' ':(exclude)CHANGELOG.md' ':(exclude)*/vendor/*' ':(exclude)*/node_modules/*')
BOTS='[[]bot[]]|dependabot|renovate'
MAXFILES=30
export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=core.quotePath GIT_CONFIG_VALUE_0=false
GIT_CONFIG_* のエクスポートは、この実行内のすべての git 呼び出しに対して core.quotePath=false を設定します(git-config, Environment 参照)。これにより、非ASCIIバイトを含むパスが、wc や以下の結合で開いたりマッチしたりできない引用符で囲まれたエスケープとしてではなく、それ自体として出力されます。
START はウィンドウ内の最初のコミット日付であり、git から導出されます。date からは導出されません。なぜなら date -d はGNU専用であり、date -v はBSD専用だからです。NONDOMAIN は開始リストです。Step 1 の前に、このリポジトリの生成、ベンダー、スナップショット、ミラーリングされたパスで拡張してください(疑わしいものについては git check-attr linguist-generated linguist-vendored を確認してください)。MAXFILES は変更セットサイズの上限であり、それを超えるコミットは一括スイープ(フォーマット変更、インポート、大量リネーム)として扱われ、頻度と結合のカウントから除外されます。Step 2 の共有ログは、ログが構築されるときに一度だけそれを適用します。後続のブロックはそれを繰り返しません。
WORK は HEAD ではなくリポジトリのトップレベルパスをキーとしています。これは Step 8 で HEAD がドキュメントブランチに移動するためです。これはシェル間で有効なままであり、Step 9 で削除されます。中断された実行からのディレクトリが既に存在する場合は、最初の Step 2 ブロックの前に削除してください。これにより、古いファイルがこの実行の出力として渡されるのを防ぎます。
NONDOMAIN が拡張されたら、解決済みの値を一度永続化します(Step 1 ゲートの後、ユーザーがウィンドウを変更した場合は再度行います。ファイルをソースとして読み込み、SINCE を設定し、Step 0 の START= 行を再実行し、その後このブロックを再実行します):
{
declare -p SINCE START NONDOMAIN BOTS MAXFILES WORK
declare -px GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0
} > "$WORK/vars.sh"
次に、. "$WORK/vars.sh" で始まるシェルでカバレッジを測定します:
git rev-parse --is-shallow-repository
git rev-list --count --since="$SINCE" --no-merges HEAD
git log --max-parents=0 --format=%cs HEAD </dev/null | sort | head -1
git log --since="$SINCE" --no-merges --format=%s HEAD </dev/null | awk '{ t++ } /\(#[0-9]+\)$/ { s++ } END { printf "%d of %d subjects end in (#N)\n", s, t }'
4行はそれぞれ、shallowかどうか、ウィンドウ内のコミット数、ルートコミットの日付(shallowの場合はshallowの境界なので「不明」と表示)、スカッシュ比率です。スカッシュ比率が高い場合は各コミットがPR全体であることを意味するため、コミットレベルの結合はすでにPRレベルの結合です。比率が低く、他の場所でスカッシュマージされたPRがある場合は、注意すべきケースです。
次に、すでにウィンドウ内にある変更をランディングするコミットをカウントします。これは、リリースブランチを通じて出荷するリポジトリは、同じ変更をオリジナル、チェリーピック、リリースまたは同期ロールアップとして持ち、以下のすべてのカウントは各コピーを個別のリビジョンとして見るためです:
git log --since="$SINCE" --no-merges --reverse -p --format='commit %H' HEAD -- . "${NONDOMAIN[@]}" </dev/null \
| git patch-id --stable | awk 'seen[$(1)]++ { print $(2) }' > "$WORK/dups.txt"
wc -l < "$WORK/dups.txt" | tr -d ' '
dups.txt は、そのパッチID (git-patch-id) が以前のウィンドウ内コミットによって既に持っていたすべてのコミットをリストします。そのため、最も古いコピーがリストから除外されるものです。これは、Step 2 の共有ログと同じウィンドウとパススペックを読み取るため、ランキングが読み取るコミットの中からコピーをカウントします。変更が既にメインライン上にあるマージされたブランチは、両方の git log の履歴単純化によってスキップされます。そのカウントはカバレッジブロックに入り、Step 3 はこれらのコミットなしで膝を再ランク付けします。これらはカウントされ、除外されません。再ランディングされた変更は依然として誰かが行った作業であり、ロールアップはそれが運ぶ変更の唯一の記録である可能性があり、以降のすべてのブロックは独自の git log または git rev-list を通じて履歴を読み取るため、共有ログにのみ適用されたフィルターはステップ間で不一致を生じさせます。スコープゲートでサブジェクトに表示されるリリースまたは同期ロールアップに名前を付けてください。これらも除外されません。
gh auth status とリモートがGitHubかどうかをプローブします。gh: yes または gh: no を記録します。ドシエディレクトリを bash "$SC" path research で解決します。ここで SC はこのスキルにバンドルされたリゾルバ、references/sidecar.sh のインストール済み絶対パスです。サイドカーのパスを自分で計算しないでください。SIDECAR MISS の場合、リゾルバは exit 1 で終了し、init コマンドを表示します。それをユーザーに表示し、ユーザーが実行するまで続行します。サイドカーの作成は人間の行為だからです。そのディレクトリ内に以前の excavation-*.md と既存の docs/solutions/ がないか確認します。再実行では、エントリを複製するのではなく更新し、以前のドシエの persistent タグを新しいウィンドウに対してスコアリングします(どの程度ホットな状態が続いているか)。これにより、カバレッジブロックは自身の予測に対するヒット率を保持します。
リポジトリがshallowの場合は、どの程度の履歴が欠落しているかを示し、git fetch --unshallow を提案します。.git を書き換えるため、決して実行しないでください。
1. スコープゲート (HITL)
カバレッジブロックを、ドシエの先頭に表示される通りの正確な形式で表示します:
Window: <START> → today (<SINCE>)
Commits: <N> non-merge (<M> excluded as bulk > MAXFILES files)
Shallow: yes | no
Squash ratio: <s>/<t>
Duplicates: <d> commits repeat an earlier commit's patch ID (counted, not excluded)
gh: yes (<fetched> of <total> merged PRs; <closed> closed unmerged) | no
Fix labels: <k> of <N> commits match the fix pattern (a lower bound; filled in at Step 3)
Excluded: <NONDOMAIN list, one line>
Not visible: closed-unmerged PRs, force-pushed or squashed history, deleted files, departed contributors
Not visible 行は定型文ではありません。以下はランクs...
(原文が途中で切れているため、以降の翻訳は不可能です。完全な原文を提供してください。)