agentfootprint 9.51.0 → 9.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/AGENTS.md +21 -1
  2. package/CLAUDE.md +6 -2
  3. package/ai-instructions/claude-code/SKILL.md +18 -1
  4. package/bin/agentfootprint-check-semantics.mjs +14 -0
  5. package/dist/core/agent/coverage/read.js +13 -0
  6. package/dist/core/agent/coverage/read.js.map +1 -1
  7. package/dist/core/agent/stages/toolCalls.js +141 -4
  8. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  9. package/dist/core/tools.js +25 -1
  10. package/dist/core/tools.js.map +1 -1
  11. package/dist/debug.js +14 -3
  12. package/dist/debug.js.map +1 -1
  13. package/dist/esm/core/agent/coverage/read.js +13 -0
  14. package/dist/esm/core/agent/coverage/read.js.map +1 -1
  15. package/dist/esm/core/agent/stages/toolCalls.js +141 -4
  16. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  17. package/dist/esm/core/tools.d.ts +64 -0
  18. package/dist/esm/core/tools.js +23 -0
  19. package/dist/esm/core/tools.js.map +1 -1
  20. package/dist/esm/debug.d.ts +1 -0
  21. package/dist/esm/debug.js +7 -0
  22. package/dist/esm/debug.js.map +1 -1
  23. package/dist/esm/events/payloads.d.ts +49 -0
  24. package/dist/esm/events/registry.d.ts +5 -1
  25. package/dist/esm/events/registry.js +4 -0
  26. package/dist/esm/events/registry.js.map +1 -1
  27. package/dist/esm/index.d.ts +2 -1
  28. package/dist/esm/index.js +11 -1
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/lib/mcp/mcpServe.js +10 -0
  31. package/dist/esm/lib/mcp/mcpServe.js.map +1 -1
  32. package/dist/esm/lib/semantics/check.d.ts +70 -0
  33. package/dist/esm/lib/semantics/check.js +154 -0
  34. package/dist/esm/lib/semantics/check.js.map +1 -0
  35. package/dist/esm/lib/semantics/cli.d.ts +40 -0
  36. package/dist/esm/lib/semantics/cli.js +148 -0
  37. package/dist/esm/lib/semantics/cli.js.map +1 -0
  38. package/dist/esm/lib/semantics/envelope.d.ts +139 -0
  39. package/dist/esm/lib/semantics/envelope.js +592 -0
  40. package/dist/esm/lib/semantics/envelope.js.map +1 -0
  41. package/dist/esm/lib/semantics/format.d.ts +11 -0
  42. package/dist/esm/lib/semantics/format.js +33 -0
  43. package/dist/esm/lib/semantics/format.js.map +1 -0
  44. package/dist/esm/lib/semantics/index.d.ts +14 -0
  45. package/dist/esm/lib/semantics/index.js +15 -0
  46. package/dist/esm/lib/semantics/index.js.map +1 -0
  47. package/dist/esm/lib/semantics/types.d.ts +230 -0
  48. package/dist/esm/lib/semantics/types.js +71 -0
  49. package/dist/esm/lib/semantics/types.js.map +1 -0
  50. package/dist/esm/lib/trace-toolpack/traceToolpack.js +6 -0
  51. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  52. package/dist/events/registry.js +4 -0
  53. package/dist/events/registry.js.map +1 -1
  54. package/dist/index.js +65 -44
  55. package/dist/index.js.map +1 -1
  56. package/dist/lib/mcp/mcpServe.js +10 -0
  57. package/dist/lib/mcp/mcpServe.js.map +1 -1
  58. package/dist/lib/semantics/check.js +158 -0
  59. package/dist/lib/semantics/check.js.map +1 -0
  60. package/dist/lib/semantics/cli.js +176 -0
  61. package/dist/lib/semantics/cli.js.map +1 -0
  62. package/dist/lib/semantics/envelope.js +603 -0
  63. package/dist/lib/semantics/envelope.js.map +1 -0
  64. package/dist/lib/semantics/format.js +37 -0
  65. package/dist/lib/semantics/format.js.map +1 -0
  66. package/dist/lib/semantics/index.js +34 -0
  67. package/dist/lib/semantics/index.js.map +1 -0
  68. package/dist/lib/semantics/types.js +74 -0
  69. package/dist/lib/semantics/types.js.map +1 -0
  70. package/dist/lib/trace-toolpack/traceToolpack.js +6 -0
  71. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  72. package/dist/types/core/agent/coverage/read.d.ts.map +1 -1
  73. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  74. package/dist/types/core/tools.d.ts +64 -0
  75. package/dist/types/core/tools.d.ts.map +1 -1
  76. package/dist/types/debug.d.ts +1 -0
  77. package/dist/types/debug.d.ts.map +1 -1
  78. package/dist/types/events/payloads.d.ts +49 -0
  79. package/dist/types/events/payloads.d.ts.map +1 -1
  80. package/dist/types/events/registry.d.ts +5 -1
  81. package/dist/types/events/registry.d.ts.map +1 -1
  82. package/dist/types/index.d.ts +2 -1
  83. package/dist/types/index.d.ts.map +1 -1
  84. package/dist/types/lib/mcp/mcpServe.d.ts.map +1 -1
  85. package/dist/types/lib/semantics/check.d.ts +71 -0
  86. package/dist/types/lib/semantics/check.d.ts.map +1 -0
  87. package/dist/types/lib/semantics/cli.d.ts +41 -0
  88. package/dist/types/lib/semantics/cli.d.ts.map +1 -0
  89. package/dist/types/lib/semantics/envelope.d.ts +140 -0
  90. package/dist/types/lib/semantics/envelope.d.ts.map +1 -0
  91. package/dist/types/lib/semantics/format.d.ts +12 -0
  92. package/dist/types/lib/semantics/format.d.ts.map +1 -0
  93. package/dist/types/lib/semantics/index.d.ts +15 -0
  94. package/dist/types/lib/semantics/index.d.ts.map +1 -0
  95. package/dist/types/lib/semantics/types.d.ts +231 -0
  96. package/dist/types/lib/semantics/types.d.ts.map +1 -0
  97. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  98. package/package.json +2 -1
@@ -0,0 +1,33 @@
1
+ /**
2
+ * semantics/format — rendering one {@link SemanticsReport} for a terminal.
3
+ *
4
+ * Pattern: the tool-lint `format.ts` sibling — pure string building, no IO.
5
+ * Role: lib/ layer, pure.
6
+ * Emits: N/A.
7
+ */
8
+ function findingLine(f) {
9
+ const mark = f.severity === 'error' ? '✗' : '⚠';
10
+ const where = f.resultIndex !== undefined ? ` result ${f.resultIndex + 1}` : '';
11
+ return ` ${mark} ${f.tool}${where} [${f.code}] field: ${f.field}\n ${f.message}`;
12
+ }
13
+ /** Render the report. Every finding names its tool and its field — the two
14
+ * facts a build log must carry for the fix to be a one-line edit. */
15
+ export function formatSemanticsReport(report) {
16
+ const errors = report.findings.filter((f) => f.severity === 'error');
17
+ const warnings = report.findings.filter((f) => f.severity === 'warning');
18
+ const lines = [
19
+ `check:semantics — ${report.checkedTools} tool${report.checkedTools === 1 ? '' : 's'}, ` +
20
+ `${report.checkedResults} sample result${report.checkedResults === 1 ? '' : 's'}`,
21
+ ];
22
+ if (report.findings.length === 0) {
23
+ lines.push(' ✓ every sampled result honors the semantic vocabulary and its class rules');
24
+ }
25
+ else {
26
+ for (const f of report.findings)
27
+ lines.push(findingLine(f));
28
+ }
29
+ lines.push(`${report.ok ? 'ok' : 'FAILED'} — ${errors.length} error${errors.length === 1 ? '' : 's'}, ` +
30
+ `${warnings.length} warning${warnings.length === 1 ? '' : 's'}`);
31
+ return lines.join('\n');
32
+ }
33
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../src/lib/semantics/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,SAAS,WAAW,CAAC,CAAmB;IACtC,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,MAAM,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;AAC3F,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IACzE,MAAM,KAAK,GAAa;QACtB,qBAAqB,MAAM,CAAC,YAAY,QAAQ,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;YACtF,GAAG,MAAM,CAAC,cAAc,iBAAiB,MAAM,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;KACpF,CAAC;IACF,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;IAC5F,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,MAAM,MAAM,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;QAC1F,GAAG,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAClE,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The semantic tool-result envelope + the `check:semantics` gate (9.53.0).
3
+ *
4
+ * The door: the main barrel publishes the AUTHORING half (`semantic()`, the
5
+ * recognizer, the vocabulary) — what a tool author writes and what a
6
+ * consumer reading raw results needs; `/observe` (via debug.ts) publishes
7
+ * the GATE half (`checkSemantics`, the CLI core, the formatter) — beside
8
+ * tool-lint, its pattern sibling. See README.md for the arguments.
9
+ */
10
+ export { composeNotCovered, coverageOfSemantics, explainSemantics, isCounterLookingAggregation, readSemantics, semantic, semanticIssues, semanticsForModel, type SemanticIssue, type SemanticIssueCode, } from './envelope.js';
11
+ export { checkSemantics, type SemanticsCatalogEntry, type SemanticsFinding, type SemanticsFindingCode, type SemanticsReport, } from './check.js';
12
+ export { formatSemanticsReport } from './format.js';
13
+ export { coerceSemanticsCatalog, runCheckSemanticsCli, type SemanticsCliIO } from './cli.js';
14
+ export { COUNTER_AGGREGATION_WORDS, RESULT_CLASSES, SEMANTICS_MARKER, SEMANTICS_NOTE, type SemanticClarify, type SemanticCoverage, type SemanticDeclaration, type SemanticEdge, type SemanticFact, type SemanticGrain, type SemanticProvenance, type SemanticRender, type SemanticSeriesPoint, type ToolResultClass, type ToolSemantics, } from './types.js';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The semantic tool-result envelope + the `check:semantics` gate (9.53.0).
3
+ *
4
+ * The door: the main barrel publishes the AUTHORING half (`semantic()`, the
5
+ * recognizer, the vocabulary) — what a tool author writes and what a
6
+ * consumer reading raw results needs; `/observe` (via debug.ts) publishes
7
+ * the GATE half (`checkSemantics`, the CLI core, the formatter) — beside
8
+ * tool-lint, its pattern sibling. See README.md for the arguments.
9
+ */
10
+ export { composeNotCovered, coverageOfSemantics, explainSemantics, isCounterLookingAggregation, readSemantics, semantic, semanticIssues, semanticsForModel, } from './envelope.js';
11
+ export { checkSemantics, } from './check.js';
12
+ export { formatSemanticsReport } from './format.js';
13
+ export { coerceSemanticsCatalog, runCheckSemanticsCli } from './cli.js';
14
+ export { COUNTER_AGGREGATION_WORDS, RESULT_CLASSES, SEMANTICS_MARKER, SEMANTICS_NOTE, } from './types.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/semantics/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,2BAA2B,EAC3B,aAAa,EACb,QAAQ,EACR,cAAc,EACd,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,cAAc,GAKf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAuB,MAAM,UAAU,CAAC;AAE7F,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,cAAc,GAYf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * semantics/types — the semantic tool-result vocabulary, as a PURE leaf
3
+ * (9.53.0, the `toolOutcome.ts` precedent).
4
+ *
5
+ * WHY IT LIVES HERE. Two sides read these words and neither may own the
6
+ * other: the agent loop's dispatch boundary (core/agent/stages/toolCalls.ts)
7
+ * recognizes the envelope at run time, and the `check:semantics` build gate
8
+ * (lib/semantics/check.ts) judges the same shapes with no agent anywhere in
9
+ * sight. Declaring the vocabulary in a leaf both sides import keeps the
10
+ * dependency pointing the right way — the loop and the gate depend on the
11
+ * words, never on each other.
12
+ *
13
+ * The one exception to "zero imports" is TYPE-ONLY and deliberate: the
14
+ * envelope's `coverage` field ABSORBS the existing coverage vocabulary
15
+ * (`CoverageItem` / `CoverageInput`, core/agent/coverage/types.ts — itself a
16
+ * pure-data leaf) instead of duplicating it. Two spellings of "ground this
17
+ * result does not cover" would eventually disagree; type-only imports erase
18
+ * at runtime, so this module stays a runtime leaf.
19
+ *
20
+ * ## What the envelope is
21
+ *
22
+ * A tool that answers "how many IOPS did fc1/3 do last hour?" today returns
23
+ * prose or an ad-hoc object, and every caveat that makes the number honest —
24
+ * the collection interval, whether the values are counters that must not be
25
+ * summed, when the world was actually measured, which clusters were not
26
+ * collected — is re-implemented by hand inside every tool and held in place
27
+ * by review. Culture scales to one disciplined author; it does not scale to
28
+ * a hundred tools. The semantic envelope makes those caveats TYPED DATA that
29
+ * travel with the values, so honesty is inherited, not re-authored — and so
30
+ * a build gate can refuse a triage tool that forgot its own limits.
31
+ *
32
+ * It is a SIBLING recognizer beside the effects envelope and the coverage
33
+ * primitives — its own reserved marker (`af_semantics`, the
34
+ * `af_absent`/`af_coverage` family), never new keys on the effects envelope.
35
+ * The three compose on one result: `{ content: semantic({…}), effects: […],
36
+ * status }` is a tool that returns typed data AND proposes a transition.
37
+ */
38
+ import type { CoverageDeclaration, CoverageItem } from '../../core/agent/coverage/types.js';
39
+ /**
40
+ * The reserved key that makes a semantic envelope recognizable. Reserved
41
+ * vocabulary on the tool-result wire (the `af_absent` / `af_coverage`
42
+ * precedent): a plain object carrying `af_semantics: true` that validates
43
+ * cleanly is an envelope; every other value any tool has ever returned keeps
44
+ * its bytes.
45
+ */
46
+ export declare const SEMANTICS_MARKER = "af_semantics";
47
+ /**
48
+ * One measured point. `t` is the tool's own clock words (an ISO string or an
49
+ * epoch number — the library never reinterprets it), `entity` is what was
50
+ * measured, `metric` names the measurement, `value` is the reading.
51
+ */
52
+ export interface SemanticSeriesPoint {
53
+ readonly t: string | number;
54
+ readonly entity: string;
55
+ readonly metric: string;
56
+ readonly value: number | string | boolean | null;
57
+ }
58
+ /**
59
+ * One row of typed facts about one entity. The columns are the tool's own —
60
+ * this library requires only that every row says WHAT it is about.
61
+ */
62
+ export interface SemanticFact {
63
+ readonly entity: string;
64
+ readonly [field: string]: unknown;
65
+ }
66
+ /** One typed relationship — "this VM rides that datastore", "this zone
67
+ * contains that WWPN". `kind` names the relationship in the tool's words. */
68
+ export interface SemanticEdge {
69
+ readonly from: string;
70
+ readonly to: string;
71
+ readonly kind: string;
72
+ readonly [field: string]: unknown;
73
+ }
74
+ /**
75
+ * The grain — what one value MEANS, stated when it is not what a reader
76
+ * would assume. This is the field that stops a model from adding
77
+ * `jobs_local` to `jobs_replicated_in` and announcing a fleet size nobody
78
+ * has.
79
+ */
80
+ export interface SemanticGrain {
81
+ /** The collection interval the values live on ('30m', '1h', 'daily'). */
82
+ readonly interval?: string;
83
+ /** How the values were folded ('avg', 'max', 'sum', 'count', …). */
84
+ readonly aggregation?: string;
85
+ /**
86
+ * Whether the values are counters. MUST be stated (true or false) whenever
87
+ * `aggregation` is counter-looking (see
88
+ * {@link COUNTER_AGGREGATION_WORDS}): summing two counters double-counts,
89
+ * and a reader cannot tell a counter from a gauge by looking at a number.
90
+ */
91
+ readonly is_counter?: boolean;
92
+ /** What was folded away ('per-port rows collapsed to per-switch'). */
93
+ readonly collapsed?: string;
94
+ }
95
+ /**
96
+ * Where the values came from and how old they are. `measured_at` is when the
97
+ * WORLD was measured — not when the tool ran; a tool that reads a nightly
98
+ * export and answers in 4ms is serving yesterday.
99
+ */
100
+ export interface SemanticProvenance {
101
+ /** When the world was measured (the tool's own clock words). Required
102
+ * whenever the envelope carries `series` or `facts`. */
103
+ readonly measured_at: string;
104
+ /** How stale the data was when the tool answered, in seconds. */
105
+ readonly age_seconds?: number;
106
+ /** The system of record the values were read from. Required with
107
+ * `measured_at`. */
108
+ readonly source: string;
109
+ /** For file-fed collectors: the export the values rode in on. */
110
+ readonly source_export_date?: string;
111
+ }
112
+ /**
113
+ * The ask-vs-answer decision, as data. A tool that matched three volumes for
114
+ * one WWN should not pick one silently — it should hand the question and the
115
+ * candidates back, typed, so the loop (or a UI) can ask.
116
+ */
117
+ export interface SemanticClarify {
118
+ readonly question: string;
119
+ /** The candidates the question is choosing between. May be empty — an open
120
+ * question is still a question. */
121
+ readonly candidates: readonly unknown[];
122
+ }
123
+ /**
124
+ * Rendering HINTS — the tool never renders. A UI that understands them draws
125
+ * a better table; one that does not loses nothing, because everything load-
126
+ * bearing is in the data fields. Dropped from the model's view entirely.
127
+ */
128
+ export interface SemanticRender {
129
+ /** The default presentation ('table', 'chart', 'prose', …). A hint. */
130
+ readonly default: string;
131
+ /** Column order for a tabular view. */
132
+ readonly columns?: readonly string[];
133
+ /** Sort hint ('avg_iops desc'). */
134
+ readonly sort?: string;
135
+ /** A note about what filtering already happened ('replicas excluded'). */
136
+ readonly filter_note?: string;
137
+ /** Chart-shape hint ('line per entity'). */
138
+ readonly chart_hint?: string;
139
+ }
140
+ /**
141
+ * The envelope's coverage, normalized — the SAME three-list vocabulary the
142
+ * `coverage()` / `absent()` primitives speak (checked / not checked / cannot
143
+ * cover), in the snake_case spelling every rendered tool shape uses because
144
+ * a model reads it more often than code does. Declared through
145
+ * {@link SemanticDeclaration.coverage} with the exact `CoverageDeclaration`
146
+ * input the `coverage()` primitive takes; the dispatch loop declares it
147
+ * through the same channel (`tools.coverage_declared`, tracked state, the
148
+ * final-answer limits block) — absorbed, never duplicated.
149
+ */
150
+ export interface SemanticCoverage {
151
+ readonly checked?: readonly CoverageItem[];
152
+ readonly not_checked?: readonly CoverageItem[];
153
+ readonly cannot_cover?: readonly CoverageItem[];
154
+ }
155
+ /**
156
+ * What a tool author passes to `semantic()`. At least one of `series`,
157
+ * `facts`, `edges` or a non-null `clarify` must be present — an envelope
158
+ * with no data and no question declares nothing.
159
+ *
160
+ * `not_covered` is deliberately NOT here: the prose list on the rendered
161
+ * envelope is DERIVED from `coverage` (not checked + cannot cover), so the
162
+ * two can never disagree. Declaring coverage is how not_covered is said.
163
+ */
164
+ export interface SemanticDeclaration {
165
+ readonly series?: readonly SemanticSeriesPoint[];
166
+ readonly facts?: readonly SemanticFact[];
167
+ readonly edges?: readonly SemanticEdge[];
168
+ readonly grain?: SemanticGrain;
169
+ readonly provenance?: SemanticProvenance;
170
+ /** The coverage()-vocabulary declaration this envelope absorbs. */
171
+ readonly coverage?: CoverageDeclaration;
172
+ /** `null` states "ambiguity was considered; there is none" — a fact, kept
173
+ * on the record. Omit the field to say nothing. */
174
+ readonly clarify?: SemanticClarify | null;
175
+ readonly render?: SemanticRender;
176
+ }
177
+ /**
178
+ * The rendered semantic envelope — the exact object a tool hands back.
179
+ * Field names are snake_case and English on purpose (the `ToolAbsence`
180
+ * precedent): this value is read by a language model far more often than by
181
+ * code, and `af_semantics` is the only field that exists for the machine.
182
+ */
183
+ export interface ToolSemantics {
184
+ readonly af_semantics: true;
185
+ readonly series?: readonly SemanticSeriesPoint[];
186
+ readonly facts?: readonly SemanticFact[];
187
+ readonly edges?: readonly SemanticEdge[];
188
+ readonly grain?: SemanticGrain;
189
+ readonly provenance?: SemanticProvenance;
190
+ readonly coverage?: SemanticCoverage;
191
+ /** DERIVED from `coverage` (not checked + cannot cover), one prose line
192
+ * per item — never author-set, so the list and the lists cannot drift. */
193
+ readonly not_covered?: readonly string[];
194
+ readonly clarify?: SemanticClarify | null;
195
+ readonly render?: SemanticRender;
196
+ /** The static sentence. Never interpolated — see `envelope.ts`. */
197
+ readonly note: string;
198
+ }
199
+ /**
200
+ * The declared class of a tool's RESULTS — what kind of answer this tool
201
+ * gives, stated by whoever wrote it (`defineTool({ resultClass })`; the
202
+ * `capabilities` law: declared, never inferred). The `check:semantics` gate
203
+ * keys its per-class rules on it:
204
+ *
205
+ * • `'triage'` — a verdict about health or fault. Every sample result must
206
+ * declare coverage: a triage that cannot say what it did NOT check turns
207
+ * "everything looks fine" into a claim about ground it never stood on.
208
+ * • `'inventory'` — a population listing. Every sample result must declare
209
+ * coverage ("4 of 5 clusters"), and one with `facts` but no `render`
210
+ * hint is warned at.
211
+ *
212
+ * Two classes, deliberately closed: each carries a rule the gate can PROVE.
213
+ * A class with no rule would be dead vocabulary.
214
+ */
215
+ export type ToolResultClass = 'triage' | 'inventory';
216
+ /** The closed set, as data — validators and docs read one list. */
217
+ export declare const RESULT_CLASSES: readonly ToolResultClass[];
218
+ /**
219
+ * Aggregation words that suggest the values are counters — the words that
220
+ * make `grain.is_counter` REQUIRED (stated true or false). Matched as whole
221
+ * tokens, singular or plural, case-insensitive.
222
+ */
223
+ export declare const COUNTER_AGGREGATION_WORDS: readonly string[];
224
+ /**
225
+ * The static sentence every semantic envelope carries in the model's view.
226
+ * Never interpolated (the `ABSENCE_NOTE` law): everything else the model
227
+ * reads is the tool's own data, and a note that quoted any of it back would
228
+ * hand the evidence corpus a second copy of values it already indexes.
229
+ */
230
+ export declare const SEMANTICS_NOTE: string;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * semantics/types — the semantic tool-result vocabulary, as a PURE leaf
3
+ * (9.53.0, the `toolOutcome.ts` precedent).
4
+ *
5
+ * WHY IT LIVES HERE. Two sides read these words and neither may own the
6
+ * other: the agent loop's dispatch boundary (core/agent/stages/toolCalls.ts)
7
+ * recognizes the envelope at run time, and the `check:semantics` build gate
8
+ * (lib/semantics/check.ts) judges the same shapes with no agent anywhere in
9
+ * sight. Declaring the vocabulary in a leaf both sides import keeps the
10
+ * dependency pointing the right way — the loop and the gate depend on the
11
+ * words, never on each other.
12
+ *
13
+ * The one exception to "zero imports" is TYPE-ONLY and deliberate: the
14
+ * envelope's `coverage` field ABSORBS the existing coverage vocabulary
15
+ * (`CoverageItem` / `CoverageInput`, core/agent/coverage/types.ts — itself a
16
+ * pure-data leaf) instead of duplicating it. Two spellings of "ground this
17
+ * result does not cover" would eventually disagree; type-only imports erase
18
+ * at runtime, so this module stays a runtime leaf.
19
+ *
20
+ * ## What the envelope is
21
+ *
22
+ * A tool that answers "how many IOPS did fc1/3 do last hour?" today returns
23
+ * prose or an ad-hoc object, and every caveat that makes the number honest —
24
+ * the collection interval, whether the values are counters that must not be
25
+ * summed, when the world was actually measured, which clusters were not
26
+ * collected — is re-implemented by hand inside every tool and held in place
27
+ * by review. Culture scales to one disciplined author; it does not scale to
28
+ * a hundred tools. The semantic envelope makes those caveats TYPED DATA that
29
+ * travel with the values, so honesty is inherited, not re-authored — and so
30
+ * a build gate can refuse a triage tool that forgot its own limits.
31
+ *
32
+ * It is a SIBLING recognizer beside the effects envelope and the coverage
33
+ * primitives — its own reserved marker (`af_semantics`, the
34
+ * `af_absent`/`af_coverage` family), never new keys on the effects envelope.
35
+ * The three compose on one result: `{ content: semantic({…}), effects: […],
36
+ * status }` is a tool that returns typed data AND proposes a transition.
37
+ */
38
+ /**
39
+ * The reserved key that makes a semantic envelope recognizable. Reserved
40
+ * vocabulary on the tool-result wire (the `af_absent` / `af_coverage`
41
+ * precedent): a plain object carrying `af_semantics: true` that validates
42
+ * cleanly is an envelope; every other value any tool has ever returned keeps
43
+ * its bytes.
44
+ */
45
+ export const SEMANTICS_MARKER = 'af_semantics';
46
+ /** The closed set, as data — validators and docs read one list. */
47
+ export const RESULT_CLASSES = ['triage', 'inventory'];
48
+ /**
49
+ * Aggregation words that suggest the values are counters — the words that
50
+ * make `grain.is_counter` REQUIRED (stated true or false). Matched as whole
51
+ * tokens, singular or plural, case-insensitive.
52
+ */
53
+ export const COUNTER_AGGREGATION_WORDS = [
54
+ 'sum',
55
+ 'count',
56
+ 'total',
57
+ 'cumulative',
58
+ 'counter',
59
+ 'delta',
60
+ ];
61
+ /**
62
+ * The static sentence every semantic envelope carries in the model's view.
63
+ * Never interpolated (the `ABSENCE_NOTE` law): everything else the model
64
+ * reads is the tool's own data, and a note that quoted any of it back would
65
+ * hand the evidence corpus a second copy of values it already indexes.
66
+ */
67
+ export const SEMANTICS_NOTE = 'Typed data, not prose. `grain` and `provenance` are caveats that travel with the ' +
68
+ 'numbers: check `is_counter` before summing values from a series, read `measured_at` ' +
69
+ '(and `age_seconds`) as how old the data is, and treat everything under `not_covered` ' +
70
+ 'as ground this result does NOT cover — a clean look here says nothing about it.';
71
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/semantics/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAIH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAsL/C,mEAAmE;AACnE,MAAM,CAAC,MAAM,cAAc,GAA+B,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAElF;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,KAAK;IACL,OAAO;IACP,OAAO;IACP,YAAY;IACZ,SAAS;IACT,OAAO;CACR,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GACzB,mFAAmF;IACnF,sFAAsF;IACtF,uFAAuF;IACvF,iFAAiF,CAAC"}
@@ -1517,6 +1517,12 @@ const OFFLINE_CONTEXT = {
1517
1517
  // Offline has no run to scope refs to; the capability teaches, never lies.
1518
1518
  artifacts: unconfiguredArtifacts(),
1519
1519
  hasArtifacts: false,
1520
+ // Offline has no stage to emit from and no dispatcher to reach (9.52.0);
1521
+ // a progress report is dropped rather than refused, because losing telemetry
1522
+ // is not a reason to fail a call that is doing its work.
1523
+ progress: () => {
1524
+ /* nowhere to file it offline — see the note above */
1525
+ },
1520
1526
  teardownScopes: [],
1521
1527
  onTeardown: () => {
1522
1528
  throw new Error('callTraceTool: onTeardown is not honoured offline — `ctx.teardownScopes` is empty, ' +