Skip to content

[#761] add-command-gate#763

Open
nrslib wants to merge 2 commits into
mainfrom
takt/761/add-command-gate
Open

[#761] add-command-gate#763
nrslib wants to merge 2 commits into
mainfrom
takt/761/add-command-gate

Conversation

@nrslib
Copy link
Copy Markdown
Owner

@nrslib nrslib commented May 26, 2026

Summary

タスク指示書: quality_gates に command gate を追加する

目的

TAKT の既存 quality_gates に、ステップ完了時に shell command を機械的に実行する type: command gate を追加する。

command gate は exit code 0 の場合のみ成功とし、exit code 0 以外の場合は、その実行結果を AI への差し戻し入力として渡す。既存の文字列 quality_gates はそのまま AI へのプロンプト指示として維持し、同じ配列内で command gate と同居できるようにする。

参照資料

以下を最初に確認すること。

  • .takt/config.yaml
    • 既存の workflow_overrides.steps.*.quality_gates の実例
  • src/infra/task/projectLocalTaktSync.ts
    • .takt/config.yaml など、worktree 再利用時に同期される .takt 資産の定義
  • src/infra/task/clone-exec.ts
    • 新規 worktree 作成時の clone 挙動
  • 既存の quality_gates 読み込み・プロンプト生成・ステップ完了処理に関係するモジュール
    • planner は rg "quality_gates|qualityGate|quality gate|quality_gate" で実装箇所を特定すること

優先度: 高

1. quality_gates の型・設定読み込みを拡張する

対象モジュール:

  • 設定スキーマ定義
  • workflow override 読み込み
  • step 定義・実行コンテキスト生成
  • quality_gates を扱う型定義

実装内容:

  • 既存の文字列 gate を維持する。
  • quality_gates 配列に以下の object gate を混在可能にする。
workflow_overrides:
  steps:
    implement:
      quality_gates:
        - "Review the implementation before finishing"

        - type: command
          name: quality-check
          command: "./.takt/quality-gates/check.sh"
          timeout_ms: 300000
  • type: command の gate を command gate として扱う。
  • 文字列 gate は従来どおり AI への指示として扱う。
  • type: command 以外の既存挙動を壊さない。

command gate の最低限の設定項目:

  • type: "command"
  • name?: string
  • command: string
  • cwd?: string
  • timeout_ms?: number

2. ステップ完了時に command gate を実行する

対象モジュール:

  • ステップ実行完了処理
  • agent への差し戻し・再実行処理
  • command 実行ユーティリティが既にある場合はその周辺

実装内容:

  • type: command gate を、対象ステップ完了時に機械的に実行する。
  • 実行順は quality_gates 配列の定義順に従う。
  • exit code 0 の場合のみ成功とする。
  • exit code 0 以外の場合は gate 失敗として扱い、AI に差し戻す。
  • command gate が失敗した場合、その後続 gate は実行せず、失敗した gate の情報を差し戻す。
  • command には shell script ファイルパスも指定できるようにする。
  • cwd 省略時は worktree のプロジェクトルートで実行する。
  • cwd 指定時は、その cwd 上で command を実行する。

差し戻しに含める情報:

  • gate 名
  • gate type
  • command
  • cwd
  • exit code
  • stdout
  • stderr
  • timeout が発生した場合は timeout 情報

3. .takt/quality-gates/ を worktree に持っていく

対象モジュール:

  • src/infra/task/projectLocalTaktSync.ts
  • worktree 作成・再利用・リトライ時の .takt 資産同期処理

実装内容:

  • .takt/quality-gates/.takt/config.yaml と同じく worktree 側へ持っていく対象にする。
  • 再利用・リトライ時の同期対象に quality-gates ディレクトリを追加する。
  • command gate の command: "./.takt/quality-gates/check.sh" は、元リポジトリではなく worktree 内のファイルを指すようにする。
  • 既存の .takt/config.yaml の同期挙動は維持する。

優先度: 中

4. 失敗ログの整形を追加する

対象モジュール:

  • command gate 実行結果のモデル
  • AI 差し戻しメッセージ生成
  • 実行ログ出力

実装内容:

  • command gate 失敗時に、AI が修正に使える形式で結果を渡す。
  • 例:
Quality gate failed: quality-check
Type: command
Command: ./.takt/quality-gates/check.sh
Cwd: .
Exit code: 1

Stdout:
...

Stderr:
...
  • 成功時は不要な stdout/stderr 全量を AI へ渡さない。
  • 既存の文字列 gate の表示・プロンプト生成は維持する。

5. 設定例を更新する

対象モジュール:

  • .takt/config.yaml
  • 関連ドキュメントまたは設定例が存在する場合はそのファイル

実装内容:

  • 既存の文字列 quality_gates と command gate が同居する例を追加する。
  • .takt/quality-gates/check.sh を使う例を示す。
  • 既存の文字列 gate が AI への指示であり、type: command がステップ完了時の機械実行 gate であることが分かる記述にする。

優先度: 低

6. サンプル shell 配置の扱いを整理する

対象モジュール:

  • .takt/quality-gates/
  • サンプルやテンプレート生成がある場合はその周辺

実装内容:

  • 必要に応じて .takt/quality-gates/check.sh のサンプルを追加する。
  • サンプルを追加する場合は、実行内容を現在の TAKT の既存確認コマンドに合わせる。

例:

#!/usr/bin/env bash
set -euo pipefail

npm run build
npm run lint
npm test
npm run test:e2e:mock

テスト方針

優先度: 高

追加・更新するテスト:

  • 設定読み込みテスト
    • quality_gates に文字列と { type: "command", ... } が混在できること
    • 既存の文字列 gate が壊れないこと
  • command gate 実行テスト
    • exit code 0 なら成功
    • exit code 1 など non-zero なら失敗
    • 失敗時に command / cwd / exit code / stdout / stderr が差し戻し情報に含まれること
  • worktree 同期テスト
    • .takt/quality-gates/ が再利用・リトライ時の同期対象になること
    • .takt/config.yaml の既存同期が維持されること

必要に応じて追加する統合テスト:

  • workflow_overrides.steps.implement.quality_gates に command gate を設定し、ステップ完了後に command が実行されること
  • command gate 失敗時に後続ステップへ進まず、AI 修正側へ戻ること

確認方法

最低限、以下を実行して確認する。

npm run build
npm run lint
npm test

worktree / workflow 実行に関係する変更が入るため、可能であれば以下も実行する。

npm run test:e2e:mock

手動確認例:

  1. .takt/quality-gates/check.sh を作成する。
  2. .takt/config.yamlworkflow_overrides.steps.implement.quality_gates に以下を追加する。
- type: command
  name: quality-check
  command: "./.takt/quality-gates/check.sh"
  timeout_ms: 300000
  1. check.sh が exit code 0 を返す場合、次の処理へ進むことを確認する。
  2. check.sh が exit code 1 を返す場合、AI への差し戻しに command 実行結果が含まれることを確認する。
  3. worktree 再利用・リトライ時にも .takt/quality-gates/check.sh が worktree 内に存在することを確認する。

Execution Report

Workflow takt-default completed successfully.

Closes #761

Summary by CodeRabbit

  • 新機能

    • ワークフローのエージェント手順で実行可能な「コマンド型品質ゲート」を追加。失敗時のログ保存・差し戻し・タイムアウト・出力制限に対応。
  • 設定

    • グローバル/プロジェクト設定に workflow_command_gates を追加し、カスタムスクリプト実行の許可制御を提供。
  • ドキュメント

    • YAMLスキーマとワークフロー資料を品質ゲート仕様と例で拡張。
  • テスト

    • コマンドゲートと関連フローの網羅的なテスト群を追加。
  • 動作変更

    • 品質ゲート失敗時はワークフローの進行を停止して失敗レスポンスを反映。

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

ワークフローの品質ゲートに type: command を追加し、設定スキーマ/型、YAML ローダーとポリシー検証、コマンド実行ランナー、失敗メッセージ整形、ワークフロー実行ループへの統合、worktree 同期、ドキュメントと広範なテスト群を導入しました。

Changes

Command Quality Gates

Layer / File(s) Summary
Type definitions and schema
src/core/models/..., src/core/models/schema-base.ts, src/core/models/config-schemas.ts
Adds CommandQualityGate and QualityGate types; normalizes raw timeout_mstimeoutMs in schemas; project/global config accepts workflow_command_gates.
Command execution & feedback
src/core/workflow/quality-gates/commandGateRunner.ts, .../commandGateMessage.ts, .../types.ts
Implements command runner with timeouts, output limits, env allowlist, log file output, and sanitized feedback formatting for failures.
Quality gates orchestration
src/core/workflow/quality-gates/qualityGateRunner.ts
Runs quality gates sequentially, skips string gates, on failure formats AgentResponse and returns { ok:false, response }.
Config normalization & policies
src/infra/config/*
Normalize/denormalize quality_gates objects, add workflow_command_gates policy resolution (custom_scripts), env specs, serializer/transforms and validation to reject command gates unless allowed.
Workflow engine integration
src/core/workflow/engine/*, src/core/workflow/types.ts, InstructionBuilder.ts
Wires runQualityGates into run loop and ParallelRunner; step results carry qualityGateFailure; InstructionBuilder injects only string gates into AI prompt.
Worktree sync & clone hooks
src/infra/task/projectLocalTaktSync.ts, src/infra/task/clone.ts
Syncs .takt/quality-gates into worktrees (excluding logs) and invokes sync after clone creation.
Docs & examples
builtins/*, docs/*
Adds YAML examples and docs explaining string vs command gates, execution semantics, and policy requirement.
Tests
src/__tests__/*
Extensive unit/integration tests for runner, formatting, loader/schema/policy, workflow integration, config save/load, env overrides, clone/sync behaviors.

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch takt/761/add-command-gate

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/infra/config/loaders/qualityGateOverrides.ts (1)

111-113: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Command gate の重複除去が参照同一性になっています。

Line 112 の new Set(gates) は object を値比較しないため、同内容の command gate がレイヤ間で重複実行されます。非冪等コマンドだと副作用を二重化します。文字列/command で正規化キーを作って重複判定してください。

修正例
-  // Deduplicate gates (same text = same gate)
-  const uniqueGates = Array.from(new Set(gates));
+  // Deduplicate gates by semantic identity
+  const seen = new Set<string>();
+  const uniqueGates: QualityGate[] = [];
+  for (const gate of gates) {
+    const key =
+      typeof gate === 'string'
+        ? `s:${gate}`
+        : `c:${gate.type}:${gate.name ?? ''}:${gate.command}:${gate.cwd ?? ''}:${gate.timeoutMs ?? ''}`;
+    if (seen.has(key)) {
+      continue;
+    }
+    seen.add(key);
+    uniqueGates.push(gate);
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infra/config/loaders/qualityGateOverrides.ts` around lines 111 - 113, The
current deduplication uses new Set(gates) which compares by reference so
identical command gate objects across layers aren’t deduped; change
deduplication to build a normalized key for each gate (e.g., serialize its
command string and relevant fields such as args/env or a joined "command|args"
token) and use a Map or object to keep the first seen gate per key, then produce
uniqueGates from the Map.values(); update the logic where gates is read and
where uniqueGates is produced to use this key-based de-duplication so
semantically-equal command gates aren’t executed twice.
src/infra/task/projectLocalTaktSync.ts (1)

85-89: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

quality-gates/logs が同期時に削除されてしまいます

sourceEntries から logs を除外している一方、Line 86 の削除フェーズで除外考慮がないため、targetDir/logs が「未存在扱い」で消されます。生成物ディレクトリを同期対象外にする意図と逆挙動です。

修正案
-  for (const entry of fs.readdirSync(targetDir)) {
+  for (const entry of fs.readdirSync(targetDir)) {
+    if (shouldSkipTaktSyncEntry(sourceDir, entry)) {
+      continue;
+    }
     if (!sourceEntries.has(entry)) {
       removePath(path.join(targetDir, entry));
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infra/task/projectLocalTaktSync.ts` around lines 85 - 89, The deletion
loop mistakenly removes excluded directories because it iterates
fs.readdirSync(targetDir) without applying shouldSkipTaktSyncEntry; update the
loop in projectLocalTaktSync.ts to skip entries that should be excluded (call
shouldSkipTaktSyncEntry(targetDir, entry) or reuse the same exclusion logic)
before calling removePath on path.join(targetDir, entry) so that excluded names
like "logs" are not treated as missing and deleted.
src/__tests__/system-workflow-schema.test.ts (1)

1037-1060: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

command gate オブジェクトの受理ケースも固定してください。

このテストで通している quality_gates は従来の文字列だけなので、新規の { type: 'command', ... } 形式が step schema 側で壊れてもここでは検出できません。少なくとも 1 件は文字列 gate と command gate を混在させたケースを追加しておきたいです。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/system-workflow-schema.test.ts` around lines 1037 - 1060, The
test currently validates only string quality gates so add a case that mixes a
string gate and a command gate object to ensure the schema accepts both forms;
update the test named "structured_output.schema_ref と delay_before_ms を受け付ける" to
include quality_gates: ['Review before finishing', { type: 'command', name:
'run_lint', args: { fix: true } }] (or similar valid command gate shape) and
assert the parsed step. Use the existing WorkflowStepRawSchema.safeParse call
and the step variable assertions (e.g., expect(step.quality_gates)).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/engine-rate-limit-fallback.test.ts`:
- Around line 683-745: The test may pass without the command gate ever running;
after awaiting engine.run() add an assertion that the gate marker file was
created to guarantee the command gate executed — check
fs.existsSync(gateMarkerPath) (or require/import fs and use fs.existsSync) and
assert it is true (e.g., expect(fs.existsSync(gateMarkerPath)).toBe(true)) so
the test cannot be a false positive; reference the existing gateMarkerPath
variable and the engine.run() call when adding this assertion.

In `@src/__tests__/it-workflow-loader.test.ts`:
- Around line 1298-1441: Add tests in the same suite to cover
workflow_command_gates precedence by exercising loadWorkflowConfig with
conflicting global vs project settings: create one test where global config
enables command gates (global workflow_command_gates: { custom_scripts: true })
but the project's .takt/config.yaml explicitly sets
workflow_command_gates.custom_scripts: false and assert loadWorkflowConfig
rejects command gates (throws /workflow_command_gates\.custom_scripts/ or
step-specific rejection); add another test where global enables but project has
an empty object (workflow_command_gates: {}) and assert the effective behavior
(allow or reject) matches policy by checking loaded config and step. Use the
existing patterns in the file (mkdirSync, writeFileSync, loadWorkflowConfig,
expect(...).toThrow / expect(...).not.toBeNull) and the same YAML templates
(command-gate.yaml / parallel-command-gate-allowed.yaml) to implement these two
cases.

In `@src/core/workflow/quality-gates/commandGateRunner.ts`:
- Around line 202-229: The stdout and stderr handlers currently track output
size separately using stdoutBytes and stderrBytes, allowing each stream to reach
the limit independently; change to a single shared counter (e.g., totalBytes)
used by both handlers and by appendOutputWithinLimit so any stream pushing the
cumulative total over the limit sets outputLimitExceeded and calls
terminateProcess immediately; update references to stdoutBytes/stderrBytes to
use totalBytes and ensure both child.stdout?.on('data', ...) and
child.stderr?.on('data', ...) call appendOutputWithinLimit with the shared total
and update that shared variable from the returned bytes.

---

Outside diff comments:
In `@src/__tests__/system-workflow-schema.test.ts`:
- Around line 1037-1060: The test currently validates only string quality gates
so add a case that mixes a string gate and a command gate object to ensure the
schema accepts both forms; update the test named "structured_output.schema_ref と
delay_before_ms を受け付ける" to include quality_gates: ['Review before finishing', {
type: 'command', name: 'run_lint', args: { fix: true } }] (or similar valid
command gate shape) and assert the parsed step. Use the existing
WorkflowStepRawSchema.safeParse call and the step variable assertions (e.g.,
expect(step.quality_gates)).

In `@src/infra/config/loaders/qualityGateOverrides.ts`:
- Around line 111-113: The current deduplication uses new Set(gates) which
compares by reference so identical command gate objects across layers aren’t
deduped; change deduplication to build a normalized key for each gate (e.g.,
serialize its command string and relevant fields such as args/env or a joined
"command|args" token) and use a Map or object to keep the first seen gate per
key, then produce uniqueGates from the Map.values(); update the logic where
gates is read and where uniqueGates is produced to use this key-based
de-duplication so semantically-equal command gates aren’t executed twice.

In `@src/infra/task/projectLocalTaktSync.ts`:
- Around line 85-89: The deletion loop mistakenly removes excluded directories
because it iterates fs.readdirSync(targetDir) without applying
shouldSkipTaktSyncEntry; update the loop in projectLocalTaktSync.ts to skip
entries that should be excluded (call shouldSkipTaktSyncEntry(targetDir, entry)
or reuse the same exclusion logic) before calling removePath on
path.join(targetDir, entry) so that excluded names like "logs" are not treated
as missing and deleted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d9356dd1-44c7-40e7-9742-7122d3a94e22

📥 Commits

Reviewing files that changed from the base of the PR and between 0b91428 and 04d5c37.

⛔ Files ignored due to path filters (1)
  • .takt/config.yaml is excluded by !.takt/**
📒 Files selected for processing (55)
  • builtins/en/config.yaml
  • builtins/ja/config.yaml
  • builtins/skill-codex/references/yaml-schema.md
  • builtins/skill/references/yaml-schema.md
  • docs/configuration.ja.md
  • docs/configuration.md
  • docs/workflows.ja.md
  • docs/workflows.md
  • src/__tests__/clone.test.ts
  • src/__tests__/commandQualityGateRunner.test.ts
  • src/__tests__/config-env-overrides.test.ts
  • src/__tests__/engine-parallel.test.ts
  • src/__tests__/engine-rate-limit-fallback.test.ts
  • src/__tests__/globalConfig-defaults.test.ts
  • src/__tests__/globalConfig.test.ts
  • src/__tests__/it-instruction-builder.test.ts
  • src/__tests__/it-workflow-loader.test.ts
  • src/__tests__/models.test.ts
  • src/__tests__/projectConfig.test.ts
  • src/__tests__/projectLocalTaktSync.test.ts
  • src/__tests__/qualityGateOverrides.test.ts
  • src/__tests__/system-workflow-schema.test.ts
  • src/__tests__/workflow-call-schema.test.ts
  • src/__tests__/workflow-run-loop-command-gates.test.ts
  • src/core/models/config-schemas.ts
  • src/core/models/config-types.ts
  • src/core/models/index.ts
  • src/core/models/schema-base.ts
  • src/core/models/types.ts
  • src/core/models/workflow-types.ts
  • src/core/workflow/engine/ParallelRunner.ts
  • src/core/workflow/engine/WorkflowEngine.ts
  • src/core/workflow/engine/WorkflowEngineSetup.ts
  • src/core/workflow/engine/WorkflowRunLoop.ts
  • src/core/workflow/instruction/InstructionBuilder.ts
  • src/core/workflow/quality-gates/commandGateMessage.ts
  • src/core/workflow/quality-gates/commandGateRunner.ts
  • src/core/workflow/quality-gates/qualityGateRunner.ts
  • src/core/workflow/quality-gates/types.ts
  • src/core/workflow/types.ts
  • src/infra/config/configNormalizers.ts
  • src/infra/config/env/global-current-env-specs.ts
  • src/infra/config/env/project-current-env-specs.ts
  • src/infra/config/global/globalConfigCore.ts
  • src/infra/config/global/globalConfigSerializer.ts
  • src/infra/config/loaders/qualityGateOverrides.ts
  • src/infra/config/loaders/workflowFileLoader.ts
  • src/infra/config/loaders/workflowNormalizationPolicies.ts
  • src/infra/config/loaders/workflowParser.ts
  • src/infra/config/loaders/workflowStepNormalizer.ts
  • src/infra/config/project/projectConfig.ts
  • src/infra/config/project/projectConfigTransforms.ts
  • src/infra/config/traced/tracedConfigSchema.ts
  • src/infra/task/clone.ts
  • src/infra/task/projectLocalTaktSync.ts

Comment thread src/__tests__/engine-rate-limit-fallback.test.ts
Comment thread src/__tests__/it-workflow-loader.test.ts
Comment thread src/core/workflow/quality-gates/commandGateRunner.ts
@nrslib
Copy link
Copy Markdown
Owner Author

nrslib commented May 27, 2026

レビューしました。GitHub 上は mergeable で CI も通っていますが、現時点ではまだマージしない方がよいです。

主な理由:

  1. src/core/workflow/quality-gates/commandGateRunner.tscwd 境界チェックが isPathInside(projectRoot, cwd) になっており、実パスを見ていません。cwd は project root 内に制限する仕様ですが、project root 配下の symlink が外部ディレクトリを指す場合、字面上は内側として通ります。command gate は任意コマンド実行なので、ここは isRealPathInside ベースで検証するべきです。

  2. 手元 macOS で対象テストが落ちました。

npm test -- --run src/__tests__/commandQualityGateRunner.test.ts src/__tests__/workflow-run-loop-command-gates.test.ts src/__tests__/projectLocalTaktSync.test.ts src/__tests__/it-workflow-loader.test.ts

失敗箇所は src/__tests__/commandQualityGateRunner.test.ts の relative cwd テストで、期待値が /var/...、実際の process.cwd()/private/var/... になっています。CI Linux では出にくいですが、実パス正規化の不足と同根に見えます。

  1. src/infra/config/loaders/qualityGateOverrides.tsnew Set(gates) は object gate を参照同一性でしか重複排除しません。同じ command gate が global/project/YAML など複数レイヤから入ると二重実行されます。非冪等な gate だと副作用が二重になります。

CodeRabbit の quality-gates/logs が同期時に消えるという指摘は、現行実装とテストを見る限り「生成ログを retry worktree に持ち込まない」意図なので、そのままブロッカーとは見ていません。

結論: 少なくとも cwd の実パス境界チェックと macOS で落ちるテストは直してからマージ判断したいです。

@nrslib
Copy link
Copy Markdown
Owner Author

nrslib commented May 27, 2026

Summary

タスク指示書: PR #763 command gate のレビュー指摘対応

目的

quality_gates の command gate 実装に対するレビュー指摘を確認し、現在のコードに残っている問題を修正する。特に、任意コマンド実行に関わる cwd 境界チェック、macOS 実パス差異によるテスト失敗、command gate 重複排除、出力上限、テスト不足を解消する。

参照資料

最初に以下を確認すること。

  • src/core/workflow/quality-gates/commandGateRunner.ts
  • src/__tests__/commandQualityGateRunner.test.ts
  • src/infra/config/loaders/qualityGateOverrides.ts
  • src/__tests__/qualityGateOverrides.test.ts
  • src/__tests__/engine-rate-limit-fallback.test.ts
  • src/__tests__/it-workflow-loader.test.ts
  • src/__tests__/system-workflow-schema.test.ts
  • src/infra/task/projectLocalTaktSync.ts
  • src/__tests__/projectLocalTaktSync.test.ts

関連箇所の特定には以下も使用すること。

rg "isPathInside|isRealPathInside|realpath|quality_gates|qualityGate|workflow_command_gates|stdoutBytes|stderrBytes|outputLimitExceeded"

優先度: 高

1. command gate の cwd 境界チェックを実パスベースに修正する

対象モジュール:

  • src/core/workflow/quality-gates/commandGateRunner.ts
  • src/__tests__/commandQualityGateRunner.test.ts

実装内容:

  • command gate の cwd が project root 内に収まるかの判定を、文字列上のパスではなく実パスで行う。
  • project root 配下の symlink が外部ディレクトリを指す場合、cwd として拒否されるようにする。
  • cwd 省略時、相対 cwd 指定時、絶対 cwd 指定時の既存挙動を維持する。
  • macOS の /var/private/var の差異でテストが落ちないよう、期待値と実行時 process.cwd() の比較を実パス正規化後の値に揃える。

追加・更新するテスト:

  • project root 配下の symlink が外部ディレクトリを指す場合に command gate が拒否されること。
  • relative cwd テストが macOS でも Linux でも安定して通ること。
  • 既存の project root 内 cwd は引き続き許可されること。

再現手順:

npm test -- --run src/__tests__/commandQualityGateRunner.test.ts src/__tests__/workflow-run-loop-command-gates.test.ts src/__tests__/projectLocalTaktSync.test.ts src/__tests__/it-workflow-loader.test.ts

2. command gate の重複排除を値ベースに修正する

対象モジュール:

  • src/infra/config/loaders/qualityGateOverrides.ts
  • src/__tests__/qualityGateOverrides.test.ts

実装内容:

  • new Set(gates) のような参照同一性ベースの dedupe をやめる。
  • 文字列 gate は文字列内容で重複排除する。
  • command gate は意味的に同一なフィールドから正規化キーを作り、同内容の object gate を重複排除する。
  • 重複排除後の順序は、最初に現れた gate の順序を維持する。
  • 文字列 gate と command gate は別種として扱う。

最低限キーに含める項目:

  • type
  • name
  • command
  • cwd
  • timeoutMs または現行コード上の正規化後フィールド

追加・更新するテスト:

  • 複数レイヤから同じ command gate object が入っても 1 件になること。
  • 同じ文字列 gate が重複しても 1 件になる既存挙動が維持されること。
  • command または cwd が異なる command gate は別 gate として残ること。

優先度: 中

3. command gate 出力上限を stdout/stderr 合算で管理する

対象モジュール:

  • src/core/workflow/quality-gates/commandGateRunner.ts
  • src/__tests__/commandQualityGateRunner.test.ts

実装内容:

  • stdoutBytesstderrBytes の個別管理をやめ、合計出力バイト数を 1 つのカウンタで管理する。
  • stdout/stderr のどちらから出力されても、合算値が上限に到達した時点で outputLimitExceeded を立て、プロセスを停止する。
  • 既存の timeout、exit code、stdout/stderr 収集、失敗メッセージ生成の挙動を壊さない。

追加・更新するテスト:

  • stdout と stderr の合計が上限を超えた場合に停止されること。
  • stdout 単独、stderr 単独の既存上限テストが引き続き通ること。

4. command gate 実行を実証するテストアサーションを追加する

対象モジュール:

  • src/__tests__/engine-rate-limit-fallback.test.ts

実装内容:

  • 該当テストで engine.run() 後に gateMarkerPath の存在確認を追加する。
  • Quality gate failed が出ないことだけでなく、command gate が実際に少なくとも 1 回実行されたことを固定する。

追加・更新するテスト:

  • 既存テスト内で existsSync(gateMarkerPath) または同等の確認を行う。

5. workflow_command_gates の global/project 優先順位テストを追加する

対象モジュール:

  • src/__tests__/it-workflow-loader.test.ts

実装内容:

  • global config が command gate を許可し、project config が明示的に拒否する場合、command gate を含む workflow load が拒否されることをテストする。
  • global config が command gate を許可し、project config が空 object の場合、現在のマージポリシーどおりの有効設定になることをテストする。
  • 期待値は実装コードで現在のポリシーを確認して固定する。

追加・更新するテスト:

  • global workflowCommandGates.customScripts: true + project workflow_command_gates.custom_scripts: false
  • global workflowCommandGates.customScripts: true + project workflow_command_gates: {}

6. workflow step schema の mixed quality gate 受理テストを追加する

対象モジュール:

  • src/__tests__/system-workflow-schema.test.ts

実装内容:

  • quality_gates に文字列 gate と { type: "command", command: "..." } が混在するケースを追加する。
  • 既存の WorkflowStepRawSchema.safeParse パターンに従い、parse 後の quality_gates が期待どおり保持されることを確認する。

優先度: 低

7. quality-gates/logs 同期削除指摘の現状確認と必要時修正

対象モジュール:

  • src/infra/task/projectLocalTaktSync.ts
  • src/__tests__/projectLocalTaktSync.test.ts

実装内容:

  • quality-gates/logs が同期対象外として扱われている現在の意図と実装を確認する。
  • 現在のコードで、生成ログを retry worktree に持ち込まないための除外挙動がテストで固定されている場合は、その挙動を維持する。
  • 現在のコード上で、除外すべき生成物以外まで誤削除する問題が確認できた場合のみ修正する。
  • 修正またはスキップ理由を最終レポートに明記する。

確認方法

最低限、以下を実行して確認する。

npm test -- --run src/__tests__/commandQualityGateRunner.test.ts src/__tests__/workflow-run-loop-command-gates.test.ts src/__tests__/projectLocalTaktSync.test.ts src/__tests__/it-workflow-loader.test.ts src/__tests__/qualityGateOverrides.test.ts src/__tests__/engine-rate-limit-fallback.test.ts src/__tests__/system-workflow-schema.test.ts
npm run build
npm run lint
npm test

可能であれば以下も実行する。

npm run test:e2e:mock

完了条件

  • cwd 境界チェックが実パスベースになり、project root 配下 symlink 経由の外部 cwd が拒否される。
  • macOS の /var/private/var 差異で対象テストが失敗しない。
  • 同内容の command gate object が複数レイヤから入っても重複実行されない。
  • command gate の出力上限が stdout/stderr 合算で適用される。
  • 指摘されたテスト不足が追加されている。
  • 実行した検証コマンドと結果を最終レポートに記載する。
  • 各レビュー指摘について、対応したか、スキップしたか、理由を最終レポートに要約する。

Execution Report

Workflow takt-default completed successfully.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/workflow/quality-gates/commandGateRunner.ts (1)

60-73: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

出力上限判定が「超過」ではなく「到達」で失敗しています。

Line 60 の条件が < MAX_OUTPUT_BYTES になっており、合計出力がちょうど上限のケースでも outputLimitExceeded になります。要件どおり「超過時のみ失敗」に合わせるなら <= にしてください(境界テスト側の期待値も合わせて更新が必要です)。

修正案
-  if (outputBytes + chunkBytes < MAX_OUTPUT_BYTES) {
+  if (outputBytes + chunkBytes <= MAX_OUTPUT_BYTES) {
     return {
       output: `${current}${chunk}`,
       bytes: outputBytes + chunkBytes,
       exceeded: false,
     };
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/workflow/quality-gates/commandGateRunner.ts` around lines 60 - 73,
The slice that decides whether adding chunk triggers the output limit uses the
condition `if (outputBytes + chunkBytes < MAX_OUTPUT_BYTES)` which treats an
exact-equal-to limit as "exceeded"; change that condition to `<=` so an exact
match is allowed (i.e., `if (outputBytes + chunkBytes <= MAX_OUTPUT_BYTES)`),
ensure when returning the success branch you return bytes as `outputBytes +
chunkBytes`, and keep the overflow branch logic using `MAX_OUTPUT_BYTES`,
`boundedChunk`, and `OUTPUT_LIMIT_MARKER` unchanged; update the related boundary
tests that expect "exceeded" to instead expect success on exact-equality.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/core/workflow/quality-gates/commandGateRunner.ts`:
- Around line 60-73: The slice that decides whether adding chunk triggers the
output limit uses the condition `if (outputBytes + chunkBytes <
MAX_OUTPUT_BYTES)` which treats an exact-equal-to limit as "exceeded"; change
that condition to `<=` so an exact match is allowed (i.e., `if (outputBytes +
chunkBytes <= MAX_OUTPUT_BYTES)`), ensure when returning the success branch you
return bytes as `outputBytes + chunkBytes`, and keep the overflow branch logic
using `MAX_OUTPUT_BYTES`, `boundedChunk`, and `OUTPUT_LIMIT_MARKER` unchanged;
update the related boundary tests that expect "exceeded" to instead expect
success on exact-equality.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a64ee529-0a79-42a3-9236-67978fe9c6c7

📥 Commits

Reviewing files that changed from the base of the PR and between 04d5c37 and 5ee3395.

📒 Files selected for processing (9)
  • src/__tests__/commandQualityGateRunner.test.ts
  • src/__tests__/engine-rate-limit-fallback.test.ts
  • src/__tests__/it-workflow-loader.test.ts
  • src/__tests__/qualityGateOverrides.test.ts
  • src/__tests__/system-workflow-schema.test.ts
  • src/core/models/quality-gate-defaults.ts
  • src/core/workflow/quality-gates/commandGateMessage.ts
  • src/core/workflow/quality-gates/commandGateRunner.ts
  • src/infra/config/loaders/qualityGateOverrides.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

タスク指示書: quality_gates に command gate を追加する

1 participant