Skip to content

feat: Track κ — AI decision loop (decision trace + rules explain + LLM condition + rules simulate)#41

Merged
chenliuyun merged 2 commits intomainfrom
worktree-feat+track-kappa-decision-loop
May 7, 2026
Merged

feat: Track κ — AI decision loop (decision trace + rules explain + LLM condition + rules simulate)#41
chenliuyun merged 2 commits intomainfrom
worktree-feat+track-kappa-decision-loop

Conversation

@chenliuyun
Copy link
Copy Markdown
Collaborator

Summary

  • PR 1 — Decision Trace: src/rules/trace.ts with ruleVersion() (sha256/8-char), TraceBuilder, and shouldWriteTrace sampling modes; engine threads trace through dispatch; audit gains rule-evaluate kind
  • PR 2 — rules explain: rules trace-explain CLI subcommand + rules_explain MCP tool to replay why an evaluation fired or was blocked, reading rule-evaluate records from the audit log
  • PR 3 — LLM condition: { llm: { prompt, provider, cache_ttl, budget, on_error } } condition type; decide() added to LLMProvider (Anthropic tool-use + OpenAI function-calling); LlmConditionEvaluator with cache (SHA-256 structured key) and hourly budget; 4 lint rules
  • PR 4 — rules simulate: simulateRule() replays historical events (from --against JSONL or audit log) through the rule pipeline, reports would-fire / blocked / throttled / skipped-llm counts; rules simulate CLI + rules_simulate MCP tool

Spec gaps fixed

Gap Resolution
canonicalize undefined deepSortedJson() in trace.ts: recursive Object.keys().sort() + JSON.stringify
Cache key raw concat sha256(JSON.stringify([ruleVersion, promptTemplate, deepSortedJson(context)])) in llm-condition.ts
--no-fire-only double negative Renamed to --all in rules trace-explain

Test plan

  • npm test — 2204 tests, 118 files, all pass
  • tests/rules/trace.test.ts — 30 tests (canonicalize, ruleVersion, TraceBuilder, sampling)
  • tests/rules/explain.test.ts — 19 tests (loadTraceRecords, formatExplainText/Json)
  • tests/rules/llm-condition.test.ts — 22 tests (cache hit/miss, budget, on_error, lint rules)
  • tests/rules/simulate.test.ts — 18 tests (against-file replay, conditions, throttle, LLM skip)

chenliuyun added 2 commits May 7, 2026 12:29
PR 1 — Decision Trace
- src/rules/trace.ts: deepSortedJson, ruleVersion (sha256/8-char), TraceBuilder,
  shouldWriteTrace (full/sampled/off), filterTraceRecords
- engine.ts: fireId before eval, TraceBuilder threaded, emitTrace closure
- matcher.ts: trace? param, pushConditionTrace after eval, isLlmCondition guard
- audit.ts: rule-evaluate/llm-condition/llm-budget-exceeded kinds; writeEvaluateTrace
- schema v0.2.json: automation.audit block (evaluate_trace, evaluate_retention_days)
- tests/rules/trace.test.ts: 30 tests

PR 2 — rules explain
- src/rules/explain.ts: loadTraceRecords, loadRelatedAudit, formatExplainText/Json
- rules.ts: trace-explain subcommand (avoids collision with static explain)
- mcp.ts: rules_explain tool
- tests/rules/explain.test.ts: 19 tests

PR 3 — LLM condition
- src/rules/types.ts: LlmCondition interface + isLlmCondition guard; AutomationLlmBudgetConfig
- llm/provider.ts: decide() + DecideResult/DecideOptions on LLMProvider interface
- llm/providers/anthropic.ts: decide() via tool-use API
- llm/providers/openai.ts: decide() via function-calling API
- src/rules/llm-condition.ts: LlmConditionEvaluator (cache, budget, on_error)
  Cache key: sha256(JSON.stringify([ruleVersion, prompt, deepSortedJson(ctx)])) — fixes spec gap #5
- matcher.ts: llm condition branch with provider injection
- schema: llm condition oneOf branch + automation.llm_budget
- engine.ts: 4 lint rules (condition-llm-no-provider, no-cache-ttl-high-freq,
  budget-zero, on-error-pass)
- tests/rules/llm-condition.test.ts: 22 tests

PR 4 — rules simulate
- src/rules/simulate.ts: simulateRule(), as-of state fetcher, against-file replay,
  ThrottleGate simulation, LLM skip marker
- rules.ts: simulate subcommand
- mcp.ts: rules_simulate tool
- capabilities.ts: trace-explain + simulate entries
- tests/rules/simulate.test.ts: 18 tests

Spec gaps fixed:
  #1 canonicalize undefined → deepSortedJson() recursive key-sort
  #5 cache key raw concat → JSON.stringify([...]) structured array
@chenliuyun chenliuyun merged commit 0bd5c33 into main May 7, 2026
11 checks passed
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.

1 participant