Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .takt/facets/instructions/review-simplicity.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The diff has been pre-collected by push-runner (Rust exe) and saved to `.takt/re
**Read this file first** using the Read tool. This is the authoritative review target.
Do NOT run `git diff` or `jj diff` yourself -- the file already contains the correct diff scope.

### Optional: lint-screen pre-pass (Phase c §8.E, ADR-038 試験運用)

If `.takt/lint-screen-report.md` exists, push-runner has already run a mistral:7b lint pre-pass on the diff. Read this file as **supplementary context** (treat as advisory, not authoritative):

- Coverage: rule names from a fixed canonical list (`unused-import` / `no-var` / `no-unused-vars` / `magic-number` / `dead-code` / `deep-nesting` / `complexity`)
- Quality: agreement 75% with Claude baseline (Phase b' conditional GO) — false positives and recall misses are expected
- Use it to:
- Cross-check anomalies you already noticed (consensus signal)
- **Skip dimensions** the lint-screen already covered (avoid duplicate findings of unused-import / magic-number etc.)
- Do NOT use it to:
- Adopt findings verbatim without diff verification
- Override your own judgment on subjective anomalies (deep-nesting boundary, complexity)

If the report shows `screen_decision: informational` and zero findings, that is a **weak signal of a clean diff** — still review yourself, but you can be more concise in approval rationale.

## Determinism layer guarantees (do NOT duplicate)

The following dimensions are enforced by deterministic hooks at write time and by `fix-metrics-check.ps1` during fix iterations. Skip them — flagging them duplicates the deterministic layer and produces noise:
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 21 additions & 1 deletion push-runner-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

[quality_gate]
parallel = true
step_timeout = 120
# step_timeout = 180s (Phase b' end-to-end test の `cargo test -- --ignored` が
# mistral:7b への 12 件 invoke で 120s 境界に達するため拡大、PR #132 で実証)
step_timeout = 180

[[quality_gate.groups]]
name = "lint"
Expand Down Expand Up @@ -35,6 +37,24 @@ commands = [
command = "jj diff -r @"
output_path = ".takt/review-diff.txt"

# ---------------------------------------------------------------------------
# [lint_screen] — Phase c (§8.E lint screen facet) — ADR-038 試験運用配下。
# diff を mistral:7b に流して lint 一次フィルタの所見を markdown として出力する。
# 詳細: docs/adr/adr-038-local-llm-finding-classification.md
# default OFF。手動で enabled = true にしたうえで Ollama 起動 + cli-finding-classifier.exe 配備を確認する。
# Phase b' agreement 75% (conditional GO) のため gating はせず report のみ出力。
# Ollama down / timeout / diff 過大時は skip + warn (push を block しない)。
# ---------------------------------------------------------------------------
[lint_screen]
enabled = false
# 以下は default 値、明示しなくてもよいが意図を残すなら明示推奨
exe_path = ".claude/cli-finding-classifier.exe"
model = "mistral:7b"
endpoint = "http://localhost:11434"
timeout_secs = 60
max_diff_lines = 5000
output_path = ".takt/lint-screen-report.md"

[takt]
workflow = "pre-push-review"
task = "pre-push review"
Expand Down
1 change: 1 addition & 0 deletions src/cli-push-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.8"
lib-jj-helpers = { path = "../lib-jj-helpers" }

Expand Down
25 changes: 25 additions & 0 deletions src/cli-push-runner/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,38 @@ use std::path::{Path, PathBuf};

pub(crate) const DEFAULT_STEP_TIMEOUT_SECS: u64 = 120;
pub(crate) const DEFAULT_PUSH_TIMEOUT_SECS: u64 = 300;
pub(crate) const DEFAULT_LINT_SCREEN_TIMEOUT_SECS: u64 = 60;
pub(crate) const DEFAULT_LINT_SCREEN_MAX_DIFF_LINES: usize = 5000;
pub(crate) const DEFAULT_LINT_SCREEN_MODEL: &str = "mistral:7b";
pub(crate) const DEFAULT_LINT_SCREEN_ENDPOINT: &str = "http://localhost:11434";
pub(crate) const DEFAULT_LINT_SCREEN_EXE_PATH: &str = ".claude/cli-finding-classifier.exe";
pub(crate) const DEFAULT_LINT_SCREEN_OUTPUT_PATH: &str = ".takt/lint-screen-report.md";

#[derive(Deserialize)]
pub(crate) struct Config {
pub(crate) quality_gate: QualityGateConfig,
pub(crate) diff: Option<DiffConfig>,
pub(crate) lint_screen: Option<LintScreenConfig>,
pub(crate) takt: TaktConfig,
pub(crate) push: PushConfig,
}

/// Phase c (§8.E lint screen facet) — pre-push 時に diff を mistral:7b に流して
/// lint 一次フィルタの所見を `.takt/lint-screen-report.md` として出力する。
///
/// `enabled = false` の場合は完全 no-op (default OFF, 試験運用)。
/// Ollama down / timeout / diff 過大時は skip + warn (push を block しない)。
#[derive(Deserialize)]
pub(crate) struct LintScreenConfig {
pub(crate) enabled: bool,
pub(crate) exe_path: Option<String>,
pub(crate) model: Option<String>,
pub(crate) endpoint: Option<String>,
pub(crate) timeout_secs: Option<u64>,
pub(crate) max_diff_lines: Option<usize>,
pub(crate) output_path: Option<String>,
}

#[derive(Deserialize)]
pub(crate) struct QualityGateConfig {
pub(crate) parallel: Option<bool>,
Expand Down Expand Up @@ -265,6 +288,7 @@ command = "echo push"
groups: vec![],
},
diff: None,
lint_screen: None,
takt: TaktConfig {
workflow: "w".into(),
task: "t".into(),
Expand Down Expand Up @@ -293,6 +317,7 @@ command = "echo push"
}],
},
diff: None,
lint_screen: None,
takt: TaktConfig {
workflow: "w".into(),
task: "t".into(),
Expand Down
47 changes: 28 additions & 19 deletions src/cli-push-runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::time::Instant;

use config::load_config;
use log::log_info;
use stages::{run_diff, run_push, run_quality_gate, run_takt, DiffResult};
use stages::{run_diff, run_lint_screen, run_push, run_quality_gate, run_takt, DiffResult};

const EXIT_SUCCESS: i32 = 0;
const EXIT_QUALITY_GATE_FAILURE: i32 = 1;
Expand All @@ -34,6 +34,29 @@ const EXIT_PUSH_FAILURE: i32 = 3;
const EXIT_CONFIG_ERROR: i32 = 4;
const EXIT_DIFF_FAILURE: i32 = 5;

/// diff stage を実行し lint-screen を呼び出す。
/// Ok(skip_takt) で成功、 Err(exit_code) で pipeline 中断。
fn run_diff_and_lint_screen(config: &config::Config) -> Result<bool, i32> {
let Some(diff_config) = &config.diff else {
return Ok(false);
};
let diff_path = match run_diff(diff_config) {
DiffResult::HasContent => diff_config.output_path.as_str(),
DiffResult::Empty => {
log_info("diff が空のためレビューをスキップして push に進みます。");
return Ok(true);
}
DiffResult::Error => {
log_info("パイプライン中断: diff 取得失敗。");
return Err(EXIT_DIFF_FAILURE);
}
};
if let Some(lint_screen_config) = &config.lint_screen {
run_lint_screen(lint_screen_config, diff_path);
}
Ok(false)
}

fn run_pipeline() -> i32 {
let start = Instant::now();

Expand All @@ -52,35 +75,21 @@ fn run_pipeline() -> i32 {
config.takt.workflow,
));

// Stage 1: quality_gate
if !run_quality_gate(&config.quality_gate) {
log_info("パイプライン中断: quality_gate 失敗。問題を修正して再実行してください。");
return EXIT_QUALITY_GATE_FAILURE;
}

// Stage 1.5: diff
let mut skip_takt = false;
if let Some(diff_config) = &config.diff {
match run_diff(diff_config) {
DiffResult::HasContent => {}
DiffResult::Empty => {
log_info("diff が空のためレビューをスキップして push に進みます。");
skip_takt = true;
}
DiffResult::Error => {
log_info("パイプライン中断: diff 取得失敗。");
return EXIT_DIFF_FAILURE;
}
}
}
let skip_takt = match run_diff_and_lint_screen(&config) {
Ok(skip) => skip,
Err(code) => return code,
};

// Stage 2: takt
if !skip_takt && !run_takt(&config.takt) {
log_info("パイプライン中断: takt ワークフロー失敗。");
return EXIT_TAKT_FAILURE;
}

// Stage 3: push
if !run_push(&config.push) {
log_info("パイプライン中断: push 失敗。");
return EXIT_PUSH_FAILURE;
Expand Down
Loading