Analyze rules can describe how a finding is shown: a role (outcome, cause, context,
advisory), a one-line summary, the subject it is about and up to six key facts. Like the
explanation, the block is stored raw on the result and resolved where it is rendered.
- Templates: a qualified token {{signal.key}} reads one key of one condition's evidence,
so counts, durations and correlation fields are reachable. RuleEvidenceKeys (Shared,
exported to the manifest) lists the keys each condition source records; tests pin it
against the evaluators.
- Backend: PresentationJson on AnalyzeRules and RuleResults, RuleVersion on results,
ValidatePresentation on create/update, and results stored without a presentation get
the current rule's at read time.
- Web + MCP: lib/rulePresentation.ts resolves the block (unrecorded facts left out, summary
falls back to the explanation). The MCP now runs generated copies of the web modules
instead of a hand-kept mirror (npm run generate:mcp-logic, freshness tests in both
suites); the duplicate baseline shrinks by one.
- MCP output: get_session and get_session_summary return the resolved block (issues gain
ruleId, role, summary, subject, facts); test_analyze_rule previews it; validate_rule
checks qualified tokens against the key catalog and lints the subject.
- Shared case files: rule-template-interpolation gains the qualified-token cases,
rule-presentation is new.
No rule carries a presentation yet; renderers behave as before until rules gain one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rule template interpolation — shared cases
A rule result stores the rule's text with its {{token}} placeholders; each renderer resolves
them from the result's matchedConditions. cases.json is the one definition of that
resolution, and every implementation runs all of it:
- Web —
interpolateRuleTemplateinsrc/Web/autopilot-monitor-web/lib/interpolateRuleTemplate.ts(test:lib/__tests__/interpolateRuleTemplate.test.ts) - MCP server —
interpolateRuleTemplateinsrc/McpServer/autopilot-monitor-mcp/src/interpolate-rule-template.ts(test:src/__tests__/interpolate-rule-template.test.ts) - Backend —
RuleTemplateInterpolator.Interpolateinsrc/Backend/AutopilotMonitor.Functions/Services/RuleTemplateInterpolator.cs(test:RuleTemplateInterpolatorTests.cs)
autoFields is the list of same-event fields the rule engine copies into every evidence
entry (RuleEngine.EvidenceAutoFields). Each implementation's list is compared against it.
A qualified token {{signal.key}} reads one key of one evidence entry (a count, a duration, a
correlation field). It has no fallback order: an unknown signal, an unknown key or a null value
leaves it literal, so a renderer can tell "not recorded" from an empty value.
A change to the resolution goes into cases.json first; the three tests then say which
implementation is behind.