From 51a1aa3ddc22b2a250e1f99760f979182098822f Mon Sep 17 00:00:00 2001 From: root Date: Fri, 24 Apr 2026 06:24:38 -0500 Subject: [PATCH] =?UTF-8?q?gateway/execution=5Floop:=20wire=20truth=20gate?= =?UTF-8?q?=20(Phase=2042=20step=206=20=E2=80=94=20was=20TODO)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Line 156 had `// --- (6) TRUTH GATE — PORT FROM Phase 42 (TODO) ---` sitting empty for weeks. The Blocked outcome variant existed but was marked #[allow(dead_code)] because nothing constructed it. Now: before the main turn loop, evaluate truth rules for the request's task_class against self.req.spec. Any rule whose condition holds AND whose action is Reject/Block short-circuits to RespondOutcome::Blocked with a reason citing the rule_id. Downstream finalize() already matched Blocked at line 848 (maps to truth_block category in kb row). Mirrors the queryd/service.rs SQL gate from 9cc0ceb — same truth::evaluate contract, same short-circuit pattern, same reason shape. For staffing.fill that means rules like deadline-required and budget-required now enforce at /v1/respond entry. Workspace warnings unchanged at 11. Blocked variant no longer needs #[allow(dead_code)] because it's now constructed. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/gateway/src/execution_loop/mod.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/gateway/src/execution_loop/mod.rs b/crates/gateway/src/execution_loop/mod.rs index a45e7af..e3da7b7 100644 --- a/crates/gateway/src/execution_loop/mod.rs +++ b/crates/gateway/src/execution_loop/mod.rs @@ -82,7 +82,7 @@ pub struct Fill { pub enum RespondOutcome { Ok { artifact: serde_json::Value, log: Vec }, Failed { reason: String, log: Vec }, - #[allow(dead_code)] // reserved for Phase 42 truth-gate (step 6) + // Constructed by the truth-gate check in run_inner (step 6, 2026-04-24). Blocked { reason: String, log: Vec }, } @@ -153,7 +153,21 @@ impl ExecutionLoop { .as_deref().unwrap_or(DEFAULT_REVIEWER_MODEL).to_string(); let max_turns = self.req.max_turns.unwrap_or(DEFAULT_MAX_TURNS); - // --- (6) TRUTH GATE — PORT FROM Phase 42 (TODO) --- + // --- (6) TRUTH GATE — Phase 42 wiring (2026-04-24) --- + // Evaluate truth rules for the request's task_class against a + // ctx built from the spec. Any rule whose condition holds AND + // whose action is Reject/Block short-circuits to Blocked before + // the executor loop runs. Mirrors queryd/service.rs SQL gate. + let truth_store = truth::default_truth_store(); + for outcome in truth_store.evaluate(&self.req.task_class, &self.req.spec) { + if !outcome.passed { continue; } + if let truth::RuleAction::Reject { message } | truth::RuleAction::Block { message } = &outcome.action { + let reason = format!("truth rule {} blocked: {message}", outcome.rule_id); + self.append(LogEntry::new(0, "system", "truth", "block", + serde_json::json!({ "rule_id": outcome.rule_id, "reason": reason.clone() }))); + return Ok(RespondOutcome::Blocked { reason, log: self.log.clone() }); + } + } // --- (1) PLAYBOOK BOOST --- let boost = self.fetch_playbook_boost(&self.req.operation).await.unwrap_or_default();