/** * semantics/envelope — minting, recognizing and projecting the semantic * tool-result envelope (9.53.0). * * Pattern: minted by a helper, RECOGNIZED by the framework (the `absent()` / * tool-effects precedent). A return shape the framework does not * understand is a convention, and a convention cannot ride the * record, feed a UI, or be refused by a build gate. * Role: lib/ layer, pure. The dispatch loop calls `readSemantics` at the * execute boundary; `semantic()` is what a tool author writes; * `checkSemantics` (check.ts) judges the same shapes offline. * Emits: N/A (the caller emits `agentfootprint.tools.semantics_declared`). * * ## Two views of one envelope — the design decision, stated * * The MODEL reads a compact, rendering-free projection * ({@link semanticsForModel}): the data (`series`/`facts`/`edges`), the * caveats that must travel with it (`grain`, `provenance`), the composed * `not_covered` prose, a non-null `clarify`, and the static note. Dropped * from the model's view: the `af_semantics` marker (machine-only), `render` * (a UI hint — the tool never renders, and a model parroting rendering * directives is noise), the three-list `coverage` detail (it rides the * coverage channel and the record; the model reads the composed * `not_covered` lines instead), and a `clarify: null` (a stated non-question * is a fact for the record, not something the model acts on). * * The RECORD gets everything: the full envelope — render, coverage, * marker and all — lands on the `tools.semantics_declared` event BEFORE the * result ceiling is measured, so grain and provenance survive to recordings * and UIs even when the content itself is refused as oversized. The * `coverage` field is additionally declared through the SAME channel the * `coverage()` primitive uses (`tools.coverage_declared`, tracked state, the * final-answer limits block) — absorbed, never duplicated. * * ## One rule set, two doors * * `semantic()` refuses a declaration this vocabulary cannot honor at the * CALL SITE (the `absent()` law) — so a minted envelope is honest by * construction: series carry their grain, data carries its provenance, * counter-looking aggregations state `is_counter`. `semanticIssues()` judges * the RENDERED shape — the same rules over a value somebody may have built * by hand — and is what recognition and the `check:semantics` gate both * stand on. Recognition is STRICT (the zero-cost guarantee): a marker- * bearing value with any issue is NOT recognized — it keeps its bytes on * the data path (dev-warned, and named field-by-field by the gate), because * this library does not half-apply a shape it cannot fully honor. */ import type { Coverage } from '../../core/agent/coverage/types.js'; import { type SemanticCoverage, type SemanticDeclaration, type ToolSemantics } from './types.js'; /** The codes an envelope can be faulted with — shared by recognition (any * issue ⇒ not recognized) and the `check:semantics` gate (issues become * findings under these same names). */ export type SemanticIssueCode = 'malformed-semantics' | 'series-without-grain' | 'counter-aggregation-unstated' | 'data-without-provenance'; /** One fault, naming the field so a refusal can teach and a gate can point. */ export interface SemanticIssue { readonly code: SemanticIssueCode; /** The offending / missing field, dot-pathed ('grain.is_counter'). */ readonly field: string; readonly message: string; } /** Whole-token match against {@link COUNTER_AGGREGATION_WORDS}, singular or * plural, case-insensitive — 'sum' and 'Counts' look like counters, * 'summary' does not. */ export declare function isCounterLookingAggregation(aggregation: string): boolean; /** Compose the `not_covered` prose lines FROM coverage — the one derivation, * used by the mint and by the drift check, so the two can never disagree. */ export declare function composeNotCovered(coverage: SemanticCoverage): readonly string[]; /** * Judge one RENDERED envelope shape against the whole rule set. Empty = a * well-formed envelope this library can honor. Non-empty = the faults, each * naming its field. * * Called with values that carry the marker; on anything else it reports the * missing marker rather than guessing. */ export declare function semanticIssues(value: unknown): readonly SemanticIssue[]; /** * Say "here is typed data, with the caveats that make it honest" in a shape * the framework recognizes, the record keeps whole, and a build gate can * refuse. * * Returns the value a tool's `execute` should return. The framework * recognizes it at the dispatch boundary: the MODEL reads the compact * projection ({@link semanticsForModel}), the FULL envelope rides the typed * `agentfootprint.tools.semantics_declared` event, and a declared `coverage` * flows through the same channel `coverage()` uses. * * Refuses (throws, at the call site — the `absent()` law) any declaration * this vocabulary cannot honor: series without grain, data without * provenance, a counter-looking aggregation with `is_counter` unstated, and * every malformed shape — each refusal names the field and the fix. * * @example a per-port IOPS tool * return semantic({ * series: rows.map((r) => ({ t: r.time, entity: r.port, metric: 'avg_iops', value: r.iops })), * grain: { interval: '30m', aggregation: 'avg', is_counter: false }, * provenance: { measured_at: latestSampleTime, source: 'InfluxDB SwitchPortStats' }, * coverage: { * checked: ['shq-fab-a: all 48 FC ports'], * notChecked: [{ what: 'the peer fabric', why: 'this collector is scoped to one fabric' }], * }, * render: { default: 'table', columns: ['entity', 'value'], sort: 'value desc' }, * }); */ export declare function semantic(decl: SemanticDeclaration): ToolSemantics; /** * Recognize (or decline to recognize) a value as a semantic envelope — * STRICT, and the strictness is the zero-cost guarantee. Only a plain object * whose `af_semantics` is exactly `true` AND that passes the whole rule set * qualifies; every other value any tool has ever returned takes the path it * always took, byte for byte. * * `undefined` means "not an envelope this library can honor" — a marker- * bearing value with faults stays DATA (never half-applied); the dispatch * loop dev-warns it and `check:semantics` names every fault. */ export declare function readSemantics(value: unknown): ToolSemantics | undefined; /** * Name what is wrong with a value that CARRIES the marker but was not * recognized. `undefined` for values without the marker (they are data, not * near-misses) and for well-formed envelopes. Diagnosis only — never changes * what any value does. */ export declare function explainSemantics(value: unknown): readonly SemanticIssue[] | undefined; /** * The MODEL's view of one recognized envelope — compact and rendering-free. * * Keeps: the data (`series`/`facts`/`edges`), the caveats that must travel * with it (`grain`, `provenance`), the composed `not_covered` prose, a * non-null `clarify`, and the static note. Drops: the marker, `render` * (UI hint), the three-list `coverage` detail (rides the coverage channel * and the record), and a `clarify: null`. Shallow-copied so the history * entry is not the object the tool still holds. */ export declare function semanticsForModel(sem: ToolSemantics): Record; /** The envelope's coverage in the normalized three-list shape the coverage * machinery reads — how `readCoverageResult` absorbs a semantic envelope's * boundary into the one coverage channel. */ export declare function coverageOfSemantics(sem: ToolSemantics): Coverage; //# sourceMappingURL=envelope.d.ts.map