auditor + aibridge: 6 fixes from Opus 4.7 self-audit on PR #11
lakehouse/auditor 16 blocking issues: cloud: claim not backed — "Verified end-to-end:"

The kimi_architect auditor on commit 00c8408 ran with auto-promotion
to claude-opus-4-7 (diff > 100k chars), produced 10 grounded
findings, 1 BLOCK + 6 WARN + 3 INFO. This commit lands 6 of them; 3
are skipped (false positives or out-of-scope cleanup deferred).

LANDED:

1. kimi_architect.ts:144  empty-parse cache poisoning. When parseFindings
   returns 0 findings (markdown shape changed, prompt too big, regex
   missed every block), the verdict was still persisted with empty
   findings, and the 24h TTL cache short-circuited every subsequent
   audit with a useless "0 findings" hit. Fix: only persist when
   findings.length > 0; metrics still appended unconditionally.

2. kimi_architect.ts:122  outage negative-cache. When callKimi throws
   (network error, gateway 502, rate limit), we returned skipFinding
   but didn't note the outage anywhere. Every audit cycle within the
   24h TTL hammered the dead upstream. Fix: write a sentinel file
   `<verdict>.outage` on failure with 10-min TTL; future calls within
   that window short-circuit immediately.

3. kimi_architect.ts:331  mkdir(join(p, "..")) -> dirname(p). The
   "/.." idiom resolved correctly via Node path normalization but
   was non-idiomatic and breaks if the path ever has trailing dots.
   Both Haiku and Opus self-audits flagged it.

4. inference.ts:202  N=3 consensus latency double/triple-count.
   `totalLatencyMs += run.latency_ms` summed across THREE parallel
   `Promise.all` calls — wall-clock is bounded by the slowest, not
   the sum. Renamed to `maxLatencyMs` using `Math.max`. Telemetry now
   reports actual wall-clock instead of 3x reality.

5. continuation.rs:198,199,230,231  i64/u64 -> u32 saturating cast.
   `resp.tokens_evaluated as u32` truncates bits when source > u32::MAX
   instead of saturating. Fix: u32::try_from(...).unwrap_or(u32::MAX)
   wraps the cast in a real saturate. Applied to both the empty-retry
   loop and the structural-completion continuation loop.

SKIPPED:

- BLOCK at Cargo.lock:8911 "validator-not-in-workspace" — confabulation.
  The diff Opus saw was truncated mid-line; validator IS in
  Cargo.toml workspace members. Real-world MAX_DIFF_CHARS=180k
  edge case to watch as we feed more big diffs.
- WARN at kimi_architect.ts:248 regex absolute-path edge case — minor,
  doesn't affect grounding rate observed so far.
- INFO at inference.ts:606 "dead reconstruction loop" — Opus misread.
  The Promise.all worker fills `summaries[]`; the second loop builds
  a sequential `scratchpad` string from those. Two distinct
  operations, not redundant.

Verification:
  bun build auditor/checks/{kimi_architect,inference}.ts   compiles
  cargo check -p aibridge                                  green
  cargo build --release -p gateway                          green
  systemctl restart lakehouse.service lakehouse-auditor.service  active

Next audit cycle (~90s after push) will run on the new diff and
exercise the negative-cache + dirname + maxLatencyMs paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-27 07:10:43 -05:00
co-authored by Claude Opus 4.7
parent 00c8408335
commit 454da15301
3 changed files with 61 additions and 21 deletions
+7 -4
View File
@@ -195,8 +195,11 @@ pub async fn generate_continuable<G: TextGenerator>(
let req = make_request(opts, prompt.to_string(), current_max);
let resp = generator.generate_text(req).await?;
calls += 1;
prompt_tokens = prompt_tokens.saturating_add(resp.tokens_evaluated.unwrap_or(0) as u32);
completion_tokens = completion_tokens.saturating_add(resp.tokens_generated.unwrap_or(0) as u32);
// u32::try_from saturates at u32::MAX instead of silently
// truncating bits when tokens_evaluated/_generated comes back
// as a u64 > 4 billion. Caught 2026-04-27 by Opus self-audit.
prompt_tokens = prompt_tokens.saturating_add(u32::try_from(resp.tokens_evaluated.unwrap_or(0)).unwrap_or(u32::MAX));
completion_tokens = completion_tokens.saturating_add(u32::try_from(resp.tokens_generated.unwrap_or(0)).unwrap_or(u32::MAX));
if !resp.text.trim().is_empty() {
combined = resp.text;
break;
@@ -227,8 +230,8 @@ pub async fn generate_continuable<G: TextGenerator>(
let req = make_request(opts, cont_prompt, current_max.min(opts.budget_cap));
let resp = generator.generate_text(req).await?;
calls += 1;
prompt_tokens = prompt_tokens.saturating_add(resp.tokens_evaluated.unwrap_or(0) as u32);
completion_tokens = completion_tokens.saturating_add(resp.tokens_generated.unwrap_or(0) as u32);
prompt_tokens = prompt_tokens.saturating_add(u32::try_from(resp.tokens_evaluated.unwrap_or(0)).unwrap_or(u32::MAX));
completion_tokens = completion_tokens.saturating_add(u32::try_from(resp.tokens_generated.unwrap_or(0)).unwrap_or(u32::MAX));
combined.push_str(&resp.text);
continuations += 1;
}