tewip について
tewipはソフトウェア変更を検証する開発ツールです。テスト失敗やテストの有効性、データベース移行を分析し、根拠付きの判断を示します。決定的なルールを優先し、結論を出せない場合はその旨を明示します。
主な機能
- 01テスト失敗の原因を診断
- 02テストが失敗し得るかを確認
- 03コード変異でテストの検出力を検証
- 04移行によるデータベースへの影響を分析
- 05変更のリスクと完了度を評価
- 06判断の根拠と情報源を提示
活用シーン
- 01CIで失敗したテストを調査
- 02失敗を検出できないテストを特定
- 03本番データベースへの移行影響を評価
- 04コード変更とテストカバレッジを確認
MCP 対応
`tewip mcp`でMCPサーバーとして動作し、要件のテスト状況、過去の問題、次の対応をAIアシスタントから調べるための15個のツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y tewip-aiOPENAI_API_KEYシークレットOptional. Turns on the AI layer for failures the deterministic rules cannot decide. Without it only the rules run, and Tewip says which layer decided each answer.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
23掲載時のツール一覧 · 2 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| pr | integer | いいえ | プルリクエスト番号 |
| repo | string | はい | owner/name(例:hmamut39/triage-agent-sandbox) |
| branch | string | いいえ | PR がない場合のブランチ名 |
詳細
Tewip
Tewip(ウイグル語の téwip、تېۋىپ:治療者、医師)は、人間またはエージェントが行ったソフトウェア作業を検証するレイヤーです。
Mamuti Aishan(Hasan)(@hmamut39)が作成・メンテナンスしています。
失敗した各テストが失敗した理由(実際のバグ、不安定なテスト、環境、テストデータ、または変更されたセレクター)を特定し、そもそもテストが失敗する可能性があるかどうかを判定します。テストが気づくかどうかを確かめるためにコードを壊し、マイグレーションが稼働中のデータベースに何をするかを読み取り、変更が完了したかどうかを一つの判定で示します。すべての回答には根拠が添えられ、判定を行ったもの(決定論的なルール、AI モデル、または人による修正)が明示されます。
インストールする価値を生むのは、あえて言わないことです。推測する代わりに 「判断できません」 と回答し、安全に絞り込めると証明できないテスト実行は絞り込まず、すべてのレポートの末尾に確認しなかった内容を記載します。以下の各数値は、フィクスチャではなく、他者の実際のコードで測定したものです。
あらゆるスタックで動作します。Node.js(node:test、Jest、Vitest、Mocha)、Python(pytest、unittest)、Java と Kotlin(JUnit、TestNG)、Go、.NET、Ruby、PHP、Rust それぞれについて、実際のランナーのレポートと照合しています(全リスト)。さらに、Playwright ではトレース、セレクターのずれ、検証済みの修正を詳細に扱います。また、これらのランナー上で動くブラウザーおよびコンポーネントテストツール(Selenium、WebdriverIO、Cypress、React、Vue、Angular 向け Testing Library、Vue Test Utils、jest-dom、Jasmine)の失敗メッセージも読み取り、公開プロジェクトの実際のメッセージを500件以上使って検証しています。
| 場所 | 方法 |
|---|---|
| ターミナル | npm install -g tewip-ai を実行し、続けて tewip explain report.xml、tewip ci owner/repo --pr 12、tewip mcp を実行します |
| VS Code、Cursor、Windsurf、VSCodium | Tewip 拡張機能(ダウンロード):Tewip をエディターの AI アシスタントに登録し、6つのコマンドを追加します。レポートの説明、このブランチで CI が失敗した理由、変更のリスクレビュー、不安定なテストの隔離対象、セキュリティチェック、修正内容の総合評価を実行できます |
| JetBrains、Claude、その他の AI アシスタント | MCP サーバー tewip mcp を追加します。ここで以前にも同じことが起きましたか?、この要件はカバーされ、テストに合格していますか?、この目標に対して次に何をすべきですか? など、15個のツールを利用できます(エディターの設定を参照) |
| 任意のモデル(モデルなしも含む) | OpenAI、Claude、Gemini、Azure、または Ollama を使った自分のマシン上のモデルに対応します。アカウントやキーは不要で、ソースコードが外部に送信されることもありません:TEWIP_PROVIDER=ollama。Tewip の回答の4分の3は、モデルを一切呼び出しません。方法 |
| GitHub CI | Tewip Action:すべてのプルリクエストへのコメント、任意のマージゲート、検証済みの修正プルリクエスト(QUICKSTART) |
以前の名称は triage-agent です。リポジトリは hmamut39/tewip に移転し、GitHub が以前のアドレスからリダイレクトしています。計画については ROADMAP.md を参照してください。
状況:フェーズ1〜14は実装済みです。現在も進行中なのは、自動修正を行うフェーズ5と8です。 Tewip はあらゆるフレームワークから失敗を収集し、まずルールで診断し、ルールで判断できない場合にのみモデルを使います。そして、その結果を各役割に応じた作業に変換します。CI コメントとマージゲート、テスト計画と検証済みテスト、不安定なテストの詳細資料、PR リスクレビュー、セキュリティスキャン、Jira、Rally、GitHub Issues、Azure Boards、Linear のチケット、Figma デザインから生成したチェック、人向けに作成した仕様、そしてオプトインした場合に限り、証明できたときのみ行うテストコードまたはアプリケーションコードの修正です。GitHub CI で実際に動作し、MCP 経由で AI アシスタントからの質問に回答します。新規の実際の Gutenberg CI 失敗を対象に、ラベル付け前にパイプラインを固定して評価した正確度は93.4%です。6つの実データセット全体では86.1%〜99.7%で、留意事項は eval/README.md に記載しています。
CI ですでにカバレッジレポートを出力している場合は、Tewip にその場所を指定してください
Tewip はインポートをたどって、テストが何に到達するかを判断します。これは名前の一致ではなく、事実に基づく方法です。ただし、GraphQL クエリを送信するテスト、HTTP ルートにアクセスするテスト、コントローラーをレンダリングするテストは検出できません。
Django、Rails、Spring のコードベースでは、テストスイートの大部分がこれに当たるため、以前は tewip done が最も重要な質問に対して、「判断できません」 と答えていました。
カバレッジレポートがあれば判断できます。CI では、ほぼ間違いなくすでに出力されているでしょう。設定は不要です。
| 形式 | 出力元 | 検出場所 |
|---|---|---|
lcov.info | JavaScript、TypeScript、Rust、Go、C++ | coverage/lcov.info、lcov.info |
Cobertura coverage.xml | pytest-cov、coverlet (.NET)、simplecov | coverage.xml、coverage/coverage.xml |
| JaCoCo | Java、Kotlin | target/site/jacoco/jacoco.xml、build/reports/... |
| Clover | PHPUnit | clover.xml、build/logs/clover.xml |
レポートがあれば、done は推測をやめます。
### Is the changed code tested?
Yes: the suite executes saleor/graphql/utils/sorting.py.
_Decided by coverage.xml, which records what ran rather than what imports what._
反対の結論も、同じようにはっきり示します。「coverage.xml にありますが、どの行も実行されていないため、このコードはテストスイートで実行されません」 は、ためらいではなく 準備不足 という判定です。
カバレッジレポートでできないこと。 記録されるのは、テストスイート全体の実行中にどの行が実行されたかであり、どのテストが実行したかではありません。そのため、答えられるのは 「このコードはテストされているか」 であって、「ここを変更したら、どのテストがその影響を検知するか」 ではありません。tewip pick は引き続きインポートをもとに対象を絞り込み、ほかの部分に影響がないと示せない場合は絞り込みを拒否します。別のチェックアウトで作られたレポートは、鵜呑みにせず無視します。レポートに記載されたファイルがディスク上にない場合、Tewip は変更全体が未テストだと報告するのではなく、何も報告しません。
データを一切外部に出さずに実行する
病院、銀行、政府機関は通常、ソースコードをホスト型 API に送信できません。Tewip は、まさにそのような利用者を主な対象として作られています。Tewip は同じマシン上のモデルを使って実行できます。
# once
curl -fsSL https://ollama.com/install.sh | sh # or ollama.com for Windows and macOS
ollama pull qwen3:8b
# then
export TEWIP_PROVIDER=ollama
tewip done --diff main...HEAD
キーもアカウントも不要で、マシンの外部へのネットワーク通信もありません。TEWIP_BASE_URL を指定すると、同じパスを LM Studio、vLLM、llama.cpp のサーバー、または OpenAI 形式に対応するほかのものに向けられます。
変わること、変わらないこと。 決定論的なレイヤーである vouch、schema、access、perf、standards は、どのプロバイダーを使う場合でもモデルを呼び出すことはなく、影響を受けません。モデルを使うのは、失敗の説明、テストの作成、計画の立案など、判断を必要とする部分だけです。小規模なローカルモデルは、最先端のモデルと比べてこうした処理の精度が低くなります。Tewip はすべての回答について、どのレイヤーが判断したかを示すため、その違いが隠されずに分かります。
また、ローカルモデルは、指定されたスキーマに 準拠するよう制約されている 可能性も低くなります。リクエストを受け付けても、実際には制約を適用しないバックエンドもあります。Tewip は、Markdown のコードフェンス内や前置きの文の後に返された応答を読み取りますが、JSON がまったく含まれていない応答は引き続き拒否します。
費用
ほとんどの失敗は、モデルに届くことすらありません。公開プロジェクト 6 件における実際の CI 失敗 3,556 件では、決定論的なルールだけで 75.1% に回答しました。また、ラベル付きの失敗については 2,012 件中 1,979 件(98.4%) で正しく回答しました。ルールで回答できる失敗には費用がかからず、理由も明確で、毎回同じ回答になります。
残りの 4 分の 1 だけがモデルに送信されるため、実際の失敗 1,000 件 のトリアージにかかる費用は、gpt-5.4-mini の公表価格で約 $1.12 です。これは推定ではなく実測値です。保留していた失敗に対する、キャッシュされていない実際の呼び出し 3 回では、プロンプトトークンがそれぞれ 3,624、出力トークンがそれぞれ 499 で課金されました。実際の 1 週間分の費用はさらに低くなります。同じ失敗が繰り返されればキャッシュから回答され、修正済みの失敗が再びモデルに送られることはないためです。
Tewip は各コマンドの費用を表示し、自身の支出に上限を設けます。また、キーがなくても動作します。ルールだけで判定し、判断できないものは推測せず UNKNOWN のままにします。
まずはこちら
npm i -g tewip-ai
cd your-project
tewip
tewip は単独で実行すると、あなたのプロジェクトを調べ、実際のパスを含めた、状況を把握するのに役立つ2、3個のコマンドを提示します。また、ここでは答えられないことも率直に伝えます。ディレクトリを読み取って終了するだけです。何も実行せず、何も書き込まず、所要時間は約1秒です。
Here is what Tewip can tell you about **this** project, in the order worth doing.
**1. `tewip vouch`**
282 test files here (282 JavaScript or TypeScript). This reads them and names the ones
that cannot fail - no model, a second or two.
**2. `tewip schema --diff main...HEAD`**
165 migrations here (165 SQL). This says what a change would do to a live database
before it runs.
## What it will not do here
- No k6, JMeter or Lighthouse report was found. Tewip judges one you produce; it does
not run load tests itself.
以下はすべて、必要なときに参照できる全リストです。
プロジェクトで使う
チーム(または他社)に渡す場合:TEAM-GUIDE.md — インストールするもの、各役割での使い方、そして決して行わないことを説明しています。
実際のリポジトリに導入する場合:QUICKSTART.md — 10分でできる手順、コピー&ペーストできる内容、最初の実行で失敗したときに確認することを説明しています。
1. GitHub CI で使う(開発者、SDET、DevOps)
CI で blob レポートを書き出すよう Playwright に指示します。組み込みのレポーターなので、設定ファイルにトリアージエージェント用のコードを書く必要はありません。
// playwright.config.ts
reporter: process.env.CI ? [['list'], ['blob']] : 'list',
use: { trace: 'retain-on-failure' },
次に、テストの後にステップを1つ追加します。
permissions:
contents: write # only needed for autofix
pull-requests: write
issues: write
actions: read # lets it read the failed job's log when no test report was written
steps:
# ... checkout, install, npx playwright test ...
- name: triage-agent
if: always()
uses: hmamut39/tewip@main
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }} # optional: without it only the rules run
autofix: 'true' # optional: verified locator-fix PRs
CI で判定動詞を実行する(Phase 38、新機能)— 1つのステップで、必要なだけチェックできます。
- uses: hmamut39/tewip@main
with:
mode: check
checks: schema, access, vouch # or: done, standards, perf, or `all`
gate: blocking # optional: fail the job on what a verb calls blocking
前のチェックで問題が見つかっていても、すべてのチェックが実行されるため、プルリクエストの全体像を1回のプッシュで把握できます。ゲートは意図的にレポートよりも対象を絞っています。失敗するのは、動詞自体がブロッキングと判定するものだけです。アドバイスでゲートが作動すると、チームは continue-on-error を設定して通過させるようになってしまうためです。確認するものがないチェックはその旨を伝え、ジョブを失敗させません。差分にマイグレーションがないことは、合格を意味しません。
@mainまたはv0.46.0以降を使用してください。 それ以前のタグには、説明に引用符で囲まれていないコロンを含むaction.ymlが同梱されていました。YAML はこれをネストされたマッピングとして読み取るため、ランナーは "Failed to load action.yml" と応答し、アクションは実行されませんでした。この問題は修正済みで、再発を防ぐため、マニフェストを対象としたテストも追加されています。 実行のたびに、このアクションは次のことを行います。
- 開発者向け: プルリクエストに診断コメントを1件投稿し、最新の状態に保ちます。各失敗について、変更が原因である可能性、理由、次にすべきことを説明します。
- SDET向け: トリアージボードをジョブのサマリーに書き込みます。
- DevOps向け: 環境に起因する失敗(サーバーエラー、接続リセット、障害)を1件の GitHub issue に集約し、新しい実行のたびにグループ化したコメントを1件追加します。
- プルリクエスト内のテスト: PR では、変更によって触れられたテストファイルを読み取り、失敗し得ないテストを特定します。たとえば、未完成の期待値、自身の値との比較、自らの失敗を破棄するテスト、実行されないテストです。すべて問題がなければ何も報告しません。また、実行が成功していても報告します。テストが失敗し得ない場合、「すべてのテストに合格しました」という文言には正確な補足が必要だからです。差分を読み取れるよう、
actions/checkoutにfetch-depth: 0が必要です。設定されていない場合は、推測で報告せず、このセクションをスキップします。このようなテストはすべて、証明書にも判断拒否として記録されます。そのため、バンドルに基づくリリース判断が、何も証明しないテストに依存することはありません。 - 変更によって見逃される問題(
prove: true): プルリクエストで触れられたソースファイルに、意図的に小さな変更を加えてテストを実行し、どの変更も検知されなかったかを、該当する行とともに「このコードへの2つの変更は、テストをすり抜けていたでしょう」と報告します。変更のたびに実際のテスト実行が必要なため、デフォルトでは無効です。prove-budget(デフォルトは300秒)で処理全体の上限を設定し、確認できなかったファイルについては、問題がなかったかのように示すのではなく、そのファイル名を報告します。すべてのファイルは、変更前と完全に同じ状態に戻されます。検知されなかった変更もすべて、証明書に判断拒否として記録されます。何もチェックしていない行を、このバンドルが検証済みだと主張することはできません。 - 証拠、毎回の実行: アクションは証明書をアーティファクトに書き込みます。証明書には、主張とその証拠、各判断を下したレイヤー、Tewip が判断を拒否した内容、そしてまったく確認しなかった内容が記録されます。Tewip が自ら検証していない情報は一切記録されないため、CI を開かなくても、証明書に基づいてリリース判断を下せます。
- 修正(
autofix: true): 決定論的ルールが、名前の変わった要素に一致すると判定した古いロケーターを修正し、そのテストを再実行します。合格した変更を別のプルリクエストとして作成します。マージは行わず、アプリケーションコードも編集しません。 - すべての役割: すべての役割別ビューを
tewip-reportアーティファクトとしてアップロードします。 - テストが1つも実行される前にジョブが停止した場合(プルできないイメージ、ディスク容量切れのランナー、起動しなかったサービスコンテナーなど):失敗したジョブのログを読み取り、原因を特定します。説明のない赤い X を残しません。
- 履歴: 実行履歴を Actions キャッシュに保持し、git には保存しません。
- 訂正: エージェントのコメントに
/triage CATEGORY #n reason(例:/triage TIMING #2 flaky on CI)と返信してください。その返信は履歴に保存され、次回そのテストが同じ理由で失敗したときには、エージェント自身の判断ではなく、回答者と理由を示してその内容を使います。訂正済みの失敗にはコストがかかりません。モデルに再度問い合わせることはありません。
シニアエンジニア、アーキテクト、リード向けには、たとえば毎週実行する mode: report のスケジュール済みワークフローを追加してください。保存された CI 履歴から、エンジニアリング品質、アーキテクチャ、リスクダイジェストの各ビューを作成します。過去の診断を再利用するため、AI への問い合わせを繰り返しません。各レポートで更新される1件の GitHub issue に、これらのビューをまとめて保持します。
on:
schedule: [{ cron: '0 6 * * 1' }]
workflow_dispatch:
permissions: { contents: read, issues: write }
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: hmamut39/tewip@main
with: { mode: report }
レポートは、実行ブランチの履歴キャッシュを読み取ります。通常はデフォルトブランチです。 修正 PR のために、リポジトリで「Allow GitHub Actions to create and approve pull requests」を有効にする必要があります。ワークフロートークンで作成されたプルリクエストは、それ自体では CI を起動しません。エージェントは、PR を作成する前にテストを再実行して各変更を検証しました。まず非公開の練習用リポジトリで最初から最後まで実証したため、ここにはクリックできるリンクがありません。このリポジトリが非公開の場合、ほかのリポジトリからこのアクションを利用するには、Settings → Actions → Access で許可する必要があります。
Claude Code プラグインとして(アカウントもマーケットプレイスの承認も不要)
claude plugin marketplace add hmamut39/tewip-plugin
claude plugin install tewip@tewip
公開の手順はこれで全部です。マーケットプレイスとは、Git リポジトリ内の .claude-plugin/marketplace.json ファイルのことです。そのため、Tewip は hmamut39/tewip-plugin で公開しています。誰かの承認を得る必要はなく、費用もかかりません。このリポジトリにはプラグインだけが含まれています。つまり、マニフェスト、3 つのスキル、npm パッケージへのポインターだけなので、このリポジトリは非公開のままにできます。このプラグインには、Tewip の MCP サーバーと、Claude Code に使うタイミングを指示する 3 つのスキルが含まれています。変更が完了したと宣言する前、テストが失敗したとき、変更がマイグレーションに触れるときに使用します。スキルが実際に必要になるまでは、セッションあたり約 410 トークンを消費します。
MCP サーバーは公開済みパッケージ(npx -y tewip-ai@latest mcp)から実行されるため、プラグインは小さいままで、常に最新バージョンを利用できます。
エディター拡張機能(VS Code、Cursor、Windsurf、VSCodium)
拡張機能ペインを開き、「Tewip」を検索してください。 どちらのレジストリにも登録されているため、VS Code、Cursor、Windsurf、VSCodium、Gitpod、Eclipse Theia で利用できます。
- VS Code — Visual Studio Marketplace
- Cursor、Windsurf、VSCodium、Gitpod、Theia — Open VSX
または、任意のリリースに添付されている .vsix を Extensions: Install from VSIX… でインストールしてください。どちらの方法でも、コマンドラインが必要です。npm install -g tewip-ai
Ctrl+Shift+P を押して「Tewip」と入力すると、この作業は完了していますか?、誰でもこれを使えますか?、これらのテストが失敗する可能性はありますか?、このファイルのバグをテストで検出できますか?、この変更に気づく可能性のあるテストはどれですか?、このマイグレーションは稼働中のデータベースに何をしますか?、このブランチで CI が失敗したのはなぜですか? などを実行できます。エディターの AI アシスタントも、設定不要で Tewip を MCP サーバーとして認識します。
2. 任意の AI アシスタントから MCP 経由で(IT チーム全体で)
mcp/server.ts は読み取り専用の Model Context Protocol サーバーです。チームの誰もが、使い慣れたエディターやチャットから、自分のアシスタントにテストの失敗について尋ねられます。
| アシスタントへの質問 | 使用するツール |
|---|---|
| "our-org/web の PR 12 で CI が失敗したのはなぜですか?" | github_ci_report:その PR の最新の CI レポートと、検証済みの修正 PR があればその情報 |
| "失敗したチェックアウトのテストについて説明してください" | explain_failure:根本原因、確信度、根拠、このコミットと他のコミットでの履歴、次のアクション |
| "直近の実行結果から、最初に何を修正すべきですか?" | triage_board(SDET)・pr_impact(開発者) |
| "テスト環境に問題がありますか?" | environment_report(DevOps/SRE) |
| "リリースできますか?" | release_readiness(ビジネス/UAT) |
| "テストスイートの脆弱な箇所はどこですか?" | quality_report(シニア/プリンシパル)・architecture_report(アーキテクト)・risk_digest(リード) |
| "C:\work\shop のチェックアウト機能のテスト計画を書いてください" | test_plan:そのプロジェクトのテスト、コード、ページに基づいたリスクとシナリオを作成し、.tewip フォルダーに保存します |
npm install の実行後にセットアップします。
- このリポジトリの Claude Code: .mcp.json はすでに用意されているため、確認を求められたら
tewipを許可してください。それ以外の場所からは、インストール済みの場合はclaude mcp add tewip -- tewip mcpを、チェックアウトからの場合はclaude mcp add tewip -- node /path/to/tewip/mcp/server.tsを実行します。 - Claude Desktop、Cursor、VS Code、その他の MCP クライアント: コマンドを
tewip、引数を["mcp"]にした stdio サーバーを追加します。または、チェックアウトからの場合は、コマンドをnode、引数を["/path/to/tewip/mcp/server.ts"]にします。
github_ci_report は、お使いのマシンでの gh CLI のログイン情報を使用します。その他のツールは data/ 以下のデータセットを読み込み、AI レイヤーは .env の OPENAI_API_KEY を使用します。
エディターから使用する(MCP に対応する任意の IDE)
VS Code、Cursor、Windsurf、VSCodium: Tewip 拡張機能(extensions/vscode。tewip-<version>.vsix としてパッケージ化されています)をインストールします。Extensions → … → Install from VSIX を選択してください。拡張機能が Tewip を MCP サーバーとして自動登録するため、設定なしでアシスタントが使用できます。また、2 つのコマンド Tewip: Explain a test report… と Tewip: Why did CI fail on this branch? が追加されます。
その他すべての MCP クライアント(JetBrains IDEs 2025.2+、Claude Code、Claude Desktop、または拡張機能のないエディター)では、設定項目を 1 つ追加します。Tewip のリリースファイルからインストールした場合(npm install -g tewip-<version>.tgz)、コマンドは tewip mcp です。チェックアウトからの場合は、cli/tewip.ts を指定します。
このチェックアウトを指すよう、絶対パスを設定してください(サーバーは自身のデータを解決するため、エディターの作業ディレクトリは関係ありません)。VS Code は servers キーと type を使う独自の形式です。ワークスペースの .vscode/mcp.json に設定するか、ユーザーレベルの設定(コマンド MCP: Open User Configuration)に設定すると、すべてのウィンドウで使用できます。
{
"servers": {
"tewip": { "type": "stdio", "command": "tewip", "args": ["mcp"] }
}
}
Cursor、Claude Desktop、Windsurf、その他ほとんどのクライアントは mcpServers 形式を使用します(Cursor:Settings → MCP)。
{
"mcpServers": {
"tewip": { "command": "tewip", "args": ["mcp"] }
}
}
- JetBrains(IntelliJ、WebStorm、PyCharm 2025.2+):Settings → Tools → MCP Server。
- このリポジトリ内: Claude Code では何も必要ありません。
.mcp.jsonはすでに設定されています。
その後、自然な言葉で "why did CI fail on my PR?"、"which tests are flaky in checkout?"、"is the main branch safe to release?" などと尋ねてください。また、"write a test plan for the checkout feature in C:\work\shop" と依頼することもできます。test_plan ツールは、そのプロジェクトの実際のテスト、コード、ページに基づいて計画を作成し、.tewip フォルダーに保存します。その他のツールはすべて読み取り専用です。また、github_ci_report は Action がアップロードしたレポートを読み込むため、リポジトリをクローンしたり Actions ページを開いたりせずに、リポジトリの CI について尋ねられます(お使いの gh ログイン情報を使用します)。
テストを計画して作成する(フェーズ 6 と 7、新機能)
プロジェクト内で以下を実行してください。どちらも OPENAI_API_KEY が必要で、費用も表示されます。
tewip plan "Checkout: a signed-in shopper pays by card and gets a receipt" --url http://localhost:3000/checkout
tewip write # tests for the plan's "to automate next" scenarios
tewip write --only CO-002,CO-004 --framework pytest
tewip planは実際の内容を読み取ります。既存のテスト(言語は問いません)、変更内容(--diff main...HEAD)、実際のページ(Playwright 経由で各ページのユーザーに見える内容)、そしてこのプロジェクトで Tewip がこれまでに診断した失敗です。計画にはリスクとシナリオが優先度順に記載されます。シナリオが「すでにカバーされている」という主張は、実際のテスト名と照合され、そのようなテストがなければ除外されます。レビュー用の Markdown と、write用の JSON として.tewip/plans/に保存されます。- 計画は実際のバグを見つけられますか? 後に何かを壊したことが判明した実際のプルリクエスト 18 件で測定しました。リポジトリはプルリクエストの作成時の HEAD で取得され、レビュアーが見た差分から計画が作成され、バグについての情報は一切与えられていません。判定可能だった 9 組のうち 8 組で、シナリオがバグを特定しました。
matrix-org/complement、NLnetLabs/domain、Bioconductor/rhdf5、Try/OpenGothicなどが該当します。あるプルリクエストのタイトルは「夜間ビルドの警告を解消」でしたが、計画はその中に隠れていた動作変更も見つけました。注意点もあり、ROADMAP.md に記載されています。判定対象の 9 組はサンプルとして少なく、各プロジェクトのエンジニアではなく Claude が判定したこと、そして見逃した 1 件こそ興味深い事例であることです。プルリクエストの 意図 が間違っている場合、その意図に基づいた計画もそれに同意してしまいます。 tewip writeは、シナリオをお使いのフレームワークとスタイルに合わせたテストとして作成します。Playwright、Cypress、WebdriverIO、Angular、Jest、Vitest、pytest(Selenium または Playwright を使用)、Maven または Gradle 上の JUnit(Selenium、Spring Boot)、.NET、Go に対応しています。既存のテストのスタイルを踏襲し、実際のページで確認できた要素だけを使用します。フロントエンドアプリでは、既存のテストの書き方に沿ってコンポーネントテストを作成します。Jest または Vitest 上の Testing Library を使う React、Vue、Svelte のほか、ng testを使う Angular(Karma と Jasmine、または Vitest)に対応しています。e2e テストとユニットテストの両方があるプロジェクトでは、計画でページを読み取った場合はブラウザーテストを、読み取らなかった場合はユニットテストまたはコンポーネントテストを作成します。その後、テストを実行します。ドラフトは、すべての実行(デフォルトでは 3 回)に合格し、かつ主要なチェックを意図的に壊したときに一度は失敗した場合に限って残されます。失敗できないテストは、テストがないよりも悪いためです。失敗したドラフトは実際のエラーに基づいて修正されます。修正は最大 2 回です。テストが正しく見えるのにアプリが別の動作をした場合、Tewip は合格するまでテストを弱めるのではなく、バグの可能性があると報告します。残されたテストは新しいファイルとして既存のテストの隣に置かれ、レビューしてコミットできます。コミットは行われず、アプリケーションコードにも手を加えません。
デザインとページを照合する(フェーズ 11、新機能)
tewip design "https://www.figma.com/design/KEY/Checkout?node-id=12-34" --url http://localhost:3000/checkout
tewip design frame.json --frame "Sign in" # a saved frame, no Figma token needed
Tewip はデザインデータ(Figma の REST API、読み取り専用、TEWIP_FIGMA_TOKEN)と実行中のページ(アクセシビリティスナップショット。スクリーンリーダーとテストの両方が参照するもの)を読み取り、相違点を報告します。例:the design says button "Sign in", the page says button "Log in"。デザインで指定された文言、レイヤー名から推定されるコントロール、セクションから推定される領域を確認します。デザインツールとブラウザーでは測定方法が異なるため、ピクセル、色、間隔は確認しません。モデルは呼び出されないため、費用はかからず、毎回同じ結果が得られます。
実際のデザインとページの組み合わせ 4 件(公開リポジトリの Figma エクスポートと、そこから構築されたページ)で測定しました。38 件のチェックを行い、デザインと一致するページでの相違点の報告は 0 件、実際の差異 11 件のうち 11 件を検出しました(コントロール名の変更、文の削除、文中の単語の置き換え、マークアップが失われた領域)。また、無害な変更 5 件のうち 5 件を無視しました(大文字と小文字、余分なスペース、リンクとして実装されたボタン、セクションの並べ替え)。まだデザイナーによる出力の評価は行われていないため、ロードマップに記載されている指標は未確定です。
対応ランナーの追加:Robot Framework、JMeter、k6(新機能)
Tewip は、JUnit XML、TRX、NUnit、Playwright 独自のレポートに加えて、Robot Framework の output.xml、JMeter の .jtl、k6 のサマリーも読み取れるようになりました。負荷テストはテストごとに失敗するわけではないため、JMeter のレポートはリクエストごとに 1 行(「5 件中 4 件のリクエストが失敗し、アサーションも失敗しました」)になり、k6 の実行結果は、しきい値を超えた項目ごとに、そのしきい値を超えた数値とともに 1 件の記録になります。
Appium と Selenium にはインポーターは必要ありません。これらのテストスイートは Mocha、pytest、JUnit を通じてレポートを出力し、Tewip はすでにそれらを読み取れます。また、「接続されたデバイスが見つかりません」「stale element reference」といった独自のエラーメッセージもすでに認識します。
各リーダーは、公開リポジトリで公開されている実際のレポートを使って検証しました。その結果、リリース前に 3 つの不具合を発見しました。日付ではない Robot のタイムスタンプ、values の中に格納されている k6 の数値、そしてアサーションが失敗したのに「ほとんど 200」と表示する JMeter の行です。
誤りを伝える(新機能)
tewip correct diagnosis "checkout charges twice" TEST_DATA "the fixture has stale prices"
tewip correct flaky "adds an item" fix-now "it is a real race, not flakiness"
tewip correct security "src/config.ts:12" noise "that is a sample key in a fixture"
tewip correct --list
Tewip は以後、あなたの判断に基づいて回答し、それがあなたによるものだと明示します。「TEST_DATA、信頼度 1.00、情報源:人による修正」。修正内容はプロジェクトに保存されるため、チーム全体で共有されます。最新の修正が優先されるので、考えが変わったときは、もう一度伝えるだけです。
**修正によって変わるのは Tewip の回答であり、Tewip が独自に行う動作ではありません。**修正を伝えても、コードの変更、テストの隔離、チケットの起票は行いません。
修正の集計結果(新機能)
tewip learn # where Tewip is systematically wrong, from what you corrected
tewip learn --labels labels.jsonl # your corrections as labelled examples, to measure a change against
修正 1 件で失敗 1 件を直せます。20 件の修正があれば、どのルールを変更すべきかがわかります。tewip learn はそれらをグループ化し、「45 件は REAL_BUG と判定されましたが、あなたは TIMING と回答しました。ルール locator-drift がそのうち 27 件を判定しました。対象は 11 件の異なるテストです」と示し、確認すべきルールと、その下に実際の失敗例 3 件を表示します。
Tewip は誇張しません。同じパターンへの修正が 3 件未満の場合は、結論ではなく「まだパターンではありません」と示します。グループの原因となるルールが 1 つもない場合は、1 つのルールを責めるのではなく、ルールが不足していると伝えます。また、パターンが何件の異なるテストから生じたのかも示します。同じ不安定なテストを 6 回修正しても、証拠は 6 件ではなく 1 件だからです。
機能を作るときは、まずテストから(新機能)
tewip build "naturalsize should take a sep argument that goes between the number and the unit"
tewip build --issue PROJ-123 # build from the ticket's own description and acceptance criteria
tewip build "..." --pr # commit the proved work on its own branch, open a draft PR
tewip build "..." --dry-run # prove it, show the patch, leave nothing on disk
Tewip はまずテストを書き、それを実行します。**そのテストが合格した場合は、そこで停止し、何も残しません。**機能がまだ存在しないのに合格するテストは、何も検証していないからです。次に、テストを合格させる最小限のコードを書き、新しいテストが合格し、かつ、合格していたテストに失敗が発生していない場合に限って、その変更を保持します。それ以外の場合は、作成したテストも含め、すべてのファイルを 1 バイトも違わない状態に戻します。コミットは一切行いません。
公開されている実際のプロジェクト 2 件で試しました。unjs/ufo には末尾のスラッシュに関するルールを追加しました(TypeScript で 4 行、$0.18)。python-humanize には sep 引数を追加しました(Python で 2 行、$0.10)。どちらも、失敗した後に合格する独自のテストがあり、プロジェクト全体のテストスイートも引き続きすべて合格しました。すでに動作している機能を依頼された場合は、モデル呼び出しを 1 回行ったところで停止し、何も残しませんでした。
Tewip は、このプロジェクトにまったく関係のない機能も拒否します。Flink の HTTP シンクに関する Apache の実際のチケットを渡したところ、URL ライブラリに「HTTP シンク」が組み込まれてしまいました。テストは合格し、テストスイートもすべて合格し、あらゆる検証ルールを満たしていました。Tewip がテストとコードの両方を書く場合、常に互いに矛盾のない組み合わせを作って合格させられるからです。そのため、今では何かを書く前に、その機能の説明がこのリポジトリに当てはまるかを確認し、当てはまらなければ費用をかけずに拒否します。
以前の約束は、*「コードに触れることはできない」でした。新しい約束は、「動作することを示さずにコードを変更することはできない」*です。
差分を読む前に(新機能)
tewip review --diff main...HEAD
この変更をカバーするテストと、その方法(ファイルをインポートしているのか、ファイルをエクスポートするパッケージをインポートしているのか、単に記述が一致しているだけなのか)、これまでに不安定な結果を出したテスト(赤になっても変更のせいではないと判断できます)、これらの領域で過去に起きた問題、何もテストしていない箇所、そして最初に実行すべき、状況を示すテストのコマンドがわかります。プロジェクト自身の履歴から調べるため、費用はかかりません。
2つの公開プロジェクトの実際のコミット16件を対象に測定しました。開発者がソースとテストの両方を変更したケースで、ソースファイルだけを与えたところ、Tewipは16件中16件で正しいテストを特定し、12件で最上位にランク付けしました。
さらに、変更によって再交渉される取り決めも表示します。差分によって書き換え、取り下げ、または名前が変更されたすべてのテストアサーションを、変更前後のテキストと並べて示します。先に書かれたテストは、誰かが合意した振る舞いです。これはレビューにおいて、変更自身の説明だけでは説明できない唯一のものです。それ以外はすべて、変更が自分自身について語る内容を読むことになります。Tewipが判断を下すことはありません。テストが変更されるのには正当な理由があるためです。作者がどのテストを変更するつもりだったのかを尋ねます。
これに加えて、テスト以外で変更が変える決定事項も示します。何かを拒否するガード、ほかのコードがフォールバック先とする値、負荷時の振る舞いを決める上限、意図的に固定されたバージョンやランナーなどです。同じルール、つまり、すでに存在していたものだけが対象で、新たに追加されたものは対象外です。そして、判定を下すのではなく、同じ問いを投げかけます。
どちらも、アイデアではなく測定結果から生まれました。後に何かを壊したと判明した実際のプルリクエスト18件のうち、Tewipのテスト計画が見逃したのは、意図が間違っていた1件でした。鮮度ルールを変更し、それに合わせてテストを変更した結果、翌日に差し戻されました。
これらのチェックは予測ツールではありません。測定結果もそのことを明確に示しています。リグレッションを引き起こしたことがわかっているプルリクエスト14件のうち、警告したのは4件です。同じリポジトリからの通常のマージ済みプルリクエスト30件では9件で、割合は29%対30%です。取り決めを変える変更が、より壊れやすいわけではありません。これらのチェックがするのは、そうした変更を人の目に触れさせることです。通常のプルリクエストでは、そのような変更を23件見つけました。その中には、削除された raise SystemExit ガード、4から1に減らされたセマフォ、変更されたCIランナーイメージが含まれていました。モデルは呼び出されないため、費用はかかりません。
隔離すべき不安定なテストと、そのコスト(新機能)
tewip flaky --days 30 # the dossier: quarantine, fix, or watch - with the evidence
tewip flaky --apply # writes the quarantine line into the test file
ほかのツールは再試行回数を数えます。Tewipは各失敗の理由をすでに判定しているため、次のように説明できます。このテストは647回の実行のうち161回、109の異なるブランチで失敗しました。つまり、テスト自体の問題で、あなたの変更が原因ではありません。このテストを隔離すれば、チームは週あたり148分のCI時間を取り戻せます。ほとんどの場合に失敗するテスト(それは不安定なのではなく、壊れています)を隠すことは拒み、実際のバグのように見える失敗があったテストを隔離することは決してありません。
3つの実プロジェクトのCI履歴(Gutenberg 2回、Supabase 1回)を対象に測定しました。隔離候補として76件のテストが提案されましたが、実際のバグによる失敗を1件でも含むものはゼロでした。これにより、週あたり約34分、148分、1,178分のCI時間を取り戻せます。また、隔離したテストが失敗しなくなり、元に戻すべきタイミングも通知します。誰も決してやらない、残り半分の作業です。
報告されたバグと、チームが保持するテストケース(フェーズ10、完了)
tewip bugs report.xml --project SHOP # shows what it would file; nothing is created
tewip bugs report.xml --project SHOP --create # files them
tewip jira plan.json --export xray --out cases.csv # or --export zephyr
tewip bugs は、実際のバグだとTewipが診断した失敗についてのみ、エラー、証拠、実行へのリンクを含むチケットを作成します。不安定なテストや壊れた環境については、意図的にチケットを作成しません。まず診断することが目的だからです。同じ失敗についてチケットが二重に作成されることはありません。2回目に検出された場合は、Tewip自身が作成したチケットに短いメモが追加されます。ドライランなら、Jiraアカウントは一切必要ありません。
--export xray|zephyr は、計画のシナリオを各ステップ1行のCSVとして書き出します。これらのツールでインポートできます。アカウントもネットワーク接続も不要です。インポートはあなたが行います。
セキュリティ:実際に対処すべき検出結果(フェーズ 9、新機能)
tewip secure # secrets + npm audit / pip-audit / osv-scanner, triaged
tewip secure --url http://localhost:3000 # also check the running app
tewip secure --zap-report zap.json # and triage an OWASP ZAP baseline report
tewip secure --gate # fails a build only on what needs a person now
スキャナーは問題の検出は得意ですが、どれが重要かを判断するのは苦手です。Tewip は、プロジェクトですでに使っているスキャナーを実行し、検出結果を 今すぐ対処するもの、実在するが到達不能なもの(開発用依存関係、どこからもインポートされていないパッケージ、Git が追跡していないファイル)、ノイズ(README のプレースホルダー)、または 承認済み(すでに担当者が判断済みで、人が編集するファイルにあるもの)に分類します。各判定には根拠が付いています。モデルを呼び出さないため、費用はかかりません。また、認証情報の場所は特定しますが、値は表示しません。
--url を指定すると、ブラウザーと同じように稼働中のアプリもチェックします。セキュリティヘッダー、Cookie のフラグ、そして決して公開してはならないファイル(.env、.git)を確認します。ペイロードの送信、ファジング、ログインの回避は行いません。また、--i-am-authorised を指定しない限り、自分のマシン以外のアドレスは拒否されます。詳細スキャンでは、OWASP ZAP のコマンドを表示し、スキャナーを装うのではなく ZAP のレポートをトリアージします。
gitleaks プロジェクト自身のラベル付きサンプルで測定したところ、Tewip が対応する認証情報の種類では、実際の認証情報 54 件中 50 件を検出しました。ウェブチェックでは、2 つのローカルアプリに仕込まれた脆弱性 8 件をすべて検出し、慎重に設定された公開サイトについては 何も報告しませんでした。また、実際の公開ホームページ 4 件では、毎回、そのサイトが実際に送信するヘッダーと一致するレポートを出しました。このデータセットで明らかになった欠陥 4 件は修正済みです。見逃したままの 4 件は、認証情報ではないもの(署名されていないトークン、Stripe の テスト用キー)です。プロジェクトが安全だと断言することはなく、チェックした項目とチェックしなかった項目を表示します。
エピック、ストーリー、受け入れ条件(フェーズ 14、新機能)
tewip spec "Readers can search the library and open a result"
tewip spec "..." --project PROJ # shows what it would file in Jira
tewip spec "..." --project PROJ --create # files the epic and its stories
コード、テスト、障害履歴をもとに、エピック、ユーザーストーリー、Given / When / Then 形式の受け入れ条件を作成します。システムがすでに実行していると記述する内容には、読み取ったファイルからの引用が付き、Tewip はその引用を一語ずつ検証します。引用できない内容は、断定的な文ではなく未解決の質問として残します。見積もり、日付、ビジネスケースは検証できないため作成しません。
実際の 3 つのプロジェクトで測定したところ、ストーリーは 15 件、受け入れ条件は 49 件でした。既存の動作に関する主張 46 件のうち、22 件は検証可能な引用付きで維持され、24 件は未解決の質問に変更されました。
あらゆる CI、チャット、自分のマシンで(フェーズ 13、新機能)
tewip report report.xml --gate # GitLab CI, Jenkins, CircleCI, Azure, Bitbucket, Travis, Drone
tewip watch --cmd "npm test" # beside your editor: explains each failure as it happens
tewip note --days 7 # the weekly quality note for a lead - free, no model calls
tewip report は、各プラットフォーム固有の変数から実行中の CI を判別し、トリアージボードを表示してファイルに書き込み、ジョブのサマリーに追記します。--gate を指定すると、既知の不安定な失敗や環境由来のノイズではない失敗に限って、ビルドを失敗させます。GitLab では、診断結果をマージリクエストのコメントとして 1 件投稿し、次回の実行時にはコメントを積み上げるのではなく、同じコメントを編集します。TEWIP_SLACK_WEBHOOK または TEWIP_TEAMS_WEBHOOK を設定すると、チームのチャットに通知します。担当者が対応すべき失敗がないときは何も通知しないため、通知がミュートされることもありません。
テストで証明できた場合に限り、コードを修正します(Phase 12、新機能、オプトイン)
tewip fix --code report.xml # shows the patch; your files are left as they were
tewip fix --code report.xml --apply # leaves the proved change in your working tree
Tewipは初日からアプリケーションコードには手を触れない方針でした。これが唯一の例外で、--code と入力した場合にのみ実行されます。Tewip自身が実際のバグだと診断した失敗(信頼度0.85以上)を受け取り、失敗が示すファイルを見つけて、最小限の変更を依頼し、それを証明します。失敗していたテストが必ず通り、さらにテストスイート全体も通らなければなりません。テスト、設定、CIファイル、ロックファイル、マイグレーション、シークレットを含むファイルは編集しません。これらを変更してテストが成功しても、何も証明できないためです。変更を証明できない場合は、代わりにバグを説明し、ファイルをバイト単位で元に戻します。コミットもマージもしません。
2つの公開リポジトリにある実際のバグ修正16件を、2つの言語で再生して測定しました。各修正の直前のコミットを使い、その修正に対応するテストだけを実行して、実際にバグが再現することを確認しています。
| プロジェクト | 言語 | バグ | テストで証明 | 正しいファイル |
|---|---|---|---|---|
| unjs/ufo | TypeScript、Vitest | 8 | 8 | 8件中8件 |
| python-humanize/humanize | Python、pytest | 8 | 8 | 8件中8件 |
変更はすべて小規模(1~16行、中央値4行)で、その多くは開発者自身が実際に書いた変更です。誤った修正は一切提案されませんでした。証明できなかった変更はすべて破棄され、ファイルはバイト単位で元に戻されました。
リリースマネージャーが確認できる1つのバンドル(Phase 15)
tewip attest --out attestation.md
ビルドに関してTewipが把握しているすべてを、1つのファイルにまとめます。実行されたテスト、それぞれの失敗の内容、どのルールまたはモデルが判断したか、判断を保留した内容、そして確認しなかったものを記録します。保留した内容こそ重要です。「判断できませんでした」と決して言わないツールには、証明する価値がありません。書き出す内容のすべてが推測である可能性があるためです。
バンドルにはダイジェストが含まれ、キーを指定するとEd25519署名も付与されます。
TEWIP_ATTEST_KEY=./private.pem tewip attest # sign it
tewip attest --verify attestation.json --key public.pem # check it
ダイジェストは署名とは異なります。Tewipはその点も明示します。キーがなければ、バンドルが破損していないことは示せますが、誰も編集していないことは示せません。署名済みバンドルから主張を編集して削除すると、検証に失敗し、終了コードは0以外になります。CIの実行ごとに、この形式のバンドルが自動的に1つ作成されます。
このインシデントはテストでカバーされていますか?(Phase 16)
tewip incident sentry-issue.json
Sentryのペイロード、OpenTelemetryのスパン、または通常のスタックトレースを読み込み、検出すべきテストを見つけて、4つの判定のいずれかで回答します。再現した、通過した(テストは実行されたものの検出できなかったため、より深刻な状況です)、別の失敗が発生した、または一度も実行されていない。 「おそらくカバーされています」とは言いません。
前回、これについて何を決定しましたか?(Phase 17)
tewip recall "the login test that keeps flaking"
チームがTewipに伝えた修正内容は、すべて保持されます。尋ねると、そのときのチーム自身の判断を答え、それがTewipではなくチームの判断だったと明示します。修正内容に基づいて独自に行動することはありません。
チケットから実行結果まで(Phase 18)
tewip trace --only "SHOP-12"
Tewipが作成したテスト計画を、それをカバーするテストと、それらを試みた実行結果に関連付けます。シナリオがカバー済みと見なされるのは、実際のテストを特定できる場合に限られ、成功と見なされるのは、実際の実行でそのテストが試みられた場合に限られます。それ以外の場合は、何が不足しているかを示します。モデルは使わず、費用もかかりません。
この作業は本当に完了していますか?(Phase 24)
tewip done --diff main...HEAD # one verdict
tewip done --prove --strict # also break the code, and fail the build unless ready
tewip done --json done.json # a sealed verdict that can be checked later
Tewip は、変更について6つの質問に回答できます。エージェントのプルリクエストをレビューするチームは、6つのコマンドを実行して答えを自分たちでまとめなければなりません。実際には、どれも実行せず、チェックが緑になったらマージすることになります。done は、その答えをまとめたものです。
# Is this work done? Not ready
| Question | Answer |
| Is anything failing? | not checked |
| Is the changed code tested? | yes |
| Can the tests in this change fail? | no |
| Would the tests catch a bug in this code? | no |
| Is what was asked for covered? | not checked |
これは、3つのテストがすべて通過した変更での実際の実行結果です。そのうち1つは assert.ok(true) で、新しいコードに意図的に加えた3つの変更がテストスイートに見逃されました。CI は緑でしたが、作業は完了していませんでした。
ここで何かを判断するわけではありません。すべての答えは、それぞれ精度が測定されたレイヤー(トリアージルール、vouch、prove、trace)から得られます。これはそれらを決められた順序で示すだけです。何が壊れているか、次に何が信頼できないか、そして何が不足しているか。常に、同じ変更には同じ判定が返されます。
「判断できない」も正当な答えであり、準備完了として扱われることはありません。 判定には、ほかの何にも代えられない2つの質問、つまり失敗しているものがあるか、このコードを実際にテストしているものがあるかに回答できている必要があります。Tewip がそのプロジェクトのテスト結果を一度も確認したことがなければ、その旨を伝え、承認を拒否します。最初のバージョンは「Ready, with 3 not checked」と答えていましたが、それは曖昧な回答を寄せ集めて承認したものでした。すべての判定の最後には、その判定が何について何も述べていないかも示されます。そこには、ここにあるどのツールにも分からない唯一のこと、つまり変更が意図したとおりに機能するかどうかも含まれます。
--json を指定すると、判定は封印されます。ファイル内の not-ready を ready に編集すると検証に失敗するため、チケットやリリースノートに記載された判定を、信頼するのではなく検証できます。また、これは MCP ツールでもあるため、エージェントは自分の作業が完了しているか、そう伝える前に確認できます。
Tewip を、ほかのエージェントが満たすべきピアとして使う(Phase 34、新機能)
tewip a2a # serves on 127.0.0.1:41241
MCP を使うと、アシスタントは Tewip をツールとして呼び出せます。A2A はその逆方向です。Tewip 自身がエージェントとなり、別のエージェントは作業を完了と見なしてもらう前に、Tewip の確認を通過しなければなりません。作業を人またはエージェントが書いたことの証明を主な役割とするツールには、この形が適しています。コードの大半をエージェントが書くようになれば、それを確認する側もエージェントがアクセスできなければなりません。
/.well-known/agent-card.json でカードを提供し、8つのスキル(triage、vouch、pick、schema、access、perf、standards、done)を備えた JSON-RPC SendMessage に応答します。
推測するのではなく、質問します。 「コードをチェックして」と送ると、Tewip が回答する8つの項目を挙げた質問が返されます。A2A には、そのための状態 TASK_STATE_INPUT_REQUIRED が用意されています。
TASK_STATE_INPUT_REQUIRED
Tewip will not guess which question you are asking: that could be "Does this keep the
team's own rules?" or "Is this work actually finished?", and Tewip will not pick for you.
ガードレールが設計の要です。 これは、リポジトリに対してコマンドを実行する HTTP ポートです。
- 利用できるのは読み取り専用のスキルだけです。
fix、write、build、pursue、proveは対象外です。これらはファイルを変更したり、テストスイートを実行したりします。そうした操作が決して実行されないことをテストで検証します。 --hostを渡さない限り、このマシン上でのみ待ち受け、その意味を明確に伝えます。- すべてのリクエストを
.tewip/a2a.jsonlに記録します。
カードでは streaming: false と pushNotifications: false が宣言されており、これらの操作を行うと、理由を示すフィールド名を含むエラーが返されます。実装していない機能を宣言することは、エージェントカードが決してしてはならないことです。
この変更は遅くなっていますか?(フェーズ30、新機能)
tewip perf summary.json --record # on main: add this run to the baseline
tewip perf summary.json --strict # on a branch: fail the build on a real regression
Tewip は以前から k6 の結果を取り込んでいましたが、それについて見解を示したことはありませんでした。今では、リリース前にどのチームも尋ねる質問に答えます。
難しいのは計算ではありません。「p95 が 180ms から 210ms に上昇、+16%」という結果は、コードなら4行で書けますが、何の役にも立ちません。16%の変化がコードによるものなのか、ノート PC によるものなのか、誰にも分からないからです。ここに、コードを変更していない状態での k6 の実際の実行結果が4つあります。
run 1 p95 = 60.9ms
run 2 p95 = 60.8ms
run 3 p95 = 62.8ms
run 4 p95 = 61.4ms
何も変えていないのに3%のばらつきがあります。これをリグレッションと判定するツールは使われなくなります。
そのため Tewip は、2つの質問に個別に答えます。それぞれ別の理由で答えられないことがあるからです。
| 自分で設定したしきい値を満たしましたか? | k6 スクリプトには、「十分に速い」と判断する基準をすでに記述しています。Tewip は、同じ予算をもう一度書くよう求めず、結果を読み取ります。 |
| 以前より遅くなっていますか? | 記録済みのベースラインが3つ以上ある場合にのみ回答します。それ未満の場合は、判断できません。 |
この3つの実際のベースラインがある場合、61.4ms の同一条件での4回目の実行はリグレッションとは判定されません。一方、実際にリグレッションが起きた場合は判定されます。
- `http_req_duration` p95 282.5ms — **slower**
- baseline 60.8ms–62.8ms over 3 runs, middle 60.9ms
- 282.5ms is outside everything 3 baseline runs produced (60.8-62.8ms) by more than
their own spread, so the runs cannot explain it. That is +364% on the middle run.
記録は意図的に自動化していません。 すべての実行をベースラインに追加するツールでは、基準が徐々に緩くなります。今日のリグレッションが明日には通常の状態となり、比較結果は「範囲内」となり続け、四半期の間にサービスのレイテンシが3倍になっても、一度も誤りのないレポートが出ないままになります。メインブランチでは --record を使い、それ以外では比較します。
実行時間や処理能力、ユーザーがどう感じるかを予測することはありません。 本番環境のハードウェア、実際のデータ量、実際のトラフィックは把握できないため、すべてのレポートでその旨を伝えます。
Lighthouse にも対応(フェーズ31、新機能)
tewip perf lighthouse-report.json --record
k6 は負荷がかかったときのサーバーの動作を測定します。Lighthouse は、実際のブラウザーでの1回のページ読み込みにかかる負荷を測定します。最大コンテンツ描画、レイアウトシフト、ブロッキング時間など、人が実際に待つ時間により近い指標です。tewip perf はどちらの形式も受け取り、どちらが渡されたかを判別します。
Lighthouse では、こうした慎重さがより重要になります。変更していないページを Lighthouse で実際に4回測定したところ、LCP は 922、912、936、916ms でした。 同じルールを適用します。ベースラインが3つあり、その範囲幅を超えて値が外れた場合です。
Tewip が判定をでっち上げることはありません。「2112ms は悪いですか?」には公表された答えがあり、それを決めるのは Google です。Lighthouse は各指標を独自の曲線でスコアリングします。Tewip は記憶したしきい値をハードコーディングせず、そのスコアを読み取ります。実際に遅くなった実行では、FCP と LCP の値がどちらも 2112ms でしたが、Lighthouse は両者を異なる評価にしているため、これは重要です。
- good — `largest-contentful-paint`: 2112ms
- needs improvement — `first-contentful-paint`: 2112ms
- **poor** — `server-response-time`: 611ms
両方に同じしきい値を適用していたら、誤った結果になっていました。
また、Lighthouse がスコアを付けない10項目のアクセシビリティ監査も表示します。論理的なタブ移動順序、フォーカストラップ、視覚的な順序が DOM に沿っているかどうかなどです。これらは失敗でも合格でもありません。失敗がなく、手動確認が必要な項目が10個も未回答のページは、合格したページではありません。
もう1つ、Tewip が受け付けないものがあります。概要が --new-machine-readable-summary から取得された場合、そのエクスポートにはしきい値の判定結果が一切記録されません。その語はスクリプトのコピー内にしか現れません。Tewip は「何も超過していません」ではなく、「このエクスポートからは判断できません」と伝えます。
すべてのユーザーが利用できるでしょうか?(フェーズ 28、新規)
tewip access # every markup file in the project
tewip access src/components/Nav.tsx # or just one
tewip access --strict # fails the build on a barrier that stops somebody outright
HTML、JSX、TSX、Vue、Svelte、Astro、ERB、PHP と、サーバー側でレンダリングされるテンプレート言語である Blade、Twig、Jinja、Razor、Handlebars、Liquid、Nunjucks、EJS を読み取ります。これらで、Web上の実際のHTMLの大部分をカバーします。
アクセシビリティは、品質に関する問題であると同時に、法的な問題でもあります。欧州アクセシビリティ法は2025年6月から施行されており、すでにテストを担当している人たちに影響します。
チームが現在のツールを信頼できない理由は、あらゆるスキャナーを無効にする理由と同じです。axe、Lighthouse、pa11yは、区別のない違反を数百件も返しますが、その多くは実際には障壁ではありません。それらを仕分けるのに必要な午後の時間を取れる人はいません。
Tewipが提示するのは、次の2種類だけで、それ以外はありません。
- 障壁 — 記述された要素が誰かの利用を妨げ、その内容を読めばそれがわかります。
- 確認事項 — ここには何かが欠けているか、読み取れません。判断できるのはあなただけです。
「警告」はありません。警告は、読み飛ばすものとして人々が覚えてしまう分類だからです。
**6 barriers (5 that stop somebody outright), 18 for a person to settle.**
### button-name - 3 places
WCAG 2.2 4.1.2 Name, Role, Value (A), blocker.
Who it stops: a screen reader announces "button" and nothing else, so it cannot be used or spoken to.
- `components/VPNavBarAskAiButton.vue:2` <button type="button" class="VPNavBarAskAiButton">
- it contains no text and carries no aria-label, so it is announced with its role and nothing else
- do this: put text inside it, or add aria-label="..." saying what it does
すべての検出結果には、WCAG 2.2 の達成基準と適合レベルが記載されます。これにより、「コントラストが悪い」というメモではなく、規制当局に提示できる内容になります。
実行する価値がある理由は、ツールが判断を差し控える点にあります。 alt={caption} はaltの欠落ではありません。子コンポーネントからテキストを受け取るボタンを、空だとは言えません。:aria-label="label" はラベルです。<slot /> は、このファイルからは見えないコンテンツです。これらはいずれも、決めつけではなく確認事項になります。<img alt={alt} /> にaltテキストがないと非難するツールは、1日で無効にされてしまうからです。
さらに、レポートにはチェックしなかった項目もすべて表示されます — コントラスト、フォーカス順序、意味のある順序、altテキストが適切かどうか — これらの確認にはレンダリングされたページが必要だからです。問題が見つからなかったという結果は、これらのチェックで何も検出されなかったことを意味します。製品がアクセシブルであることを意味するものでは決してありません。
ブラウザー不要、サーバー不要、ネットワーク不要、モデル不要、費用不要。実際のファイル416件を1.65秒で処理します。
フィクスチャではなく、公開プロジェクト4件 — excalidraw、bootstrap、vitepress、svelte — で測定しました。 障壁は50件、そのうち29件は誰かの利用を直接妨げるもので、確認事項は90件でした。 途中で誤検出のクラスを7つ見つけて修正しました。どれもプロジェクト側ではなくTewipの不具合であり、フィクスチャから検出されることはありませんでした。これらはROADMAP.mdに記載されています。
すでに axe を実行しましたか?Tewip に JSON を渡しましょう(フェーズ 29、新機能)
tewip access --report axe-results.json
マークアップを読んでもコントラストは確認できません。ブラウザーなら確認できるので、Playwright、Cypress、または jest-axe のテストスイートがすでに axe レポートを書き出している場合は、それを渡してください。Tewip がレポートをそのまま返すのではなく、内容を精査します。
ここで、数字が厳しい現実を示します。実際の 9 ページで axe 4.14 を実行したところ、174 件の検出事項が返されました。
| 53 件の障壁 | 実際の WCAG 基準であり、EU アクセシビリティ法が引用する EN 301 549 の条項があります |
| 51 件の助言 | best-practice タグが付いた axe ルールで、どの基準にも該当しません |
| 70 件の確認事項 | axe 自身の incomplete。判定できなかった項目です |
axe が返すものの 42% は、どの規格にも基づいていません。 region だけで 40 件あり、「すべてのコンテンツをランドマーク内に配置する」という内容で、ページ上の実際の障壁をどの項目よりも多く上回りました。Tewip はこれらを障壁ではなく助言として報告し、ビルドを失敗させることもありません。この区別こそが、重要なポイントの大部分を占めています。
未確認項目のリストも、率直に言えば短くなります。7 項目のうち、確認済みに移るのは 1 項目、1.4.3 コントラストだけです。残る 6 項目は、どのツールでも判断できないため、そのまま残ります。また、レポートには実行対象となったページ数が記載され、開かなかったページや到達しなかった状態については何もわからないことが明記されます。
## Checked here only because a browser run was given
- **1.4.3 Contrast (Minimum)** - would otherwise be unreachable: needs the computed colours of a
rendered page, not the markup
ソースコードの検出事項を対象外にするのは、実行時に同じファイルを開き、同等のルールを再実行した場合に限られます。React または Vue のプロジェクトでは、対象外になるものはありません。ソースコードとレンダリング後の出力は別々の成果物であり、どちらももう一方の証拠にはならないためです。
代わりに Lighthouse を実行済みですか?それでも問題ありません(フェーズ 32、新機能)。
tewip access --report lighthouse-report.json
Lighthouse のアクセシビリティ監査は axe ルールそのもの、つまり同じルール ID を使っているため、同じ方法で精査できます。ほとんどのチームは CI で Lighthouse を実行しており、別途 axe を実行する手順はありません。すでに使っているツールで、上記の内容をすべて確認できます。
問題は、Lighthouse のレポートでは axe のタグが削除されるため、landmark-one-main としか表示されず、それがどの WCAG 基準に該当するのか、そもそも基準に該当するのかもわからないことでした。この違いは axe の 105 個のルールのうち 30 個に関係します。100 個の対応関係を記憶した表には、間違いが含まれます。そこで、この表は axe-core 自体から生成されます(scripts/axe-rules.ts)。105 個のルールのうち、75 個には基準があり、30 個はベストプラクティスのみで、分類されていないものはありません。
また、Lighthouse が manual としてマークする 10 個の監査項目も示します。論理的なタブ順序、フォーカストラップ、視覚的な順序が DOM に従っているかどうかなどです。これらは確認事項となり、合格扱いにはなりません。不合格項目がなく、未回答の手動確認が 10 件あるページは、合格したことにはなりません。
プロジェクト独自のルールを教える(フェーズ 27)
tewip standards # what this project has taught Tewip
tewip standards --diff main...HEAD --strict
Tewip はソフトウェア全般に当てはまることを数多く知っていますが、あなたの会社に当てはまることは何も知りません。どの IT 部門にも独自のルールがあります。「書き込みを止めるリリースでは列を削除しない」「ロケーターには data-testid を使う」「テストで sleep を使わない」などです。そうしたルールを教えられないツールは、社内ルールと衝突するツールです。
標準は .tewip/standards/ に置く Markdown ファイルです。
---
description: A fixed wait hides a race instead of fixing it.
applies-to: tests/, e2e/
forbid: /waitForTimeout|sleep\(/ because a fixed wait passes by luck and fails in CI
---
Wait for the thing you are actually waiting for — an element, a response, a state —
never for a number of milliseconds.
重要なのは、この区別です。 forbid と require の行は確認され、適用されます。違反した行が引用され、その隣に独自の理由が表示されます。下の説明文はガイダンスです。Tewip は作成や修正の内容に反映し、レポートでも引用しますが、確認済みとして数えられることも、遵守済みとして報告されることもありません。適用できないルールが適用されているとチームが信じている状態は、ツールをまったく使わず自分たちで注意を払い続けるチームよりも危険です。Tewip が解析できないルールは、黙って削除するのではなく、使用できないものとして報告されます。
ルールを記述すると、そのルールは作業の評価に関わるあらゆる場所に表示されます。tewip review、プルリクエストのコメント、そして tewip done の質問 — 「このプロジェクト独自の標準を守っていますか?」 — にも表示されます。この質問への回答は いいえ となり、該当するルールが示されます。tewip write がテストを作成する際には、ガイダンスがプロンプトに含まれるため、返される内容は Tewip の慣例ではなく、あなたのチームの規約に沿ったものになります。
このマイグレーションは稼働中のデータベースにどのような影響を与えるか?(フェーズ 26)
tewip schema --diff main...HEAD # or: tewip schema migrations/0002_drop_nickname.sql
tewip schema --strict # fails the build on a change that breaks the running version
プルリクエストで最もコストのかかる変更は、たいていテストではなくマイグレーションです。前回のデプロイがまだそのカラムを参照している間にカラムを削除すること。CONCURRENTLY を使わずにインデックスを作成し、最も負荷の高いテーブルへの書き込みをすべてブロックすること。データが入っているテーブルに NOT NULL を追加すること。こうした問題は既知で、文書化されており、ツールならマイグレーションのテキストからすべてを特定できます。
1 of 1 migration file(s) read. 1 change(s) would break the running version or destroy data
## Breaks the version that is still running (1)
- drops the column nickname from orders — migrations/0002_drop_nickname.sql:1
- Instead: deploy code that no longer selects or writes the column, then drop it in a later
migration. During a rolling deploy the old version is still running and will fail on a column
that is gone
## Code that still uses what this takes away (1)
- orders.nickname is still named in 1 file(s): app/orders.py
最後のセクションは、SQL リンターではできないことを行います。マイグレーションによって失われるものが、自分たちのコード内のどこで使われているかを検索します。「これは users.nickname を削除しますが、まだ 4 つのファイルで読み取っています」は、「カラムの削除にはリスクがあります」とはまったく異なる指摘であり、障害を防ぐのはこちらです。
SQL、Django、Rails、Alembic、TypeORM、Sequelize、Knex、Laravel、EF Core、Liquibase のマイグレーションを読み取ります。Prisma、Drizzle、Flyway、golang-migrate も、いずれも通常の .sql を出力するため対象になります。フォワードパスのみを評価します(ロールバックの手順には変更の逆が含まれるため、それを読むと、テーブルを作成するマイグレーションがテーブルを破棄すると判定されます)。また、チームがすでに安全な方法を採用している場合は警告しません。たとえば atomic = False、algorithm: :concurrently、NOT VALID、postgresql_concurrently=True などです。マイグレーションを読み取れない場合は、通過させるのではなく、その旨を伝えます。「読み取ったが何も見つからなかった」ことが、「読み取っていない」ことと混同されることはありません。
実際のプロジェクトで検証済みです。 Zulip のマイグレーション 200 件のうち 199 件を読み取り、稼働中のバージョンを壊したりデータを破壊したりする変更を 19 件検出しました。各検出結果はファイルと照合して正しいことを確認しています。Python のデータマイグレーション内にある生 SQL に埋め込まれた DROP COLUMN も検出しました。Mastodon のマイグレーション 60 件では、テーブルを再書き込みする change_column を検出しました。そのマイグレーションの名前からは、カラムを 1 つ追加するだけに見えていました。
把握できないことについても、きちんと伝えます。テーブルのサイズやデータベースの負荷は把握できないため、文が何をするか、つまりテーブルの再書き込み、全行のスキャン、書き込みのブロックなどを報告し、所要時間の判断はデータを把握している人に委ねます。CI では検出結果をプルリクエストのコメントに記載し、稼働中のバージョンを壊すものは拒否として証拠バンドルに含めます。テストスイートに合格しても、マイグレーションが検証されたことにはなりません。
この変更に気づく可能性のあるテストだけを実行する(Phase 25)
tewip pick --diff main...HEAD # or: tewip pick src/pricing.js
tewip pick --list # just the files, for piping into your runner
40分かかるテストスイートは、実行されなくなります。ベンダーはこれを予測として売り込んでいます。つまり、モデルが重要なテストを推測するというものです。しかし、推測はこの用途には適していません。判断を誤った場合の代償は、バグが本番環境に到達することであり、しかもその推測は誰にも監査できないからです。
ここでは、テストをスキップすることは、そのテストが変更に気づく可能性はなかったという主張です。そして、主張には根拠が必要です。変更されたファイルをインポートするテスト、別のモジュールを経由してそのファイルに到達するテスト、変更自体によって編集されたテスト、実行時にリポジトリを読み込むテスト(すべてのソースファイルをスキャンするガードは、どのファイルによっても壊れる可能性があります)、または最近失敗したテストが実行されます。不明なものは決してスキップされません。それ以外は除外され、その理由が横に表示されます。
絞り込みを一切行わないのは、変更が依存関係、ビルドまたはテストの設定、共通セットアップやフィクスチャに触れる場合、テストスイートがブラウザーを操作する場合(ブラウザーテストが何を実行するかは、インポート内容には記されていないため)、または変更されたファイルをどのテストにもたどれない場合です。インポートに現れない経路からコードに到達することもあるためです。
コードを壊して測定します(eval/pick-safety.ts)。実際の変更を加え、pick にそれを検知できる可能性のあるテストを尋ねてから、テストスイート全体を実行し、実際にどのテストが変更を検知するかを調べます。変更を検知するテストを除外してしまうことが失敗です。
2026-10-19 に、1,288 件のテストを含むテストスイートに対して10個のモジュールで再検証しました。Phase 92 で、変更生成エンジンが報告内容と異なる変更を書き込む可能性が判明したため、一からやり直しました。**実際の変更は28件、そのうち19件はテストスイート全体で検知され、選択の評価に使用できました。検知テストの除外は0件でした。**残りの9件はどのテストにも検知されず、成功として数えるのではなく除外しています。どのテストにも気づかれなかった変更によって、選択が安全だと示すことはできません。
**削減率は一つの数字ではなく、以前公表された5.7%は代表的な値ではありません。**変更されたファイルがどれだけ中心的かによって変わります。これは選択の弱点ではなく、テストが到達できる範囲を正しく反映しています。
| 変更されたファイル | 選択されたテストファイル数(全101件) | 割合 |
|---|---|---|
engine/release/channels.ts | 4 | 4% |
engine/flaky/flaky.ts、engine/perf/compare.ts | 5 | 5% |
engine/secure/secrets.ts | 12 | 12% |
engine/prove/mutants.ts | 31 | 31% |
engine/vouch/vouch.ts | 44 | 44% |
engine/schema/statements.ts | 47 | 47% |
engine/rules.ts、engine/import/junit.ts | 52 | 52% |
評価対象となった19件の変更の平均は**27.9%**です。葉モジュールを変更した場合、実行対象はテストスイートの20分の1に絞られます。ルールエンジンを変更した場合は、半分が正当にその変更に到達します。以前の数値は周辺的なファイルを対象に測定され、この範囲の下限に位置していました。これは、CI の予算を計画する際に使うには不適切な数値です。すべてのテストがパッケージの公開エントリーポイントをインポートするモノリスでは、削減効果をでっち上げず、スキップできるテストはないと示します。また、これは MCP ツールなので、エージェントは何かを実行する前に、実行すべきものを尋ねることができます。
CI では、mode: pick がテストの前に実行され、ワークフローに実行するファイルを渡します。
- id: pick
uses: hmamut39/tewip@main
with: { mode: pick } # needs fetch-depth: 0 on actions/checkout
- run: npx jest ${{ steps.pick.outputs.tests }}
if: steps.pick.outputs.narrowed == 'true'
- run: npx jest
if: steps.pick.outputs.narrowed != 'true'
除外された項目とその理由はすべてジョブのサマリーに記録されるため、「なぜ CI はそのテストを実行しなかったのか」という疑問には、実行結果そのものが答えます。安全に絞り込めない場合、narrowed は false となり、tests は空になります。そのため、このフラグを無視するワークフローでも、すべてのテストを実行します。これが安全なデフォルトです。
テストはバグを検出できるでしょうか?(フェーズ23)
tewip prove src/pricing.js # or --diff main...HEAD for what a change touched
tewip prove src/pricing.js --strict # exits non-zero when something goes unnoticed
カバレッジが示すのは、ある行が実行されたことです。誰かがその行を検証したかどうかは分かりません。prove は実行によってそれを確かめます。境界値を1つずらす、条件を反転させる、and を or にする、返されるフラグを反転させる、パターンを緩めるといった小さな変更を意図的にコードに加え、そのファイルに到達するテストを実行し、どの変更が検知されなかったかをすべて報告します。
4 change(s) were made to your code and the covering tests were run against each. 3 went unnoticed.
- line 2: a boundary moved by one
- was: if (total >= 100 && isMember) return 0.2;
- became: if (total > 100 && isMember) return 0.2;
- line 9: a sign reversed
- was: return total - total * off;
- became: return total + total * off;
どちらも実際に起きています。テストでは150と10が使われましたが、境界値そのものは使われていませんでした。また、finalPrice を呼び出すテストは何も検証していませんでした。どちらの問題も、カバレッジレポートには現れません。どちらの行もカバーされていたからです。
レポートを出すよりも中止することのほうが多くあります。その中止があるからこそ、レポートを読む価値があります。
- ファイルは、改行コードも含めてバイト単位で完全に元どおりに復元されます。
finallyで復元し、復元できたことも前提にせず検証します。復元に失敗した場合は、見過ごすのではなくエラーとして扱います。 - ハングする可能性のある箇所には触れません。 ループのヘッダーは変更しません。
whileの比較条件を反転させても、テストが失敗するのではなく、永久に実行され続ける可能性があるためです。 - テストスイートが失敗していても、証拠にはなりません。 対象ファイルをカバーするテストは、まず変更を加えずにすべて実行します。成功しなかったテストは名前を挙げて除外し、成功するテストが1つもない場合は、その旨を伝えて停止します。すでに失敗していたテストが、あらゆる変更を「検出」したように見えてしまうのを防ぐためです。
- テストが実際にファイルを読み込んでいるかを確認します。 ファイルを完全に壊してもテストが1つも失敗しない場合、テストはインストール済みのコピーかビルド出力を読み込んでいます。その場合は、存在しない問題を並べて報告するのではなく、そのことを伝えます。最初に出会ったPythonプロジェクトで、
import humanizeがまったく別のチェックアウトを参照していた実例を検出しました。 - 文字列やコメントは変更しません。 メッセージの変更は、テストが検出すべきバグではないためです。
インポートをたどるため、別のモジュールを経由して読み込まれるファイルも検証できます。レイヤー構造のあるコードベースでは、そうしたファイルが大半です。必要なのはユニットテストフレームワーク(jest、vitest、mocha、node --test、pytest、go test、maven、gradle、dotnet)だけです。モデルは呼び出さず、かかるコストは実行時間だけです。また、MCP ツールでもあるため、コーディングエージェントは、自分が頼りにしているテストが自身のミスを止められたかどうかを確認できます。
これらのテストは本当に失敗することがあるのでしょうか?(フェーズ 22)
tewip vouch tests/ # or a file, or the whole project
tewip vouch tests/ --strict # exits non-zero, for a merge gate
JavaScript、TypeScript、Python、Java、Kotlin、Scala、Go、C#、Ruby、PHP、Rustを読み取ります。読み取れないファイルを空にするのではなく、そのことを伝えます。
プルリクエストのテストの多くは、今ではエージェントが作成しています。しかし、それが価値のあるテストかどうかを決める問いは、誰も尋ねていません。**このテストは本当に失敗することがあるのでしょうか?**何も検証しないテストでも、カバレッジには数えられます。CI はそのテストを問題なしと判断します。レビュー担当者はもっともらしいコードにざっと目を通し、承認します。
vouch は他の人が書いたテストを読み、テストごとに根拠となる行を引用して回答します。期待値の検証が未完了のテスト(マッチャーのない expect(value); — 検証しているように見えます)、値と同じ値を比較するテスト、自らの失敗を捕捉して無視するテスト、一度も実行されないテスト、値をまったく比較しないテストを見つけます。モデルもコストも不要です。
また、MCP ツールでもあるため、コーディングエージェントは変更がテストでカバーされていると主張する前に、作成したばかりのテストについて質問できます。
6 つの公開プロジェクト(Keycloak、OpenMRS、bitwarden/server、Saleor、GOV.UK Frontend、Firefly III)の Java、C#、Python、PHP、TypeScript のテスト、計 41,523 件で評価しました。すべての指摘をソースコードと照らし合わせて手作業で確認し、固定したコミットに対する件数を corpus/expected.json に記録しています。リリースのたびに npm run corpus で再計算します。
**一度、大きく間違えたことがあります。その点は率直にお伝えすべきです。**この説明の以前のバージョンでは、5,448 件のテストのうち 19 件すべてを正しく判定したと報告していました。その後、Tewip を Keycloak に適用したところ、正しいテストを 166 件も価値のないものと判定しました。そのすべてが、「例外が発生することを期待する」ときの標準的な Java の書き方でした。AssertionError は Exception ではないため、Assert.fail() によって正しく失敗します。このルールは、捕捉された例外の型を一度も確認していませんでした。それ以前も以後もユニットテストは 918 件すべて成功しました。だからこそ、この評価用データセットが存在します。重要なのは、Tewip が他の人のコードについて何を言うかであり、それを測定するものは何もなかったのです。
このリストを読む価値がある理由として、Tewip が拒むことが 2 つあります。
- 推測しません。 検証処理が、追跡できないヘルパー関数の中にあるテストは、価値がないとは判定せず、テスト名を示して未判定として報告します。他の人のテストに対する誤った指摘は、見逃しよりも大きな損失につながります。
- 過大な主張をしません。 アサーションがなくても、コードが例外を投げればテストは失敗します。axios では、TypeScript のフィクスチャをコンパイルして実行するテストが、意図的に何もアサーションしていない場合があります。そのようなテストは、壊れているのではなく「値を比較していない」として別途報告され、
--strictを作動させません。
実行による再現率の測定(eval/vouch-recall.ts):ソースファイルに変更を加え、どのテストがどの変更を検出するか記録します。何かを確実に検出したテストについて、最後の文を削除し、すべてをもう一度実行します。変更を検出していたテストが何も検出しなくなった場合、そのテストが検証を失ったことは明らかです。この判定は vouch 独自のパターンに依存しません。2 つのプロジェクトにおける 7 組のソース/テスト間でこのようなケースが 17 件あり、vouch はそのうち 12 件(70.6%)を指摘しました。指摘しなかった 5 件にも実際のアサーションが残っているため、それらの判定も正しいものです。変更を引き続き検出できたテストを誤って指摘したことはありません。
動詞ではなく目標(フェーズ19および21)
tewip pursue "keep the checkout flow green"
tewip pursue "keep the checkout flow green" --act
Tewip に目標を与えると、実際に確認できる情報をもとに、次に何をするか、そしてその理由を示します。実行順序は固定され、公開されており、テスト可能です。モデルが選ぶものではありません。まず実際のバグ、次に環境、次に不安定さ、次に原因を説明できない失敗、次に失敗しないテスト、その次にカバレッジの不足を確認し、目標を認証する価値があるのはその後です。同じ状態を2回判定すると、同じ答えが返ります。
--act を指定すると、その判断を実行します。ここで拒否のルールが最も重要になります。
- 作業そのものを行うことはありません。 各アクションは、変更内容をすでに検証できる既存のコマンドです。
writeは、テストに合格し、かつ 壊れた場合に失敗するときに限り、そのテストを保持します。 - 許可リストにあるアクションは2つです。不足しているテストの作成と、成功した目標の認証です。それ以外はすべて、名前を挙げて拒否します。実際のバグを回避するような対応はしません。
- アクションは1つ実行したら停止します。 無人で繰り返すループはありません。
- 実行または拒否した内容はすべて、その根拠となった実行結果とともに
.tewip/actions.jsonlに記録されます。 - 同じ試みを繰り返すことはありません。新しい実行結果から新たな根拠が得られるまで、同じ試みは拒否されます。
試行実績
| プロジェクト | 方法 | 結果 |
|---|---|---|
| 非公開の練習用リポジトリ(非公開のためリンクなし) | 故意に仕込んだ11件の失敗を含むリリースPRで、GitHub Actionsを実行 | 診断コメント、環境の問題1件、チェックアウト後に5か所のロケーター変更が合格する修正PR。トラップには手を加えず。合成データ。 |
| WordPress Gutenberg(公開) | CIの実際のBlobレポートを5つの期間からオフラインで利用。そのうち2つはパイプラインの凍結後に収集 | ラベル付けされた実際の失敗1,441件で正解率84~98%。このカテゴリを測定できるだけのドリフト事例があった唯一のプロジェクトです(注意事項はeval/README.mdを参照)。 |
| JupyterLab(公開) | Galata UIスイートをオフラインで利用 | ラベル付けされた失敗41件で90.2%。決定論的ルールだけで判定した34件は、34件すべて正解でした。 |
| LXD UI(公開) | プルリクエスト用スイートをオフラインで利用 | ラベル付けされた失敗69件で91.3%。ルールによる判定は63件中63件が正解でした。誤判定6件はすべて、ブランチ間の不安定さを実際のバグとして読み取ったものです。 |
| Supabase Studio(公開) | シャドー実行:実際のCI Blobレポートを利用し、プロジェクトには何も投稿せず | REAL_BUGは6件中6件、TEST_DATAは6件中6件が正解。多数を占めるTIMINGは、ラベルと同じシグナルを共有しています。 |
| Penpot(公開) | ダウンロード可能な実行結果21件でシャドー実行 | 3つ目のプロジェクトでも動作。ただし、ラベル付き事例は5件だけで、スコアを算出するには少なすぎます。 |
| Nextcloud server(公開) | 試行 | 収集は問題なく完了(失敗45件)しましたが、対象期間内にラベル付けの根拠があった事例は1件だけで、スコアを算出するには少なすぎます。 |
| Ghost(公開) | 試行 | 外部からは利用できません。Ghostは失敗した実行結果のBlobレポートしかアップロードせず、保存期間も約1日です。そのため、255件の実行結果のうち残ったのは3件でした。 |
シャドー実行は、プロジェクトに手を加えることなく、公開プロジェクト上でエージェントを試す方法です。npm run harvest -- <source> を実行し、続けて node scripts/shadow.ts <source> [--publish your/private-repo] を実行します。
他のツールとの比較(2026年9月)
ほかのツールもこの作業の一部を担います。この表は、各ツールが公開情報で示している特徴と、triage-agentとの違いをまとめたものであり、各ツールのベンチマークではありません。
| ツール | 機能 | triage-agentとの違い |
|---|---|---|
| Playwright Test Agents — Healer | 壊れたセレクターを書き換えてテストを再実行します。開発元によると、セレクターの失敗に対する成功率は約75%です | triage-agentはまず、そもそもセレクターが変更されたのかどうかを判断します(実際のバグ、競合状態、環境、テストデータを先に除外します)。その後、決定的なルールに一致し、再実行で効果が確認できたものだけを修正します。実際に修正できたのは14件で、誤った修正はありませんでした。すべてのセレクター失敗を修復するヒーラーは、削除された機能まで「修復」してしまいます |
| Trunk、BuildPulse、Datadog Test Optimization | 成功・失敗の履歴から不安定なテストを検出し、マージを妨げないよう隔離します | 同じ中核シグナル(同じコードで失敗した後に成功したテスト)に加え、不安定なテストだけでなく、すべての失敗の原因を示し、失敗ごとにマージを制御します。実際の失敗2,296件で測定済み(以下を参照) |
| ReportPortal | 過去の人による分類との照合により、失敗を製品のバグ、自動化のバグ、システムの問題に分類します | 人から学習する考え方(/triageによる修正)に加え、学習データが不要な決定的ルールも備えているため、初回の実行から役立ちます |
| Develocity | ビルドとテストの失敗を履歴にわたって根本原因ごとにグループ化します(GradleとMaven) | JUnit XMLまたはTRXを介してあらゆる言語に対応し、失敗ごとに対応します。コメント、グループ化された環境の問題、検証済みの修正、ゲートを提供します |
備えていない機能もありますが、これらのツールにはあります。ダッシュボードとホスト型の履歴(履歴はActionsキャッシュに保存されます)、そして本番環境での長年の利用実績です。
スマートマージゲート
gate: real-failuresを指定すると、失敗したテストについて人の対応が必要な場合に限り、トリアージのステップがビルドを失敗させます。対象は、実際のバグ、変更されたセレクター、テストデータの問題、または判定保留のものです。決定的なルールまたは人によって不安定なテストか環境の問題と分類された失敗は、ブロックしません。AIのみの判定は、モデルの信頼性が低い側であるため、引き続きブロックします。
- name: Tests
continue-on-error: true # let the gate decide the outcome
run: npx playwright test # or pytest, jest, mvn test, go test ...
- name: triage-agent
if: always()
uses: hmamut39/tewip@main
with:
gate: real-failures
5つのプロジェクトから収集した、ラベル付きの実際の失敗2,296件で測定した結果、ゲートは1,823件の失敗を通過させ、その中に実際のバグ、変更されたセレクター、テストデータの問題は1件もありませんでした。不安定なテストと環境の問題のうち、全体の84%(2,160件中1,823件)がマージをブロックしなくなります。このゼロという結果は慎重に受け止めてください。最初の測定では実際のバグを1件通過させました(新しいテストが、フィーチャーブランチで新しいバックエンドコードによるサーバーエラーに遭遇しました)。その後、テストが一度も成功していない場合はサーバーエラーのルールが判定を保留するように変更されました。このゼロは、問題の発見に使われたものと同じデータで測定されているため、楽観的な結果です。週次ジョブでは、新しいデータを使って継続的に確認しています。件数は後続のステップで使用できるステップ出力(blocking、flaky、environment)としても提供されます。
動作の仕組み
-
reporters/triage-reporter.tsはカスタムの Playwright レポーターです。listと並行して実行されます。ステータスがfailedまたはtimedOutの試行ごとに、エラー、スタック、所要時間、リトライ、トレース、スクリーンショットとerror-context.mdのパス、実行 ID、git SHA を記録します。各失敗にルールエンジンを実行し、それぞれのdiagnosisを含むレコードをdata/triage.jsonlに追記します。また、各テストの実行回数を記録する、実行ごとのサマリー行をdata/runs.jsonlに追記します。 -
engine/はフェーズ 2 のルールエンジンです。決定論的に動作し、同じ失敗と履歴に対しては常に同じ結果を返します。失敗を 5 つの根本原因(REAL_BUG、LOCATOR_DRIFT、TIMING、ENV、TEST_DATA)のいずれかに、信頼度と根拠とともに分類します。どのルールでも判定できない場合は、フェーズ 3 で使うため、各ルールが確認した内容とともに信頼度 0 のUNKNOWNを返します。 -
engine/llm/とengine/trace/がフェーズ 3 の LLM レイヤーを構成します。ルールによってUNKNOWNとされた失敗のみを処理します。trace.zip(最終 DOM、失敗したリクエスト、コンソールエラー、テスト手順)とerror-context.md(ページのスナップショットと、コメントを除去した失敗箇所のコード行)を読み取ります。生ログではなく、短い構造化サマリーを作成し、モデルに 5 つのカテゴリのいずれかであることを必須とする厳密な JSON 形式の回答を求めます。回答はローカルでも再検証されます。呼び出しに失敗した場合、または回答が無効な場合、失敗はUNKNOWNのままです。engine/pipeline.tsがルールを実行してから LLM を実行し、レポーター、CLI、評価のすべてでこれを使用します。 -
eval/には、正解ラベルとフェーズ 3 の精度指標を出力するevaluate.tsがあります。eval/harvest/は公開リポジトリの実際の CI 実行を取り込みます。eval/README.md を参照してください。 -
engine/decide.tsは、エージェントの DECIDE ステップです。ROADMAP.md の自律性テーブルに従い、各診断を次のアクションに変換します。ロケーターまたは固定待機時間の修正、再実行と通知、テストセットアップの修正、バグ報告、人間へのエスカレーションのいずれかです。信頼度が低い場合(0.5 未満)は、必ずエスカレーションします。コード修正をエージェントが実行できるのは、信頼度が 0.85 を超える場合のみです。まだ何も実行されません。アクションの実行はフェーズ 5 で行います。 -
outlets/にはフェーズ 4 のビューがあります。各ビューは同じTriageItemを表示します。内容は診断、次のアクション、信頼度、データソース、根拠です。npm run triageはビューをdata/reports/<dataset>/配下に Markdown 形式で出力します(gitignore 対象)。役割 ビュー 対象範囲 開発者 pr-comment.md:どの失敗がこの変更によるものと考えられるか、その理由失敗した各実行 SDET sdet-board.md:すべての失敗を次のアクションごとに分類失敗した各実行 DevOps / SRE infra.md:環境の失敗を問題の種類ごとに分類し、リトライによる復旧と、まとめたアラートを表示失敗した各実行 ビジネス / UAT release.md:READY / WAIT / NOT READY を平易な言葉で表示失敗した各実行 シニア / プリンシパルエンジニア quality.md:CI 時間の損失順に、フレーキーテストのホットスポット、繰り返し発生するパターン、テスト設計上の負債を表示対象期間全体 アーキテクト architecture.md:領域ごとの脆弱性、多数のスイートを壊した単一のコミット、依存関係の失敗を表示対象期間全体 リード / マネージャー digest.md:対象期間の前半から後半にかけて失敗率が上昇した領域を表示対象期間全体 -
scripts/history.tsはレコードをテストごとにグループ化し、失敗率を出力します。失敗率が 20% から 80% の間で、エラーメッセージにばらつきがあるテストにはSUSPECTED_FLAKYのフラグが付けられます。 -
scripts/diagnose.tsは収集したすべての失敗に対してエンジンを実行し、データセット名を付けてフェーズ 2 の指標(カバレッジ)を出力します。 -
tests/には、fixtures/からオフラインで提供され、意図的に失敗する 5 つのテストがあります。これらはパイプラインの動作確認のためだけに存在します。これらのテストで算出した数値は、製品の指標ではありません。
収集したデータはローカルに保持されるため、data/ は gitignore 対象です。各実行の成果物は test-results/<runId>/ に書き込まれるため、過去の実行の添付ファイルパスも引き続き機能します。
ルール(engine/rules.ts)
この順序で最初に一致したルールによってカテゴリが決まります。優先度の低いルールと一致しない場合、信頼度が0.1下がります。
| ルール | カテゴリ | 該当条件 |
|---|---|---|
env-mass-failure | ENV | 3件以上のテストが失敗し、その失敗が実行全体の30%以上を占め、すべてが同じエラーの形を示す場合です。エラーが異なる多数の失敗は該当しません。 |
env-network | ENV | エラーが接続エラー(net::ERR_*、ECONNREFUSED など)、HTTP 5xx、または認証失敗を示している場合です。 |
test-data-collision | TEST_DATA | エラーが、テストデータと既存データの衝突(重複キー、一意制約、「already exists」)を示している場合です。 |
env-server-error | ENV | テスト中にアプリのバックエンドが5xxを返した場合です。ただし、意図的にエラーを発生させるテストと、このコミットでのみ確認されたエラーは除外します。 |
locator-drift-strict | LOCATOR_DRIFT | アクションのロケーターが複数の要素に一致し、そのうちちょうど1つの要素にロケーター名が単語全体として含まれている場合です(name: 'Edit' → "Editor canvas"、"Edit link")。修正には、その要素に対して Playwright が表示したロケーターを使います。 |
timing-intercepted | TIMING | 要素は操作可能な状態だったものの、別の要素(スナックバー、メニュー、オーバーレイ)がポインターイベントを妨げているとエラーが示し、クリックできなかった場合です。Selenium の Other element would receive the click と Cypress の is being covered by another element も該当します(ラベル付きデータで測定するまでは0.65)。 |
timing-stale-element | TIMING | Selenium の StaleElementReferenceException または Cypress の the page updated while this command was executing の場合です。要素を検索してから使用するまでの間に、ページ上でその要素が置き換えられています(測定するまでは0.65)。 |
timing-retry-pass | TIMING | 同じ実行内で、同じコードを使った別の試行が成功した場合です。 |
timing-known-flaky | TIMING | 既知の不安定なテストの場合です。以前の実行で同じエラーが発生した後、再試行で成功しています。テスト中にリクエストが失敗した場合は後退します。 |
locator-drift | LOCATOR_DRIFT | 要素が見つからなかった(Playwright、Selenium の NoSuchElementException、WebdriverIO、Cypress の Expected to find element)ものの、ページのスナップショットに類似した名前の要素がある場合です(類似度 ≥ 0.6)。テストに成功記録のある実行がない場合は除外します。要素が一致したことを示す記録がないためです。 |
timing-flaky | TIMING | 3回以上の実行における失敗率が20%~80%で、エラーメッセージが一定でない場合です。 |
real-bug-assertion | REAL_BUG | 履歴が安定しているテストで値の不一致が発生した場合です。以前は問題なく成功しており、それ以降は同じ形で失敗しています。 |
各ルールの正確さ
6つのラベル付きデータセットで、node eval/calibration.ts を使って測定しました。ルールのみを対象としており、モデルは使っていません。
claimed 列は、ルールが回答とともに出力する確信度です。observed 列は、その回答が人手で付けたラベルと一致した頻度です。実績より高い確信度を示すルールは、このプロジェクトで許容しない唯一の種類の誤りです。
| rule | cases | right | observed | claimed | projects |
|---|---|---|---|---|---|
timing-retry-pass | 1478 | 1463 | 99.0% | 0.74 | 6 |
env-network | 395 | 395 | 100.0% | 0.80 | 5 |
env-server-error | 43 | 43 | 100.0% | 0.60 | 5 |
timing-intercepted | 32 | 32 | 100.0% | 0.80 | 5 |
real-bug-assertion | 26 | 10 | 38.5% | 0.40 | 5 |
locator-drift-strict | 17 | 17 | 100.0% | 0.89 | 2 |
timing-flaky | 9 | 9 | 100.0% | 0.90 | 1 |
test-data-collision | 6 | 6 | 100.0% | 0.70 | 1 |
locator-drift | 5 | 3 | 60.0% | 0.80 | 2 |
2つを除くすべてのルールは、実際の性能を控えめに見積もっています。これは安全ですが、負担がないわけではありません。マージゲートが信頼するには0.7、オートフィックスには0.85が必要です。そのため、395回中395回正解しているのに確信度を0.80とするルールでは、本来見る必要のなかった人に作業が回されます。
例外は real-bug-assertion でした。これは、アプリケーションが壊れているとチームに伝えるルールです。このルールは 0.65 + 0.05 x failingStreak、最大0.9の確信度を示していましたが、26回中正解は10回でした。16回の誤判定はすべて、フレーキーテストを本物のバグと判定したものでした。連続失敗による加算は、根拠がないだけでなく、結果を逆に悪化させていました。連続失敗が1回のとき、このルールの正解率は5つのプロジェクト全体で62.5%でしたが、2回以上では10件中0件でした。現在は正解率と同じ0.40を示し、どちらのしきい値も下回っています。つまり、5回に2回の確度のシグナルがふさわしい、人による確認に回されます。判定内容自体に変更はありません。ルール層はこれまでと同じ2,012件の失敗に回答し、同じ1,979件で正解しています。
locator-drift の正解率は60%ですが、測定結果をそのままにしています。2つのプロジェクトにまたがる5件だけでは数値を変更するには不十分です。それを明示するほうが、無視したり、根拠のない修正を考案したりするより適切です。
履歴は時点ごとに評価されます。各失敗は、その失敗が発生した実行までの履歴のみを使って判定し、それ以降の実行は参照しません。そのため、テストで初めて発生した失敗には履歴がなく、履歴に基づくルールは判定を見送ります。
使い方
Node >= 22.18 が必要です。Node は .ts スクリプトを直接実行します。
npm install
npx playwright install chromium
npm test # one run (records are diagnosed as they are saved)
npm run test:loop # 5 runs in a row, to build up history
npm run history # failure-rate table
npm run diagnose # rule-engine classification + coverage metric (add -- --evidence for details)
npm run eval:synthetic # rules + LLM vs the synthetic labels (pipeline check, not a product metric)
npm run eval # rules + LLM vs your real labels in eval/ground-truth.jsonl
npm run lab # drift lab: the full collect -> diagnose -> decide -> auto-fix -> verify loop, locally
npm run triage # every role's view for data/ + the phase-4 metric
npm run triage -- --data data/real/gutenberg-holdout # the same on real CI data
npm run test:engine # unit tests for rules, LLM layer, decide step and views (no network)
オートフィックスとドリフトラボ(フェーズ5、進行中)
engine/autofix/ は LOCATOR_DRIFT 用の ACT + VERIFY ループです。仕様ファイル内で失敗したロケーターを見つけ、失敗時のページから取得したロールベースの置き換え候補を最大3つ試します。試行のたびに該当するテストを1つ再実行し、テストに合格した場合に限って変更を保持します。合格しなければファイルを元に戻します。安全のため、次のルールがコードに組み込まれています。
- サンドボックスディレクトリ内のファイルのみを編集し、アプリケーションコードは決して編集しません。
- 壊れた呼び出しの後に
expect()がないテストは拒否します。その場合の合格は何の証明にもならないためです。 - 決定論的なドリフトルール(
locator-driftまたはlocator-drift-strict)が0.85を超える確信度で診断したドリフトのみを対象とします。実際のCIデータでは、AIだけの判定で、本物のバグが0.88〜0.96の確信度で「ドリフト」と呼ばれていたため、AIのみで判定したドリフトは人に回します。 - すべての判定とその理由を記録し、プッシュやマージは決して行いません。
npm run lab は lab/app に対してループ全体を実行します。バージョンv1を対象にテストが作成されています。バージョンv2は、名前や形状が変更された要素が6つと、見た目が似た要素に置き換えられた削除済み機能、誤った価格、無効化されたボタン、サーバー障害、アサーションのないテストという5つの罠を含むリリースです。正解データは lab/cases.json にあります。現在の結果は、ドリフトしたロケーター7件中6件を修正して検証し、誤修正は6件中0件です。これは合成データであり、製品の指標ではありません。実際にラベル付けされたGutenbergの失敗では、ルールによってオートフィックスの対象となるドリフト15件に到達しており、誤りは0件です。各ケースで提案されるロケーターは、開発者自身が記述したものと完全に一致します。
人から学ぶ(LEARN)
エージェントの PR コメントは、修正方法を伝える1行で締めくくられます。たとえば /triage TEST_DATA #1 the fixture user has no saved card のような返信は、次回の実行時に読み取られ、実行履歴とともに保存され、同じテストで同じ失敗が後から発生するたびに適用されます。ビューには、そのカテゴリが人によって修正済みと表示され、根拠として修正した人の名前と理由が示されます。また、エージェントが述べた内容もその横に残るため、意見の食い違いがひそかに上書きされず、見える状態に保たれます。
意図的に設けている制限は2つあります。
- 修正されるのはカテゴリであり、コード変更ではありません。
LOCATOR_DRIFTと書いても、再実行によって有効性が確認された代替ロケーターをエージェントに提示したことにはならないため、SDET が引き続き修正を記述します。 - 適用されるのは、同じテストで同じ失敗の仕方をした場合です。そのテストで異なる失敗が発生した場合は別の問題であり、エージェントが自ら回答します。
実行にかかるコスト
各トリアージ実行、CLI、評価、CI ジョブの概要は、モデル呼び出しの回数、所要時間、キャッシュによって無料になった回数、使用トークン数、ドル建てのコストを示す1行で終わります。各呼び出しは、それぞれのモデルに応じて OpenAI の公開価格で計算されます(キャッシュされた入力にはキャッシュ用の料金が適用されます)。独自の価格を設定するチームは TRIAGE_LLM_PRICE_IN/OUT を指定できます。価格が不明なモデルは推測せず、その旨が報告されます。ほとんどの失敗には決定論的なルールが回答し、ルールで判断できないものだけがモデルに送られるため、実行コストを抑えられます。実測例(JupyterLab、実際に発生した41件の失敗)では、ルールが34件を判定し、6件がモデルに送られました。その6回の呼び出しにかかった時間は30秒、使用トークン数は合計約31,000でした。
セキュリティ
エージェントは、プルリクエストの作成者が制御できるテキスト(テスト名、エラーメッセージ、トレース)を読み取り、マージをブロックするかどうかを変えられるため、信頼できない入力を前提に構築されています。
- 修正できるのは書き込みアクセス権のある人(オーナー、メンバー、コラボレーター)だけです。 パブリックリポジトリでは、見知らぬ人からの
/triageコメントは無視されるため、チーム外の人が実際の失敗をマージゲートで見逃させることはできません。 #1の意味を定義できるのは、エージェント自身のコメントだけです。 ほかの人が投稿した番号対応表は無視され、対応表のフィールドは、テスト名が外部に抜け出せないようエンコードされます。- テスト実行から取得したテキストは、コメント内で無害化されます。
@mentionsによる通知は発生せず、リンクと画像はプレーンテキストとして表示され、HTML はエスケープされます。 - リスクを伴う判断の最終決定を AI に委ねることはありません。 作為的なエラーメッセージでモデルに特定の回答を促すことはできても、AI だけによる判定で失敗をゲートに通すことはなく、コード変更を許可することもありません。修正には、決定論的なルールとの一致と、再実行での成功が必要です。
- マージもアプリケーションコードの編集も行わず、収集したデータはリポジトリではなく Actions キャッシュに保存します。OpenAI キーは省略可能で、シークレットから読み取られる場合に限り使用されます。
既知の問題(実データで確認)
- ドリフトと実際のバグを見分けるのは困難です(改善中)。 Rules-5 は Playwright の strict-mode エラーを読み取ります。
name: 'Edit'のようなロケーターが複数の要素に一致するようになると、エラーにはすでにそれらの要素が列挙されており、テストが意図しているのは名前が完全な単語になっている要素です。新しいデータセット(9月1〜3日)では、ドリフトは 16/20 = 80% です(ラベル付けの不備を修正する前のラベルでは 16/23 = 70%。詳細は eval/README.md を参照)。実際のバグをドリフトと誤判定したのは 29件中1件で、ドリフトの15件は自動修正できるようになりました。いずれの提案も、開発者自身による修正と一致しています。未確認の1週間分のデータ(8月20〜26日、473件のラベル)では、ドリフトは 3/3 で、エージェントによる自動変更は引き続き 0件です。残る見逃しには利用可能なページデータがありません。エラーにロケーター名がまったく含まれていないためです。 - Playwright がページのスナップショットを常に書き込むとは限りません。 一部の失敗(フレーム内のタイムアウトなど)では、
error-context.mdにエラーとテストソースしか含まれないため、類似性ルールでは判定できません。トレース DOM からページを再構築しても役に立ちません。実データでは、実際のバグもドリフトも同程度の類似度(0.80〜0.96)となり、AI に有益な情報ではなくノイズを与えるためです(試したところ、ホールドアウト精度は 86.1% から 81.3% に低下しました)。 - 想定されたサーバーエラー(一部修正済み)。 サーバーエラーを意図的に発生させるテストは、以前は ENV として判定されていました。現在は、テスト名からエラーハンドリングを検証していると分かる場合、そのことをモデルに伝えます(プロンプト llm-4)。
- ビューでは、プルリクエストのブランチとメインブランチをまだ区別できません。 レコードにブランチが保存されないため、未マージの PR 内のリグレッションも、アーキテクチャビューとダイジェストでは製品のバグとして数えられます。
- 繰り返し発生する一部の不安定なテストは誤判定されます。 他のブランチでも失敗する不安定なテストは誤分類されます(ホールドアウトセットでは 0/22)。また、TEST_DATA と LOCATOR_DRIFT はまだ実データで測定されていません。
環境変数(.env に記述できます。このファイルは gitignore の対象です):
OPENAI_API_KEY:LLM レイヤーを有効にします。設定しない場合、ルールのみが実行されます。TRIAGE_LLM=off:キーを設定していても、LLM レイヤーを無効にします。TRIAGE_LLM_MODEL(デフォルトはgpt-5.4-mini)とTRIAGE_LLM_REASONING(デフォルトはlow):使用するモデルと推論の強度を指定します。TRIAGE_LLM_CACHE=off:data/llm-cache.jsonlのレスポンスキャッシュをスキップします。キャッシュが有効な場合、変更のないリクエストにはキャッシュから無料で応答します。TRIAGE_LLM_MAX_CALLS:1回の実行でのモデル呼び出しの上限です。この上限を超えた場合、それ以降の失敗についてはルールによる判定を維持し、その旨を表示します。大規模な失敗実行で請求額が際限なく増えるのを防ぎます。TRIAGE_LLM_PRICE_IN/TRIAGE_LLM_PRICE_OUT:OpenAI モデル向けに組み込まれている公開価格を上書きする、入力/出力トークン100万件あたりの独自価格です。組み込み価格のないモデルの場合、コストを確認するにはこれらを設定してください。設定しない場合、実行時に価格不明と表示されます。CI_RUN_ID:実行 ID として使用します。設定しない場合、実行 ID はタイムスタンプに基づきます。GIT_SHAまたはGITHUB_SHA:レコードのgitShaとして保存されます。どちらも設定されていない場合、gitShaは空のままです。
マシン外に送信されるデータ: LLM レイヤーが有効な場合、UNKNOWN と判定された各失敗の概要が OpenAI に送信されます。この概要には、エラーテキスト、ページのスナップショット、失敗したリクエスト URL(クエリ文字列を除く)、コンソールエラーが含まれます。git にコミットされるものはありません。
開発者
Tewip は Mamuti Aishan(Hasan) が作成・保守しています。GitHub:@hmamut39。
名前はウイグル語に由来します。téwip(تېۋىپ)は、治療師または医師という意味です。医師の仕事の考え方と同じです。 原因を見つけ、根拠を示し、判断できないときは率直にそう伝えます。
同じ作者が以下も公開しています。
- npm —
tewip-ai - VS Code Marketplace — Tewip
- Open VSX(Cursor、Windsurf、VSCodium)— hmamut39.tewip
- MCP registry —
io.github.hmamut39/tewip - Claude Code plugin — tewip-plugin
ライセンスは Apache-2.0 です。機械可読形式の著者情報については、CITATION.cff をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。