UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

1,726 lines • 64.7 kB
/**
 * auditShapes — WHAT the audit chain's bounded mode keeps of each event: one
 * shape per registered event type, every field of its payload ruled.
 *
 * Pattern: a declarative table, total over the registry
 *          (`{ [T in keyof AgentfootprintEventMap]-?: BoundRule }`), built from
 *          the combinators in `auditBounding.ts`.
 * Role:    the bounding layer's data. `audit.ts` asks it for every event in
 *          `payloadMode: 'bounded'`; an event type it does not know is
 *          `unknownEventShape` — every field a marker.
 * Emits:   N/A.
 *
 * A new event type, or a new field on a payload, does not compile until it is
 * classified here. Content (what a person, the model, a tool or the data
 * wrote, or a message composed from it) is a marker; structure (ids, names,
 * kinds, codes, verdicts, counts, the library's own sentences, the words the
 * app declared up front) is kept — and every kept value is CHECKED at runtime
 * as the kind its type declares: `num`, `bool`, `str` (an open string: an id,
 * a name, a label), `oneOf` (a closed union: exactly its words). No container
 * is kept whole; each is spelled out field by field, so a child its type does
 * not declare is a marker. The type walker
 * (`test/type-regressions/AuditBoundingDepth.test.ts`) holds every rule here
 * to the type beneath it; the runtime sweep
 * (`test/observability-providers/audit-bounded-sweep.test.ts`) hands every rule
 * what its kind forbids.
 *
 * The positions a record keeps although their value may come from the run —
 * meta's who, decision evidence, a policy's tag, an app's reason word, a seen
 * tool's name — are the rules `auditKeptByContract.ts` names, placed here.
 *
 * `audit.ts` looks an event's shape up in `eventShapeTable` — a `Map`, so an
 * event NAME is never a key into a plain object (`constructor`, `__proto__`).
 */
import { blocksMarker, bool, charsMarker, either, keysMarker, listOf, messagesMarker, nullOr, num, oneOf, orList, recordOf, shapeOf, str, summariesMarker, typeMarker, } from './auditBounding.js';
import { appReasonWord, decisionSummary, declaredValue, metaIdentity, policyReasonTag, routeEvidence, seenToolName, } from './auditKeptByContract.js';
const SCRIPT_LABELS = [
    'submitted',
    'returned',
    'reported-success',
    'reported-failure',
    'completed',
    'completed-with-failure',
    'outcome-unknown',
];
/** A submitted program's attached record: only its text is content. */
const boundShownScript = shapeOf({
    toolCallId: str,
    dispatch: num,
    tool: str,
    language: str,
    label: oneOf(...SCRIPT_LABELS),
    exitCode: num,
    resultWithheld: oneOf('over-ceiling'),
    rewritten: oneOf(true),
    bytes: num,
    lines: num,
    truncated: shapeOf({ shownBytes: num }),
    text: charsMarker,
});
/** Attachment summary: preserve every declared field, check every runtime child. */
export const boundScripts = shapeOf({
    shown: listOf(boundShownScript),
    omitted: num,
    closedFence: shapeOf({
        char: oneOf('backtick', 'tilde'),
        length: num,
    }),
    withheldFromText: oneOf(true),
});
/** Match verdicts contain labels and references, never the program. */
const boundScriptsVerdict = shapeOf({
    blocks: listOf(shapeOf({
        block: num,
        label: oneOf(...SCRIPT_LABELS, 'unmatched'),
        exitCode: num,
        toolCallId: str,
        tool: str,
        dispatch: num,
        alsoMatches: num,
        reason: oneOf('no-submission-this-turn', 'over-size', 'kept-out'),
    })),
    earlierTurnRows: num,
    regionsDropped: num,
    scriptsDropped: num,
});
// ─── Shared pieces: coverage, periods, witnesses ─────────────────────
/** One coverage item: the tool author's prose (`what`, `why`, `short`), and its `kind`. */
const boundCoverageItem = shapeOf({
    what: charsMarker,
    why: charsMarker,
    short: charsMarker,
    kind: oneOf('existence', 'scope'),
});
/** What a read found still running: the tool author's prose, and how many things it stands for. */
const boundInProgressItem = shapeOf({
    what: charsMarker,
    why: charsMarker,
    short: charsMarker,
    count: num,
});
/** A declared window: both instants are the tool's own values. */
const boundInstants = shapeOf({
    from: charsMarker,
    to: charsMarker,
});
/** What the store holds — a window, or the library's word `'unknown'` (the tool
 *  said it cannot vouch for the store), which stays. */
const boundHeld = either(oneOf('unknown'), boundInstants);
/** A declared period: its instants are the tool's values. */
const boundPeriod = shapeOf({
    queried: boundInstants,
    held: boundHeld,
    readAt: charsMarker,
});
/** An absence's source and its clock, as the tool declared them. */
const boundProvenance = shapeOf({
    measuredAt: charsMarker,
    source: charsMarker,
    ageSeconds: num,
    sourceExportDate: charsMarker,
});
/**
 * What the library composed for a `search` tool. Kept: facets ride BY
 * REFERENCE, and a gap's words name arguments and verdicts, never a value
 * (`CoverageGapPayload`'s contract) — a `'prose'` gap's words are the ones
 * the search declaration states up front.
 */
/** What a gap bears on: a facet word, or the filter and values the search declaration states. */
const boundBearsFilter = shapeOf({
    filter: str,
    values: listOf(either(str, num, bool)),
});
const boundBears = either(oneOf('completeness', 'period', 'population', 'source'), boundBearsFilter);
const boundComposition = shapeOf({
    origin: oneOf('local', 'remote'),
    resultId: str,
    complete: bool,
    facets: listOf(shapeOf({
        facet: oneOf('filter', 'names', 'period', 'population', 'source', 'subject'),
        from: oneOf('call', 'default', 'host', 'result'),
        ref: shapeOf({ resultId: str, argument: str }),
        any: bool,
    })),
    gaps: listOf(shapeOf({
        kind: oneOf('argument-unsent', 'cap-reached', 'credential-limited', 'match', 'paged', 'partial', 'period', 'prose', 'ranking', 'scope'),
        what: str,
        why: str,
        bears: boundBears,
        argument: str,
    })),
});
/**
 * A skill guard's evaluation: the edge, the call, the verdict, and per
 * condition the key, operator and value the app DECLARED — and the engine's
 * summary of the value it read (`actualSummary`), the decision evidence the
 * chain keeps by contract (redaction-aware).
 */
const boundGuard = shapeOf({
    from: str,
    to: str,
    toolName: str,
    toolCallId: str,
    verdict: bool,
    conditions: listOf(shapeOf({
        key: str,
        op: str,
        value: orList(declaredValue),
        // The engine's decision evidence: a summary of the value a guard read.
        actualSummary: decisionSummary,
        passed: bool,
    })),
});
/** What an integrity finding is about: a kind and an id. */
const boundSubject = shapeOf({ kind: str, id: str });
/** What a message said that won a routing match: the text is the person's; the
 *  keyword is the app's declared vocabulary. */
const boundWitness = shapeOf({
    text: charsMarker,
    keyword: str,
});
/**
 * A typed answer's limits: the three lists, the declared periods, what a read
 * found still running and the values an `assume` rule filled. Every sentence
 * and value is a marker; the tool and argument NAMES, the call ids, counts,
 * kinds and the library's `'unknown'` stay.
 */
export const boundAnswerCoverage = shapeOf({
    checked: listOf(boundCoverageItem),
    notChecked: listOf(boundCoverageItem),
    cannotCover: listOf(boundCoverageItem),
    periods: listOf(shapeOf({
        toolName: str,
        toolCallId: str,
        queried: boundInstants,
        held: boundHeld,
        readAt: charsMarker,
    })),
    inProgress: listOf(shapeOf({
        toolName: str,
        toolCallId: str,
        items: listOf(boundInProgressItem),
    })),
    assumed: listOf(shapeOf({
        toolName: str,
        argument: str,
        value: charsMarker,
        hidden: bool,
    })),
});
/**
 * A typed answer's negatives: each statement and the population it is about
 * are markers; the answer field's declared name, the codes, verdicts, ids,
 * tool names and counts stay.
 */
export const boundAnswerNegatives = shapeOf({
    field: str,
    version: str,
    delivery: oneOf('as-checked', 'fallback', 'recorded'),
    claims: listOf(shapeOf({
        kind: oneOf('complete', 'none', 'not-found', 'unknown'),
        about: charsMarker,
        restsOn: listOf(str),
        statement: charsMarker,
        delivery: oneOf('record-composed'),
        version: str,
    })),
    checks: listOf(shapeOf({
        id: str,
        path: str,
        index: num,
        kind: oneOf('complete', 'none', 'not-found', 'unknown'),
        notes: listOf(oneOf('absence-kind-normalized')),
        // The payload declares any string: a checker's code.
        code: str,
        disposition: oneOf('checked-fail', 'not-applicable', 'unreachable'),
        tools: listOf(str),
        results: listOf(str),
        staleSince: shapeOf({
            turn: num,
            readAt: str,
        }),
    })),
    coverage: listOf(shapeOf({ tool: str, checked: num })),
    actions: listOf(shapeOf({
        tool: str,
        outcome: oneOf('error', 'not-run', 'ok'),
    })),
});
/** A shape for one event's whole payload, exhaustive over that event's payload type. */
const eventShape = (rules) => shapeOf(rules);
/** The pause reason the library writes itself — its own words, kept. */
const FIXED_PAUSE_REASON = 'stage requested pause';
/** Why a turn's answer stands where it does — the assessment's own words. */
const boundAssessmentReasons = listOf(oneOf('answer-check-failed', 'argument-asked', 'argument-assumed', 'argument-read', 'argument-unverified', 'asked', 'check-unreachable', 'claim-exceeds-search', 'coverage-gap', 'declaration-overclaimed', 'declared-absent', 'derived-from-reading', 'empty-undeclared', 'negative-prose-unverified', 'period-beyond-retention', 'period-differs-from-asked', 'period-not-held', 'period-partly-held', 'period-undeclared', 'period-unknown', 'script-unmatched', 'sources-conflict', 'steps-unfinished', 'stopped-early', 'value-contingent', 'value-survived-revision', 'value-unsupported'));
/** Which honesty checks ran, and over how much. */
const boundAssessmentChecks = listOf(shapeOf({
    layer: oneOf(1, 2, 3, 4),
    check: oneOf('answer-checks', 'argument-rules', 'argument-sources', 'names-and-numbers', 'result-period', 'result-shape', 'script-match', 'tool-coverage'),
    ran: num,
    of: num,
}));
/** A turn's answer assessment: verdict words, reason codes and check counts. */
const boundAnswerAssessment = shapeOf({
    assessment: oneOf('known', 'not-applicable', 'unknown', 'unrefuted'),
    standing: oneOf('ask', 'consistent', 'known', 'not-assessed', 'not-sure'),
    reasons: boundAssessmentReasons,
    checked: boundAssessmentChecks,
});
/** One context source's share of a slot: characters and pieces. */
const boundSourceShare = shapeOf({ chars: num, count: num });
/** A slot's share by context source — every source the library declares, by name. */
const boundSourceBreakdown = shapeOf({
    assistant: boundSourceShare,
    base: boundSourceShare,
    custom: boundSourceShare,
    'evidence-recovery': boundSourceShare,
    fact: boundSourceShare,
    findings: boundSourceShare,
    instructions: boundSourceShare,
    memory: boundSourceShare,
    ontology: boundSourceShare,
    rag: boundSourceShare,
    registry: boundSourceShare,
    skill: boundSourceShare,
    steering: boundSourceShare,
    'tool-result': boundSourceShare,
    user: boundSourceShare,
});
const requestReason = oneOf('answered', 'cancelled', 'changes-without-key', 'exhausted', 'no-time-left', 'not-permitted', 'not-replayable', 'not-retryable', 'retryable', 'wait-limit');
const requestFailure = oneOf('auth', 'network', 'permanent', 'rate-limited', 'server', 'timeout', 'unknown');
const requestRefusalKind = oneOf('session-busy', 'throttle');
const requestEffect = oneOf('applied', 'none', 'unknown');
/** A request's error: one of the library's two fixed sentences, and a category — never the error itself. */
const requestError = shapeOf({
    message: oneOf('The call ran out of time before an answer arrived.', 'The request failed before an answer arrived. Its error is not kept.'),
    code: requestFailure,
});
/** One try of a tool's request: outcome, reason, timing and the library's categories. */
const boundRequestAttempt = shapeOf({
    attempt: num,
    outcome: oneOf('answered', 'cut', 'failed', 'refused', 'timed-out'),
    reason: requestReason,
    status: num,
    kind: requestRefusalKind,
    failure: requestFailure,
    waitMs: num,
    retryAfterMs: num,
    error: requestError,
    remote: oneOf('unknown'),
    effect: requestEffect,
    permission: shapeOf({
        by: oneOf('adapter', 'compatibility', 'declaration'),
        on: oneOf('network', 'throttle'),
        assumes: oneOf('refused-before-execution'),
        deduplicated: bool,
    }),
    durationMs: num,
});
/** How a tool's request ended. */
const boundRequestEnd = shapeOf({
    outcome: oneOf('answered', 'cancelled', 'cut', 'failed', 'refused', 'timed-out'),
    reason: requestReason,
    status: num,
    kind: requestRefusalKind,
    failure: requestFailure,
    during: oneOf('request', 'wait'),
    error: requestError,
    remote: oneOf('unknown'),
    attempts: num,
    effect: requestEffect,
    mayHaveRun: bool,
});
/**
 * Each record's meta: the run and stage ids, paths, indices and engine
 * coordinates the dispatcher stamps — and the who the caller named
 * (`sessionId`, `principal`, `tenant`), kept by contract. A field `EventMeta`
 * does not declare, or a value of another kind, is a marker. (`wallClockMs` is
 * the record's `timestamp`; `runId` its run anchor — `audit.ts` lifts both.)
 */
export const boundMeta = shapeOf({
    wallClockMs: num,
    runOffsetMs: num,
    sourcePosition: shapeOf({
        engineRunId: str,
        logRunId: str,
        drillPath: listOf(str),
        committedThroughIdx: num,
    }),
    runtimeStageId: str,
    subflowPath: listOf(str),
    compositionPath: listOf(str),
    turnIndex: num,
    iterIndex: num,
    traceId: str,
    spanId: str,
    correlationId: str,
    runId: str,
    sessionId: metaIdentity,
    principal: metaIdentity,
    tenant: metaIdentity,
});
/** What a tool returned, as `describedResult()` declared it: the data is content;
 *  its kinds, field and column names, counts and the library's static note stay. */
const boundSemantics = shapeOf({
    af_semantics: bool,
    series: listOf(shapeOf({
        t: charsMarker,
        entity: charsMarker,
        metric: str,
        value: charsMarker,
    })),
    // An open record: `entity` and every other value is the data; the keys stay.
    facts: listOf(shapeOf({ entity: charsMarker })),
    edges: listOf(shapeOf({ from: charsMarker, to: charsMarker, kind: str })),
    grain: shapeOf({
        interval: str,
        aggregation: str,
        is_counter: bool,
        collapsed: charsMarker,
    }),
    provenance: shapeOf({
        measured_at: charsMarker,
        age_seconds: num,
        source: charsMarker,
        source_export_date: charsMarker,
    }),
    period: shapeOf({ queried: boundInstants, held: boundHeld, read_at: charsMarker }),
    resolved: listOf(shapeOf({
        argument: str,
        id: charsMarker,
        name: charsMarker,
        aliases: listOf(charsMarker),
    })),
    // `null` says there is no next page; a cursor or page number is a value.
    paging: shapeOf({ next: nullOr(charsMarker) }),
    coverage: shapeOf({
        checked: listOf(boundCoverageItem),
        not_checked: listOf(boundCoverageItem),
        cannot_cover: listOf(boundCoverageItem),
    }),
    not_covered: listOf(charsMarker),
    clarify: nullOr(shapeOf({ question: charsMarker, candidates: listOf(charsMarker) })),
    render: shapeOf({
        default: str,
        columns: listOf(str),
        sort: str,
        filter_note: charsMarker,
        chart_hint: charsMarker,
    }),
    // "The static sentence. Never interpolated."
    note: str,
});
/**
 * The whole-event shapes as a `Map`, by event type — what `audit.ts` looks an
 * event up in. An event's name is the emitter's to choose (`agent.emit()`
 * takes any string), so it is never a key into a plain object: a name
 * `Object.prototype` holds (`constructor`, `toString`, `__proto__`) finds no
 * shape here, and that event is bounded as unknown — every field a marker.
 */
export function eventShapeTable(toolRan) {
    return new Map(Object.entries(eventShapes(toolRan)));
}
/**
 * The whole-event shapes, by event type. `toolRan` answers whether this
 * strategy has seen a tool of that name run (`createToolRunTracker`): a
 * `tryInsteadTool` names another tool, and that name is kept only then —
 * otherwise it is the tool author's word for a tool this agent may not hold
 * (`otel.ts` · `coverageAttrs`, the same rule).
 */
export function eventShapes(toolRan) {
    return {
        // ── The seven a tool, the model or the person writes into ──────────
        'agentfootprint.tools.absent': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            lookedFor: charsMarker,
            checked: listOf(boundCoverageItem),
            notChecked: listOf(boundCoverageItem),
            cannotCover: listOf(boundCoverageItem),
            tryInstead: charsMarker,
            tryInsteadTool: shapeOf({
                tool: seenToolName(toolRan),
                why: charsMarker,
            }),
            provenance: boundProvenance,
            period: boundPeriod,
            composition: boundComposition,
            lookedForRef: shapeOf({
                resultId: str,
                field: oneOf('lookedFor'),
            }),
        }),
        'agentfootprint.tools.coverage_declared': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            checked: listOf(boundCoverageItem),
            notChecked: listOf(boundCoverageItem),
            cannotCover: listOf(boundCoverageItem),
            period: boundPeriod,
            inProgress: listOf(boundInProgressItem),
            composition: boundComposition,
        }),
        'agentfootprint.tools.semantics_declared': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            semantics: boundSemantics,
        }),
        'agentfootprint.agent.evidence_checked': eventShape({
            iteration: num,
            posture: oneOf('assist', 'guard', 'rails'),
            candidates: num,
            lookedUp: num,
            unsupported: listOf(shapeOf({
                value: charsMarker,
                shape: str,
                region: oneOf('prose', 'code'),
            })),
            action: oneOf('flagged', 'grounded', 'refused', 'revision-asked'),
            afterRevision: bool,
            evidenceTruncated: bool,
            carriedBy: listOf(shapeOf({
                toolCallId: str,
                values: num,
                only: num,
            })),
            stagedRefs: listOf(shapeOf({
                ref: str,
                kind: str,
            })),
            spenderTools: listOf(str),
            // `from` names the operands — and a unit-scaled figure's source value.
            computed: listOf(shapeOf({
                value: charsMarker,
                shape: str,
                derivation: str,
                from: charsMarker,
            })),
            scripts: boundScriptsVerdict,
        }),
        'agentfootprint.integrity.external_ground_used': eventShape({
            toolName: str,
            toolCallId: str,
            path: str,
            value: charsMarker,
            source: str,
            iteration: num,
        }),
        'agentfootprint.map.engaged': eventShape({
            mapId: str,
            iteration: num,
            by: oneOf('assumed', 'explicit', 'lexical', 'semantic', 'structural'),
            witness: charsMarker,
            reengaged: bool,
            upgraded: bool,
            foundedBy: oneOf('assumed', 'explicit', 'lexical', 'semantic', 'structural'),
            tenantChanged: bool,
            at: str,
        }),
        'agentfootprint.skill.turn_routed': eventShape({
            by: oneOf('continuity', 'decider', 'entry', 'intent', 'menu', 'none'),
            from: str,
            to: str,
            scorer: str,
            scores: listOf(shapeOf({
                id: str,
                score: num,
                relevance: num,
            })),
            runnerUp: shapeOf({
                id: str,
                gap: num,
            }),
            decisive: bool,
            witness: boundWitness,
            offered: listOf(str),
            stayOffered: bool,
            policy: shapeOf({
                nearTieMargin: num,
                menuSize: num,
                floor: num,
            }),
            window: num,
            droppedResume: shapeOf({
                id: str,
                reason: oneOf('unknown-skill'),
            }),
            decider: shapeOf({
                provider: str,
                model: str,
                picked: str,
            }),
        }),
        // ── The same rule, everywhere else the run's words ride ────────────
        'agentfootprint.map.parked': eventShape({
            mapId: str,
            iteration: num,
            by: oneOf('assumed', 'explicit', 'lexical', 'semantic', 'structural'),
            idleCalls: num,
            witness: charsMarker,
        }),
        // A guard's conditions are the engine's decision evidence (kept, see audit.ts).
        'agentfootprint.context.evaluated': eventShape({
            iteration: num,
            activeCount: num,
            skippedCount: num,
            evaluatedTotal: num,
            activeIds: listOf(str),
            skippedDetails: listOf(shapeOf({
                id: str,
                reason: oneOf('hidden', 'parked', 'predicate-threw', 'unknown-fact', 'unknown-trigger-kind'),
                error: charsMarker,
            })),
            triggerKindCounts: recordOf(num),
            // The catalog and the routing provenance are what the app declared.
            skillCatalog: listOf(shapeOf({
                id: str,
                description: str,
            })),
            routing: listOf(shapeOf({
                injectionId: str,
                flavor: str,
                via: str,
                path: listOf(shapeOf({ label: str, branch: str })),
                label: str,
                from: str,
                triggerKind: str,
                tools: listOf(str),
            })),
            cursorMove: shapeOf({
                from: str,
                to: str,
                by: str,
                offered: listOf(str),
                declinedOffer: bool,
                witness: boundWitness,
                guard: boundGuard,
                guardsClosed: listOf(boundGuard),
                reachable: listOf(str),
            }),
            supersededIds: listOf(str),
        }),
        'agentfootprint.validation.args_invalid': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            issues: listOf(shapeOf({
                path: str,
                expected: str,
                got: str,
                value: charsMarker,
                hint: str,
            })),
            enforced: bool,
        }),
        'agentfootprint.agent.output_schema_validation_failed': eventShape({
            message: charsMarker,
            stage: oneOf('json-parse', 'schema-validate'),
            path: str,
            rawOutput: charsMarker,
            draftWithheld: bool,
            attempt: num,
            cumulativeRetries: num,
        }),
        'agentfootprint.resilience.output_fallback_triggered': eventShape({
            stage: oneOf('json-parse', 'schema-validate'),
            rawOutputPreview: charsMarker,
            primaryErrorMessage: charsMarker,
            retriesSpent: num,
        }),
        'agentfootprint.resilience.output_canned_used': eventShape({
            rawOutputPreview: charsMarker,
            fallbackErrorMessage: charsMarker,
            retriesSpent: num,
        }),
        'agentfootprint.stream.tool_progress': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            payload: keysMarker,
        }),
        'agentfootprint.checkin.request': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            request: keysMarker,
        }),
        'agentfootprint.checkin.decision': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            requestId: str,
            approved: bool,
            by: str,
            note: charsMarker,
            componentId: str,
        }),
        'agentfootprint.middleware.decision': eventShape({
            middleware: str,
            moment: oneOf('after-tool', 'before-tool', 'input', 'output', 'window'),
            at: oneOf('message', 'tool'),
            phase: oneOf('input', 'output'),
            toolName: str,
            toolCallId: str,
            iteration: num,
            outcome: oneOf('allow', 'ask', 'deny'),
            changed: bool,
            why: charsMarker,
            componentId: str,
        }),
        'agentfootprint.skill.step_skipped': eventShape({
            skillId: str,
            // The step the app declared — its tool and note.
            step: shapeOf({
                index: num,
                total: num,
                tool: str,
                note: str,
            }),
            reason: charsMarker,
            policy: oneOf('advance', 'hold'),
            iteration: num,
            toolCallId: str,
        }),
        'agentfootprint.stream.llm_start': eventShape({
            iteration: num,
            provider: str,
            model: str,
            systemPromptChars: num,
            systemPromptText: charsMarker,
            messagesCount: num,
            toolsCount: num,
            // The catalog the model saw: names and the descriptions the tools declared.
            tools: listOf(shapeOf({
                name: str,
                description: str,
            })),
            estimatedPromptTokens: num,
            temperature: num,
            providerRequestRef: str,
            brain: shapeOf({
                via: oneOf('escalation', 'skill'),
                skillId: str,
            }),
        }),
        'agentfootprint.credential.failed': eventShape({
            service: str,
            reason: charsMarker,
            tool: str,
            errorClass: str,
            toolCallId: str,
            iteration: num,
        }),
        'agentfootprint.fallback.triggered': eventShape({
            kind: oneOf('provider', 'skill', 'tool'),
            primary: str,
            fallback: str,
            reason: charsMarker,
        }),
        'agentfootprint.memory.retrieved': eventShape({
            strategy: str,
            queryHash: str,
            k: num,
            threshold: num,
            maxChars: num,
            charsUsed: num,
            embedderId: str,
            dimensions: num,
            consideredCount: num,
            admittedCount: num,
            rejectedCount: num,
            candidates: listOf(shapeOf({
                id: str,
                score: num,
                rank: num,
                admitted: bool,
                reason: oneOf('below-threshold', 'over-budget', 'over-char-budget', 'over-max-entries'),
                docUri: str,
                page: num,
                heading: charsMarker,
            })),
            candidatesComplete: bool,
            candidatesOmittedReason: str,
            corpusEmpty: bool,
            namespace: str,
        }),
        'agentfootprint.integrity.context_error': eventShape({
            kind: oneOf('column-type-mismatch', 'dangling-reference', 'duplicate-execution', 'empty-lookup', 'invariant-violation', 'missing-column', 'prior-turn-evidence', 'unsupported-argument', 'unsupported-claim'),
            seam: oneOf('choice', 'claim', 'compose', 'wire', 'write'),
            subjects: listOf(boundSubject),
            witnesses: listOf(shapeOf({
                subject: boundSubject,
                predicate: str,
                value: charsMarker,
                epoch: num,
                stratum: oneOf('asserted', 'quoted'),
                provenance: charsMarker,
                runtimeStageId: str,
                synthetic: bool,
            })),
            predicate: str,
            epoch: num,
            synthetic: bool,
            advisory: bool,
            message: charsMarker,
            iteration: num,
        }),
        'agentfootprint.tools.effect': eventShape({
            kind: oneOf('propose-transition', 'require-instruction'),
            outcome: oneOf('accepted', 'refused', 'superseded'),
            stay: bool,
            toolName: str,
            toolCallId: str,
            iteration: num,
            targetSkillId: str,
            reason: charsMarker,
            instructionId: str,
            deliveryLease: oneOf('next-call', 'until-skill-exit'),
            refusalReason: str,
            supersededBy: oneOf('earlier-proposal'),
        }),
        // `reason` is `pauseData.reason` — the same words `questionPayload` hides.
        'agentfootprint.pause.request': eventShape({
            // The library's own pause sentence stays; a pause's own reason is its data.
            reason: oneOf(FIXED_PAUSE_REASON),
            questionPayload: keysMarker,
        }),
        'agentfootprint.artifacts.minted': eventShape({
            ref: str,
            kind: str,
            mediaType: str,
            bytes: num,
            label: charsMarker,
            digest: str,
            expiresAt: num,
            origin: shapeOf({
                runId: str,
                toolCallId: str,
            }),
            parentRefs: listOf(str),
            // The column, zone and interval the rows declare.
            timeAxis: shapeOf({
                column: str,
                unit: oneOf('epoch-ms', 'epoch-s', 'iso'),
                zone: str,
                interval: str,
                // One aggregate for every column, or one per column.
                aggregate: either(oneOf('avg', 'count', 'last', 'max', 'min', 'raw', 'sum'), recordOf(oneOf('avg', 'count', 'last', 'max', 'min', 'sum'))),
            }),
            tool: str,
        }),
        'agentfootprint.artifacts.presented': eventShape({
            ref: str,
            as: str,
            snapshot: shapeOf({
                kind: str,
                mediaType: str,
                bytes: num,
                label: charsMarker,
            }),
            toolCallId: str,
            iteration: num,
        }),
        'agentfootprint.artifacts.refused': eventShape({
            op: oneOf('delete', 'dispatch', 'get', 'head', 'list', 'put'),
            reason: oneOf('digest-mismatch', 'invalid-input', 'kind-mismatch', 'missing-or-expired', 'no-store', 'unknown-parent'),
            ref: str,
            detail: charsMarker,
            tool: str,
        }),
        'agentfootprint.reliability.fail_fast': eventShape({
            phase: oneOf('post-decide', 'pre-check'),
            kind: str,
            attempt: num,
            label: str,
            reason: charsMarker,
            providerUsed: str,
            errorKind: str,
            errorMessage: charsMarker,
        }),
        'agentfootprint.agent.handoff': eventShape({
            fromAgentId: str,
            toAgentId: str,
            reason: charsMarker,
            viaProtocol: oneOf('http', 'mcp', 'native'),
        }),
        // A policy's `reason` is its telemetry tag; its `rationale` is prose per decision.
        'agentfootprint.permission.check': eventShape({
            capability: oneOf('external_net', 'memory_read', 'memory_write', 'skill_read', 'tool_call', 'user_data'),
            actor: str,
            target: str,
            result: oneOf('allow', 'deny', 'gate_open', 'halt'),
            policyEngine: oneOf('cerbos', 'custom', 'opa'),
            policyRuleId: str,
            rationale: charsMarker,
            reason: policyReasonTag,
            toolCallId: str,
            iteration: num,
        }),
        // `tellLLM` is the tool result the model read in place of the call.
        'agentfootprint.permission.halt': eventShape({
            checkerId: str,
            target: str,
            reason: policyReasonTag,
            tellLLM: charsMarker,
            iteration: num,
            sequenceLength: num,
            toolCallId: str,
        }),
        // A router's `{ reason }` is the routing model's own words; `decide()`
        // evidence is the engine's, kept (see audit.ts).
        'agentfootprint.composition.route_decided': eventShape({
            conditionalId: str,
            chosen: str,
            rationale: str,
            evidence: routeEvidence,
        }),
        // ── Every other event: structure, and the fields bounded whole ─────
        'agentfootprint.composition.enter': eventShape({
            kind: oneOf('Conditional', 'Loop', 'Parallel', 'Sequence'),
            id: str,
            name: str,
            childCount: num,
        }),
        'agentfootprint.composition.exit': eventShape({
            kind: oneOf('Conditional', 'Loop', 'Parallel', 'Sequence'),
            id: str,
            name: str,
            status: oneOf('break', 'budget_exhausted', 'err', 'ok'),
            durationMs: num,
        }),
        'agentfootprint.composition.fork_start': eventShape({
            parentId: str,
            branches: listOf(shapeOf({
                id: str,
                name: str,
            })),
        }),
        'agentfootprint.composition.branch_complete': eventShape({
            parentId: str,
            branchId: str,
            status: oneOf('err', 'ok'),
            durationMs: num,
        }),
        'agentfootprint.composition.merge_end': eventShape({
            parentId: str,
            strategy: oneOf('fn', 'llm', 'outcomes-fn'),
            resultSummary: charsMarker,
            mergedBranchCount: num,
            totalBranchCount: num,
        }),
        'agentfootprint.composition.iteration_start': eventShape({
            loopId: str,
            iteration: num,
        }),
        'agentfootprint.composition.iteration_exit': eventShape({
            loopId: str,
            iteration: num,
            reason: oneOf('body_complete', 'break', 'budget', 'guard_false'),
        }),
        'agentfootprint.agent.turn_start': eventShape({
            turnIndex: num,
            userPrompt: charsMarker,
        }),
        'agentfootprint.agent.turn_end': eventShape({
            turnIndex: num,
            finalContent: charsMarker,
            totalInputTokens: num,
            totalOutputTokens: num,
            iterationCount: num,
            durationMs: num,
            stoppedEarly: shapeOf({
                reason: oneOf('cost-budget', 'max-iterations'),
                iteration: num,
                pendingToolCalls: num,
                wrappedUp: bool,
            }),
            answerCoverage: boundAnswerCoverage,
            answerAssessment: boundAnswerAssessment,
            standingLineNames: recordOf(str),
            answerNegatives: boundAnswerNegatives,
            scripts: boundScripts,
            refused: shapeOf({
                by: oneOf('evidence-rails'),
            }),
        }),
        'agentfootprint.agent.iteration_start': eventShape({
            turnIndex: num,
            iterIndex: num,
        }),
        'agentfootprint.agent.iteration_end': eventShape({
            turnIndex: num,
            iterIndex: num,
            toolCallCount: num,
            history: messagesMarker,
        }),
        'agentfootprint.agent.route_decided': eventShape({
            turnIndex: num,
            iterIndex: num,
            chosen: oneOf('evidence-recheck', 'final', 'negative-recheck', 'output-retry', 'step-nudge', 'tool-calls', 'wrap-up'),
            // A fixed sentence, or one the library composes (a count, a skill's name).
            rationale: str,
        }),
        'agentfootprint.agent.output_contract_unmet': eventShape({
            stage: oneOf('json-parse', 'schema-validate'),
            error: charsMarker,
            path: str,
            attempts: num,
            retriesSpent: num,
            fallbackConfigured: bool,
            iteration: num,
            brokenBy: str,
        }),
        'agentfootprint.agent.output_schema_retry': eventShape({
            attempt: num,
            retriesRemaining: num,
            iteration: num,
            stage: oneOf('json-parse', 'schema-validate'),
            error: charsMarker,
            path: str,
            correctiveMessageHash: str,
        }),
        'agentfootprint.agent.grounding_nudged': eventShape({
            iteration: num,
            refs: listOf(shapeOf({
                ref: str,
                kind: str,
            })),
            refsOmitted: num,
            tools: listOf(str),
        }),
        'agentfootprint.agent.run_configured': eventShape({
            agentId: str,
            llm: shapeOf({
                provider: str,
                model: str,
                modelOverrides: listOf(oneOf('configure', 'skill-brains')),
            }),
            cache: shapeOf({
                requested: oneOf('default', 'explicit'),
                strategy: oneOf('none'),
                status: oneOf('not-applicable'),
            }),
            reactMode: oneOf('classic', 'dynamic', 'dynamic-grouped'),
            memories: listOf(shapeOf({
                id: str,
                type: oneOf('causal', 'episodic', 'narrative', 'semantic'),
                strategy: oneOf('budget', 'decay', 'extract', 'hybrid', 'summarize', 'topK', 'window'),
                retrieval: str,
                embedderId: str,
                flavor: oneOf('memory', 'rag'),
            })),
            window: str,
            skillGraph: shapeOf({
                routing: oneOf('assist', 'guard', 'rails'),
                continuity: oneOf('conversation', 'turn'),
                scorer: str,
            }),
            evidenceGate: oneOf('assist', 'guard', 'rails'),
            artifacts: shapeOf({
                placement: bool,
                recordings: bool,
            }),
            recipes: listOf(shapeOf({
                id: str,
                version: str,
            })),
        }),
        'agentfootprint.agent.thinking_parse_failed': eventShape({
            providerName: str,
            subflowId: str,
            error: charsMarker,
            errorName: str,
            iteration: num,
        }),
        'agentfootprint.agent.thinking_omitted': eventShape({
            providerName: str,
            model: str,
            messageIndex: num,
            blockIndex: num,
            reason: oneOf('content-changed', 'missing-signature', 'prefix-changed', 'sequence-changed', 'thinking-retired'),
            phase: oneOf('prepared'),
        }),
        'agentfootprint.agent.budget_exhausted': eventShape({
            reason: oneOf('cost-budget', 'max-iterations'),
            iteration: num,
            limit: num,
            pendingToolCalls: num,
            action: oneOf('cut-short', 'wrapped-up'),
        }),
        'agentfootprint.stream.llm_end': eventShape({
            iteration: num,
            content: charsMarker,
            contentWithheld: bool,
            toolCallCount: num,
            // A provider's counts. Its usage object can carry more than these (structural
            // typing lets it): a child the type does not declare is a marker.
            usage: shapeOf({
                input: num,
                output: num,
                cacheRead: num,
                cacheWrite: num,
                thinking: num,
            }),
            stopReason: str,
            durationMs: num,
            providerResponseRef: str,
        }),
        'agentfootprint.stream.token': eventShape({
            iteration: num,
            tokenIndex: num,
            content: charsMarker,
        }),
        'agentfootprint.stream.tool_start': eventShape({
            toolName: str,
            toolCallId: str,
            args: keysMarker,
            parallelCount: num,
            protocol: oneOf('http', 'mcp', 'native', 'python-fn'),
            notDispatched: shapeOf({
                pausedCall: shapeOf({
                    toolCallId: str,
                    toolName: str,
                }),
            }),
        }),
        'agentfootprint.stream.tool_end': eventShape({
            toolCallId: str,
            result: typeMarker,
            error: bool,
            durationMs: num,
            status: oneOf('absent', 'denied', 'failure', 'invalid', 'partial', 'pending', 'success'),
            notDispatched: shapeOf({
                pausedCall: shapeOf({
                    toolCallId: str,
                    toolName: str,
                }),
            }),
            modelResult: typeMarker,
            changedArgKeys: listOf(str),
            notExecuted: bool,
        }),
        'agentfootprint.stream.thinking_delta': eventShape({
            iteration: num,
            tokenIndex: num,
            content: charsMarker,
        }),
        'agentfootprint.stream.thinking_end': eventShape({
            iteration: num,
            blockCount: num,
            totalChars: num,
            tokens: num,
            blocks: blocksMarker,
        }),
        'agentfootprint.context.injected': eventShape({
            contentSummary: charsMarker,
            contentHash: str,
            rawContent: charsMarker,
            slot: oneOf('messages', 'system-prompt', 'tools'),
            asRole: oneOf('assistant', 'system', 'tool', 'user'),
            asRecency: oneOf('earlier', 'latest'),
            position: num,
            sectionTag: str,
            source: oneOf('assistant', 'base', 'custom', 'evidence-recovery', 'fact', 'findings', 'instructions', 'memory', 'ontology', 'rag', 'registry', 'skill', 'steering', 'tool-result', 'user'),
            sourceId: str,
            upstreamRef: str,
            reason: str,
            retrievalScore: num,
            rankPosition: num,
            threshold: num,
            budgetSpent: shapeOf({
                tokens: num,
                fractionOfCap: num,
            }),
            expiresAfter: oneOf('iteration', 'persistent', 'run', 'turn'),
        }),
        'agentfootprint.context.evicted': eventShape({
            slot: oneOf('messages', 'system-prompt', 'tools'),
            contentHash: str,
            reason: oneOf('budget', 'low_score', 'policy', 'stale', 'user_revoked'),
            survivalMs: num,
        }),
        'agentfootprint.context.slot_composed': eventShape({
            slot: oneOf('messages', 'system-prompt', 'tools'),
            iteration: num,
            budget: shapeOf({
                cap: num,
                used: num,
                headroomChars: num,
            }),
            sourceBreakdown: boundSourceBreakdown,
            orderingStrategy: str,
            droppedCount: num,
            droppedSummaries: summariesMarker,
        }),
        'agentfootprint.context.budget_pressure': eventShape({
            slot: oneOf('messages', 'system-prompt', 'tools'),
            overflowBy: num,
            planAction: oneOf('abort', 'evict', 'none', 'summarize'),
            unit: oneOf('chars', 'tokens'),
            cap: num,
            projected: num,
        }),
        'agentfootprint.memory.strategy_applied': eventShape({
            strategyId: str,
            strategyKind: oneOf('fact-extraction', 'hybrid', 'semantic', 'sliding-window', 'summarizing'),
            reason: str,
            scoreEvidence: keysMarker,
            inputMemoryCount: num,
            outputMemoryCount: num,
            droppedIds: listOf(str),
            addedIds: listOf(str),
        }),
        'agentfootprint.memory.attached': eventShape({
            memoryId: str,
            contentSummary: charsMarker,
            score: num,
            rank: num,
            source: oneOf('auto-extract', 'manual', 'store'),
            retriever: oneOf('chroma', 'custom', 'pinecone', 'qdrant', 'weaviate'),
        }),
        'agentfootprint.memory.detached': eventShape({
            memoryId: str,
            reason: oneOf('budget', 'policy', 'score_low', 'stale'),
        }),
        'agentfootprint.memory.written': eventShape({
            memoryId: str,
            contentSummary: charsMarker,
            source: oneOf('auto', 'manual'),
            actor: str,
        }),
        'agentfootprint.tools.offered': eventShape({
            availableIds: listOf(str),
            withheldIds: listOf(str),
            withheldReasons: recordOf(oneOf('cost_guard', 'gated', 'permission', 'skill_inactive')),
            reason: appReasonWord,
        }),
        'agentfootprint.tools.activated': eventShape({
            toolId: str,
            reason: oneOf('autoActivate', 'permission_granted', 'skill_activated'),
            source: str,
        }),
        'agentfootprint.tools.deactivated': eventShape({
            toolId: str,
            reason: oneOf('permission_revoked', 'skill_deactivated'),
        }),
        'agentfootprint.tools.discovery_started': eventShape({
            providerId: str,
            iteration: num,
        }),
        'agentfootprint.tools.discovery_completed': eventShape({
            providerId: str,
            iteration: num,
            durationMs: num,
            toolCount: num,
        }),
        'agentfootprint.tools.discovery_failed': eventShape({
            providerId: str,
            error: charsMarker,
            errorName: str,
            iteration: num,
            durationMs: num,
        }),
        'agentfootprint.tools.shadowed': eventShape({
            toolName: str,
            iteration: num,
            schemaFrom: oneOf('framework', 'provider', 'registry', 'skill'),
            schemaFromId: str,
            dispatchTo: oneOf('framework', 'provider', 'registry', 'skill'),
            dispatchToId: str,
        }),
        'agentfootprint.tools.claim_swallowed': eventShape({
            toolName: str,
            iteration: num,
            lostBy: oneOf('framework', 'provider', 'registry', 'skill'),
            lostById: str,
            wonBy: oneOf('framework', 'provider', 'registry', 'skill'),
            wonById: str,
        }),
        'agentfootprint.tools.answered_off_wire': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            answeredBy: oneOf('framework', 'provider', 'registry', 'skill'),
            answeredById: str,
        }),
        'agentfootprint.tools.session_started': eventShape({
            tool: str,
            scope: oneOf('call', 'run', 'session', 'shutdown'),
            keyHash: str,
            runnerId: str,
            label: str,
        }),
        'agentfootprint.tools.session_reused': eventShape({
            calls: num,
            tool: str,
            scope: oneOf('call', 'run', 'session', 'shutdown'),
            keyHash: str,
            runnerId: str,
            label: str,
        }),
        'agentfootprint.tools.session_closed': eventShape({
            reason: oneOf('call-end', 'evicted', 'idle', 'run-end', 'session-end', 'shutdown'),
            durationMs: num,
            tool: str,
            scope: oneOf('call', 'run', 'session', 'shutdown'),
            keyHash: str,
            runnerId: str,
            label: str,
        }),
        'agentfootprint.tools.result_refused': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            sizeChars: num,
            maxChars: num,
            narrowBy: listOf(str),
            declaredStatus: oneOf('absent', 'denied', 'failure', 'invalid', 'partial', 'pending', 'success'),
        }),
        'agentfootprint.tools.repeated_call': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            occurrences: num,
            argsFingerprint: str,
            resultFingerprint: str,
            mode: oneOf('arguments'),
        }),
        'agentfootprint.tools.code_run': eventShape({
            tool: str,
            language: str,
            stagedInputs: num,
            outputChars: num,
            truncated: bool,
            ok: bool,
            exitCode: num,
            serviceError: bool,
            terminatedBy: str,
            shapeHash: str,
        }),
        // One use of an MCP client pool: "ids, digests, evidence and outcomes only" —
        // never an identity value, a session handle, an argument, a result or a server's text.
        'agentfootprint.tools.mcp_client': eventShape({
            server: str,
            at: oneOf('call', 'list'),
            toolCallId: str,
            keyHash: str,
            clientId: str,
            generation: num,
            client: oneOf('expired', 'handle-lost', 'joined', 'not-needed', 'opened', 'refused', 'reused'),
            previous: oneOf('evicted', 'expired', 'handle-lost', 'idle', 'terminated'),
            evidence: oneOf('server-404', 'transport-forgot-handle'),
            refusal: oneOf('binding-changed', 'closed', 'ending-full', 'identity-mismatch', 'incomplete-identity', 'init-failed', 'init-timeout', 'lease-expired', 'no-identity', 'operations-full', 'pool-full', 'principal-full', 'request-unmatched', 'stale-tools'),
            initMs: num,
            definitions: oneOf('listed', 'shared'),
            definitionsAgeMs: num,
            revalidated: oneOf('kept', 'refused'),
        }),
        'agentfootprint.tools.request_attempts': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            endpoint: str,
            origin: str,
            attempts: listOf(boundRequestAttempt),
            omitted: num,
            end: boundRequestEnd,
        }),
        'agentfootprint.tools.session_close_failed': eventShape({
            reason: oneOf('call-end', 'evicted', 'idle', 'run-end', 'session-end', 'shutdown'),
            durationMs: num,
            error: charsMarker,
            errorClass: str,
            tool: str,
            scope: oneOf('call', 'run', 'session', 'shutdown'),
            keyHash: str,
            runnerId: str,
            label: str,
        }),
        'agentfootprint.skill.activated': eventShape({
            skillId: str,
            reason: oneOf('autoActivate', 'manual', 'read_skill_result'),
            injectedTools: listOf(str),
            injectedSystemPromptChars: num,
        }),
        'agentfootprint.skill.graph_declared': eventShape({
            nodes: listOf(shapeOf({
                id: str,
                kind: str,
                description: str,
                label: str,
                title: str,
            })),
            edges: listOf(shapeOf({
                from: nullOr(str),
                to: str,
                kind: str,
                label: str,
                guard: shapeOf({
                    conditions: listOf(shapeOf({
                        key: str,
                        op: str,
                        // The value the app declared to compare against: one, or a list.
                        value: orList(declaredValue),
                    })),
                }),
            })),
        }),
        'agentfootprint.skill.deactivated': eventShape({
            skillId: str,
            reason: appReasonWord,
        }),
        'agentfootprint.skill.rejected': eventShape({
            requestedId: str,
            currentSkillId: str,
            allowed: listOf(str),
            iteration: num,
            posture: oneOf('guard', 'rails'),
            reason: oneOf('posture', 'self-call', 'unreachable'),
        }),
        'agentfootprint.skill.reroute_superseded': eventShape({
            volunteeredId: str,
            wonId: str,
            fromSkillId: str,
            iteration: num,
            source: oneOf('tool-proposal'),
        }),
        'agentfootprint.skill.route_conflict': eventShape({
            iteration: num,
            fromSkillId: str,
            winner: shapeOf({
                toolCallId: str,
                toolName: str,
                target: str,
            }),
            losers: listOf(shapeOf({
                toolCallId: str,
                toolName: str,
                target: str,
            })),
            source: oneOf('tool-proposal'),
        }),
        'agentfootprint.skill.step_advanced': eventShape({
            skillId: str,
            step: shapeOf({
                index: num,
                total: num,
                tool: str,
                note: str,
            }),
            iteration: num,
            toolCallId: str,
            completed: bool,
        }),
        'agentfootprint.skill.steps_unfinished': eventShape({
            skillId: str,
            remaining: listOf(shapeOf({
                index: num,
                tool: str,
                note: str,
            })),
            total: num,
            action: oneOf('accepted', 'cut-short', 'nudged'),
            iteration: num,
        }),
        'agentfootprint.skill.escalated': eventShape({
            iteration: num,
            afterRefusals: num,
            refusals: num,
            from: shapeOf({
                provider: str,
                model: str,
            }),
            to: shapeOf({
                provider: str,
                model: str,
            }),
        }),
        'agentfootprint.permission.gate_opened': eventShape({
            gateId: str,
            openedBy: str,
            expiresAt: num,
        }),
        'agentfootprint.permission.gate_closed': eventShape({
            gateId: str,
            reason: appReasonWord,
        }),
        'agentfootprint.credential.requested': eventShape({
            service: str,
            mode: oneOf('machine', 'user'),
            toolCallId: str,
            iteration: num,
        }),
        'agentfootprint.credential.acquired': eventShape({
            service: str,
            kind: str,
            expiresAt: num,
            toolCallId: str,
            iteration: num,
        }),
        'agentfootprint.credential.authorization_required': eventShape({
            service: str,
            sessionId: str,
            toolCallId: str,
            iteration: num,
        }),
        'agentfootprint.cost.tick': eventShape({
            scope: oneOf('iteration', 'run', 'turn'),
            model: str,
            provider: str,
            tokensInput: num,
            tokensOutput: num,
            estimatedUsd: num,
            cumulative: shapeOf({
                tokensInput: num,
                tokensOutput: num,
                estimatedUsd: num,
            }),
        }),
        'agentfootprint.cost.limit_hit': eventShape({
            kind: oneOf('max_cost', 'max_iterations', 'max_tokens', 'max_wallclock'),
            limit: num,
            actual: num,
            action: oneOf('abort', 'degrade', 'warn'),
        }),
        'agentfootprint.eval.score': eventShape({
            metricId: str,
            value: num,
            threshold: num,
            target: oneOf('iteration', 'run', 'toolCall', 'turn'),
            targetRef: str,
            evaluator: oneOf('fn', 'heuristic', 'llm'),
            evidence: keysMarker,
            label: str,
            explanation: charsMarker,
        }),
        'agentfootprint.eval.threshold_crossed': eventShape({
            metricId: str,
            direction: oneOf('above', 'below'),
            value: num,
            threshold: num,
            actionTaken: str,
        }),
        'agentfootprint.error.retried': eventShape({
            attempt: num,
            maxAttempts: num,
            lastError: charsMarker,
            backoffMs: num,
            reason: str,
            statedWaitMs: num,
        }),
        'agentfootprint.error.recovered': eventShape({
            attempt: num,
            totalDurationMs: num,
        }),
        'agentfootprint.error.fatal': eventShape({
            error: charsMarker,
            stage: str,
            scope: str,
        }),
        'agentfootprint.error.circuit_changed': eventShape({
            state: oneOf('closed', 'half-open', 'open'),
            reason: str,
            providerName: str,
        }),
        'agentfootprint.reliability.retried': eventShape({
            attempt: num,
            action: oneOf('retry', 'retry-other'),
            errorKind: str,
            errorMessage: charsMarker,
            fromProvider: str,
            toProvider: str,
        }),
        'agentfootprint.reliability.recovered': eventShape({
            attempt: num,
            recoveredVia: oneOf('fallback', 'retry', 'retry-other'),
            priorFailures: num,
            errorKind: str,
        }),
        'agentfootprint.pause.resume': eventShape({
            resumeInput: keysMarker,
            pausedDurationMs: num,
            componentId: str,
        }),
        'agentfootprint.findings.declared': eventShape({
            toolName: str,
            toolCallId: str,
            iteration: num,
            basis: oneOf('direct', 'exploratory'),
            expect: oneOf('high', 'low', 'medium'),
            hasProposition: bool,
            malformed: num,
        }),
        'agentfootprint.findings.standing': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            standing: oneOf('fact', 'noise', 'open', 'ruled-out'),
            declaredOn: oneOf('answer', 'tool-call'),
            assertionCount: num,
            conflictKeys: listOf(str),
            unknownId: bool,
            agrees: bool,
        }),
        'agentfootprint.findings.judged': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            against: oneOf('proposition', 'question'),
            standing: oneOf('fact', 'noise', 'open', 'ruled-out'),
            confidence: num,
            latencyMs: num,
            inputTokens: num,
            outputTokens: num,
        }),
        'agentfootprint.findings.judge_failed': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            status: num,
            latencyMs: num,
        }),
        'agentfootprint.findings.contingent': eventShape({
            iteration: num,
            declaredOn: oneOf('answer', 'tool-call'),
            toolCallId: str,
            carriers: num,
            standings: listOf(oneOf('fact', 'noise', 'open', 'ruled-out')),
            valueChars: num,
        }),
        'agentfootprint.findings.argument': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            turn: num,
            argument: str,
            rule: oneOf('ask', 'assume'),
            period: bool,
            source: oneOf('answered', 'app', 'default', 'model', 'result', 'said'),
            asked: oneOf('invalid-answer', 'missing', 'unverified'),
            claimed: oneOf('app', 'assumed', 'none', 'result', 'turn', 'user'),
            matched: oneOf('mention', 'phrase', 'quote', 'spelling'),
            reading: bool,
            earlier: bool,
            setAside: oneOf('noise', 'open', 'ruled-out'),
            argumentsFrom: oneOf('listed', 'unlisted'),
            coincides: oneOf('app', 'person', 'result'),
            free: bool,
            failed: oneOf('composed-message', 'no-earlier-turn', 'not-in-app-text', 'not-in-earlier-turns', 'not-in-result', 'only-in-model-answer', 'placed-result', 'quote-not-found', 'uncheckable', 'unknown-result'),
            malformed: num,
            valueChars: num,
        }),
        'agentfootprint.findings.period': eventShape({
            toolCallId: str,
            toolName: str,
            iteration: num,
            turn: num,
            verdict: oneOf('covered', 'not-held', 'partly-held', 'undeclared', 'unknown'),
            timeChecks: listOf(oneOf('partly-beyond-retention', 'period-beyond-retention', 'period-differs-from-asked', 'period-shifted')),
        }),
        'agentfootprint.findings.negative_claim': eventShape({
            iteration: num,
            turn: num,
            field: str,
            span: shapeOf({
                start: num,
                end: num,
            }),
            packVersion: str,
            phraseId: str,
            truncated: bool,
            kind: oneOf('negative-claim', 'negative-claim-note'),
            // A claim row's checker codes and native result ids; a note row's code.
            claim: oneOf('complete', 'none'),
            notes: listOf(str),
            results: listOf(str),
            code: str,
        }),
        'agentfootprint.tool_choice.picked': eventShape({
            iteration: num,
            chosen: str,
            confidence: num,
            offered: num,
            served: num,
            narrowed: bool,
            narrowedSkipped: oneOf('after-miss', 'evidence-revision', 'too-few', 'unavailable', 'wrap-up'),
            latencyMs: num,
            inputTokens: num,
            outputTokens: num,
        }),
        'agentfootprint.tool_choice.outcome': eventShape({
            iteration: num,
            called: listOf(str),
            firstAgrees: bool,
            missed: listOf(str),
        }),
        'agentfootprint.tool_choice.failed': eventShape({
            iteration: num,
            status: num,
            latencyMs: num,
        }),
        'agentfootprint.ontology.served': eventShape({
            iteration: num,
            id: str,
            version: str,
            hash: str,
            nodes: num,
            sources: num,
            edges: num,
        }),
        'agentfootprint.answer.assessed': eventShape({
            turn: num,
            iteration: num,
            assessment: oneOf('known', 'not-applicable', 'unknown', 'unrefuted'),
            standing: oneOf('ask', 'consistent', 'known', 'not-assessed', 'not-sure'),
            reasons: boundAssessmentReasons,
            checked: boundAssessmentChecks,
        }),
        'agentfootprint.embedding.generated': eventShape({
            model: str,
            provider: oneOf('cohere', 'custom', 'local', 'openai', 'voyage'),
            inputKind: oneOf('document', 'query'),
            dimension: num,
            count: num,
            durationMs: num,
            tokensSpent: num,
        }),
        'agentfootprint.artifacts.resolved': eventShape({
            ref: str,
            via: oneOf('get', 'head'),
            kind: str,
            bytes: num,
            tool: str,
        }),
        'agentfootprint.artifacts.expired': eventShape({
            ref: str,
            reason: oneOf('max-bytes', 'max-count', 'ttl'),
            kind: str,
            bytes: num,
            tool: str,
        }),
        'agentfootprint.artifacts.hand_over_failed': eventShape({
            cause: oneOf('abort', 'expired', 'hook', 'operation', 'timeout'),
            op: oneOf('delete', 'dispatch', 'get', 'head', 'list', 'put'),
            errorClass: str,
            errorCode: str,
        }),
        'agentfootprint.integrity.disposition': eventShape({
            posture: oneOf('dev', 'observe'),
            workExisted: bool,
            rows: listOf(shapeOf({
                check: str,
                seam: oneOf('choice', 'claim', 'compose', 'wire', 'write'),
                checked: num,
                findings: num,
                notApplicable: num,
                unreachable: num,
                lastFiredAt: num,
                synthetic: num,
            })),
        }),
    };
}
//# sourceMappingURL=auditShapes.js.map