agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
107 lines • 6.95 kB
JavaScript
;
/**
* auditKeptByContract — what a BOUNDED audit record keeps although its value
* may come from the run: the named exceptions to "structure is kept, content
* is a marker", in one place.
*
* Pattern: a closed list of named exceptions (`KEPT_BY_CONTRACT`), each a rule
* built from `auditBounding.ts` and wrapped in `byContract`, so a walker
* finds every one by name.
* Role: `auditShapes.ts` places these rules in the event shapes and the meta
* shape; no other rule keeps a value the run composed.
* Emits: N/A.
*
* An exception is a POSITION, never a pass-through: each one still checks its
* value like every other rule — it keeps a value of its declared kind (a
* string, or decide() evidence's own shape, field by field), and a value of any
* other kind, or a child its type does not declare, is a marker.
*
* Adding an exception, or placing one somewhere new, changes the pin in
* `test/observability-providers/audit-bounded-sweep.test.ts` — a reviewed
* change, never a silent one. The module documentation of `audit.ts`, the
* observability README and the exporters page state the same list.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.routeEvidence = exports.seenToolName = exports.appReasonWord = exports.policyReasonTag = exports.decisionSummary = exports.metaIdentity = exports.declaredValue = exports.KEPT_BY_CONTRACT = void 0;
const auditBounding_js_1 = require("./auditBounding.js");
/** The exceptions, by name — what each keeps, and why the record keeps it. */
exports.KEPT_BY_CONTRACT = {
'meta-identity': "who a run is for — the session id, principal and tenant the caller named — on each record's meta: the who of an audit record",
'decide-evidence': 'decide()/select() evidence an app emits on `composition.route_decided`, as the engine summarized it: rule labels, branches, operators, thresholds and verdicts, each field checked',
'decision-summary': "the engine's summary of a value a decision rule read (decide() evidence, a skill guard's condition) — redaction-aware: under an agent's `redact` a selected key is the placeholder; otherwise the summary shows the value",
'policy-reason-tag': "a permission policy's telemetry `reason` tag (`permission.check`, `permission.halt`) — the policy's own word",
'app-reason-word': 'the reason word an app attaches to a lifecycle event it emits itself (`skill.deactivated`, `tools.offered`, `permission.gate_closed`) — the app’s own words, as written',
'seen-tool-name': 'a `tryInsteadTool` name, once this strategy has seen that tool run',
};
const exception = (name, rule) => (0, auditBounding_js_1.byContract)(name, rule);
/** A value the app declared: a word, a number or a flag — or a declared "none". */
exports.declaredValue = (0, auditBounding_js_1.nullOr)((0, auditBounding_js_1.either)(auditBounding_js_1.str, auditBounding_js_1.num, auditBounding_js_1.bool));
// ─── The exceptions ──────────────────────────────────────────────────
/** `meta.sessionId`, `meta.principal`, `meta.tenant`: the caller's own names for who. */
exports.metaIdentity = exception('meta-identity', auditBounding_js_1.str);
/** The engine's summary of a value a rule read. */
exports.decisionSummary = exception('decision-summary', auditBounding_js_1.str);
/** A permission policy's telemetry tag. */
exports.policyReasonTag = exception('policy-reason-tag', auditBounding_js_1.str);
/** A reason word an app attaches to a lifecycle event it emits itself. */
exports.appReasonWord = exception('app-reason-word', auditBounding_js_1.str);
/**
* A `tryInsteadTool` name: kept only once this strategy has seen that tool run —
* a tool the agent holds, by construction (`otel.ts` · `coverageAttrs`, the same
* rule); otherwise it is the tool author's word for a tool this agent may not
* hold.
*/
function seenToolName(toolRan) {
return (0, auditBounding_js_1.when)('a name this strategy has seen run is a tool the agent holds', (value) => typeof value === 'string' && toolRan(value), exception('seen-tool-name', auditBounding_js_1.str), auditBounding_js_1.charsMarker);
}
exports.seenToolName = seenToolName;
/** One rule's evidence: what it read or compared, its verdict; a rule's thrown message is a marker. */
const boundRuleEvidence = (0, auditBounding_js_1.shapeOf)({
type: (0, auditBounding_js_1.oneOf)('filter', 'function'),
ruleIndex: auditBounding_js_1.num,
branch: auditBounding_js_1.str,
matched: auditBounding_js_1.bool,
label: auditBounding_js_1.str,
inputs: (0, auditBounding_js_1.listOf)((0, auditBounding_js_1.shapeOf)({ key: auditBounding_js_1.str, valueSummary: exports.decisionSummary, redacted: auditBounding_js_1.bool })),
conditions: (0, auditBounding_js_1.listOf)((0, auditBounding_js_1.shapeOf)({
key: auditBounding_js_1.str,
op: auditBounding_js_1.str,
threshold: (0, auditBounding_js_1.orList)(exports.declaredValue),
actualSummary: exports.decisionSummary,
result: auditBounding_js_1.bool,
redacted: auditBounding_js_1.bool,
})),
// A `when` that threw: its message can echo the value it read.
matchError: auditBounding_js_1.charsMarker,
});
/** decide()/select() evidence: every field footprintjs declares, each checked. */
const boundDecideEvidence = (0, auditBounding_js_1.shapeOf)({
retryLoop: (0, auditBounding_js_1.shapeOf)({
id: auditBounding_js_1.str,
series: auditBounding_js_1.str,
attempt: auditBounding_js_1.num,
of: auditBounding_js_1.num,
effect: (0, auditBounding_js_1.oneOf)('applied', 'none', 'unknown'),
reconciled: auditBounding_js_1.bool,
next: (0, auditBounding_js_1.oneOf)('done', 'retry', 'stop'),
reason: auditBounding_js_1.str,
}),
rules: (0, auditBounding_js_1.listOf)(boundRuleEvidence),
chosen: auditBounding_js_1.str,
default: auditBounding_js_1.str,
defaultLabel: auditBounding_js_1.str,
selected: (0, auditBounding_js_1.listOf)(auditBounding_js_1.str),
});
/** decide() evidence carries its own `rules` list — `otel.ts`'s test too. */
const isDecideEvidence = (value) => typeof value === 'object' &&
value !== null &&
!Array.isArray(value) &&
Object.hasOwn(value, 'rules') &&
Array.isArray(value.rules);
/**
* `composition.route_decided.evidence`: decide() evidence is kept by contract,
* as its own shape; any other evidence (a router's own `{ reason }`) is a
* free-form record — its key names only.
*/
exports.routeEvidence = (0, auditBounding_js_1.when)("decide() evidence is the engine's, kept by contract; any other is a record", isDecideEvidence, exception('decide-evidence', boundDecideEvidence), auditBounding_js_1.keysMarker);
//# sourceMappingURL=auditKeptByContract.js.map