@sensigo/realm 0.41.0 → 0.43.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.
- package/dist/adapters/gorgias-adapter.d.ts.map +1 -1
- package/dist/adapters/gorgias-adapter.js +39 -10
- package/dist/adapters/gorgias-adapter.js.map +1 -1
- package/dist/engine/execution-loop.d.ts.map +1 -1
- package/dist/engine/execution-loop.js +124 -21
- package/dist/engine/execution-loop.js.map +1 -1
- package/dist/engine/run-health.d.ts +1 -1
- package/dist/engine/run-health.d.ts.map +1 -1
- package/dist/engine/run-health.js +49 -4
- package/dist/engine/run-health.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/types/run-record.d.ts +11 -1
- package/dist/types/run-record.d.ts.map +1 -1
- package/dist/types/run-record.js.map +1 -1
- package/dist/types/workflow-definition.d.ts +146 -10
- package/dist/types/workflow-definition.d.ts.map +1 -1
- package/dist/types/workflow-definition.js +225 -0
- package/dist/types/workflow-definition.js.map +1 -1
- package/dist/types/workflow-error.d.ts +1 -1
- package/dist/types/workflow-error.d.ts.map +1 -1
- package/dist/types/workflow-error.js.map +1 -1
- package/dist/workflow/diagnostics.d.ts +41 -5
- package/dist/workflow/diagnostics.d.ts.map +1 -1
- package/dist/workflow/diagnostics.js +34 -6
- package/dist/workflow/diagnostics.js.map +1 -1
- package/dist/workflow/registrar.d.ts +42 -0
- package/dist/workflow/registrar.d.ts.map +1 -1
- package/dist/workflow/registrar.js +57 -0
- package/dist/workflow/registrar.js.map +1 -1
- package/dist/workflow/step-key-registry.d.ts +1258 -0
- package/dist/workflow/step-key-registry.d.ts.map +1 -0
- package/dist/workflow/step-key-registry.js +1217 -0
- package/dist/workflow/step-key-registry.js.map +1 -0
- package/dist/workflow/yaml-loader.d.ts +16 -0
- package/dist/workflow/yaml-loader.d.ts.map +1 -1
- package/dist/workflow/yaml-loader.js +581 -345
- package/dist/workflow/yaml-loader.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
/** Strips block and line comments, then collapses every whitespace run to a single space. Run on
|
|
2
|
+
* BOTH the real source and the registry's own pattern before matching, so a pattern can be
|
|
3
|
+
* written as a readable one-line slice of code that may itself span or sit beside comments in
|
|
4
|
+
* the file. The single-char lookback on `//` keeps a `https://…` literal from being truncated as
|
|
5
|
+
* if it opened a line comment.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately a manual, single left-to-right scan rather than the equivalent lazy-regex pair
|
|
8
|
+
* (`/\/\*[\s\S]*?\*\//g` + a lookback-guarded `//` strip) that a first draft of this file
|
|
9
|
+
* shipped: CodeQL flagged that pair as a genuine polynomial-time DoS — a run of unterminated
|
|
10
|
+
* `/*` occurrences (no closing `*\/` anywhere after them) forces a full failed scan-to-end for
|
|
11
|
+
* EACH occurrence, which is quadratic in the number of occurrences. The scan below still does at
|
|
12
|
+
* most one `indexOf` per comment opener, but a failed `indexOf` (no closer anywhere in the rest
|
|
13
|
+
* of the string) ends the whole pass immediately — linear, not quadratic, in the worst case. */
|
|
14
|
+
export function normalizeSource(text) {
|
|
15
|
+
let out = '';
|
|
16
|
+
const n = text.length;
|
|
17
|
+
let i = 0;
|
|
18
|
+
// Once a single `indexOf('*/', k)` call returns -1, no `/*` found at any LATER position can
|
|
19
|
+
// ever close either — its search range is a strict suffix of the one that already failed. This
|
|
20
|
+
// flag turns that monotonicity into a hard cap of ONE failed full-length scan for the entire
|
|
21
|
+
// call, however many unclosed `/*` occurrences follow — without it, a string built from many
|
|
22
|
+
// `/*` openers and no closer anywhere would cost one failed O(remaining-length) scan PER
|
|
23
|
+
// opener, which is exactly the quadratic shape CodeQL flagged in the lazy-regex draft this
|
|
24
|
+
// replaced.
|
|
25
|
+
let noMoreBlockClosersAhead = false;
|
|
26
|
+
while (i < n) {
|
|
27
|
+
const ch = text[i];
|
|
28
|
+
const nextCh = i + 1 < n ? text[i + 1] : '';
|
|
29
|
+
if (!noMoreBlockClosersAhead && ch === '/' && nextCh === '*') {
|
|
30
|
+
const close = text.indexOf('*/', i + 2);
|
|
31
|
+
if (close === -1) {
|
|
32
|
+
// No closer anywhere ahead — the original regex would fail to match here too, leaving
|
|
33
|
+
// this `/*` as literal text. Emit it as-is and continue scanning normally; the flag
|
|
34
|
+
// above stops this branch from ever paying for another full scan.
|
|
35
|
+
noMoreBlockClosersAhead = true;
|
|
36
|
+
out += ch;
|
|
37
|
+
i += 1;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
out += ' ';
|
|
41
|
+
i = close + 2;
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (ch === '/' && nextCh === '/') {
|
|
46
|
+
const prevCh = i === 0 ? '' : text[i - 1];
|
|
47
|
+
if (prevCh === ':' || prevCh === '"' || prevCh === "'") {
|
|
48
|
+
out += ch;
|
|
49
|
+
i += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const newlineAt = text.indexOf('\n', i);
|
|
53
|
+
i = newlineAt === -1 ? n : newlineAt; // the newline itself, if any, is left for the next pass
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
out += ch;
|
|
57
|
+
i += 1;
|
|
58
|
+
}
|
|
59
|
+
return out.replace(/\s+/g, ' ');
|
|
60
|
+
}
|
|
61
|
+
/** Exact non-overlapping occurrence count of `pattern` inside `source`, both normalized first. */
|
|
62
|
+
export function countWitnessMatches(source, pattern) {
|
|
63
|
+
const hay = normalizeSource(source);
|
|
64
|
+
const needle = normalizeSource(pattern).trim();
|
|
65
|
+
if (needle.length === 0)
|
|
66
|
+
return 0;
|
|
67
|
+
let count = 0;
|
|
68
|
+
let i = hay.indexOf(needle);
|
|
69
|
+
while (i !== -1) {
|
|
70
|
+
count += 1;
|
|
71
|
+
i = hay.indexOf(needle, i + needle.length);
|
|
72
|
+
}
|
|
73
|
+
return count;
|
|
74
|
+
}
|
|
75
|
+
// File-path shorthands, repo-root-relative — the convention purge-guard.test.ts already
|
|
76
|
+
// established for a cross-package source-text read: each conformance runner resolves these from
|
|
77
|
+
// its own package location, never from cwd.
|
|
78
|
+
const EL = 'packages/core/src/engine/execution-loop.ts';
|
|
79
|
+
const ELIG = 'packages/core/src/engine/eligibility.ts';
|
|
80
|
+
const SETTLE = 'packages/core/src/engine/settlement.ts';
|
|
81
|
+
const CL = 'packages/core/src/engine/claim-liveness.ts';
|
|
82
|
+
const YL = 'packages/core/src/workflow/yaml-loader.ts';
|
|
83
|
+
const RA = 'packages/cli/src/agent/run-agent.ts';
|
|
84
|
+
const RECLAIM = 'packages/cli/src/commands/reclaim.ts';
|
|
85
|
+
const GEN = 'packages/mcp-server/src/protocol/generator.ts';
|
|
86
|
+
// #517 (the drive-flip): every minted prohibition's `by[]` carries this ONE witness — the mint
|
|
87
|
+
// walk's own error-construction shape in yaml-loader.ts, exact-count 1. The per-key hand-written
|
|
88
|
+
// firing conditions these cells used to cite, and the two kind-prohibition loops, are DELETED by
|
|
89
|
+
// the flip; the mint is now the single enforcement mechanism, so this one shared witness is the
|
|
90
|
+
// truthful successor (a corruption of the walk reds every minted cell's witness check at once —
|
|
91
|
+
// by design). Except-bearing and `blocked_transitive` cells keep their own live, hand-written
|
|
92
|
+
// witnesses below.
|
|
93
|
+
export const MINT_WITNESS_PATTERN = "errors.push( withKeyLine( stepName, key, `Step '${stepName}': ${renderRegistryProhibition(key, kind, cell)}`,";
|
|
94
|
+
const MINT = { file: YL, pattern: MINT_WITNESS_PATTERN };
|
|
95
|
+
// ——— message_data: the invariant tails of the shipped bespoke messages (see header) ———
|
|
96
|
+
const MSG_ON_OUTCOME = "'on_outcome' is only valid on execution: finalizer steps — it selects which finalizers run " +
|
|
97
|
+
'for a given outcome, and only finalizers are selected that way, so here it would decide ' +
|
|
98
|
+
'nothing. Move it to the finalizer that should react to the outcome, or remove it.';
|
|
99
|
+
const MSG_ABORT_UNLESS = "'abort_unless' is only valid on execution: guard steps — it is the condition list a guard " +
|
|
100
|
+
'evaluates before letting the run continue, and only guard steps are evaluated that way, so ' +
|
|
101
|
+
'here it would gate nothing. Put the check on a guard step, or remove it.';
|
|
102
|
+
const MSG_ABORT_MESSAGE = "'abort_message' is only valid on execution: guard steps — it is the text reported when a " +
|
|
103
|
+
'guard aborts the run, and nothing but a guard reads it, so here it would never be read. ' +
|
|
104
|
+
'Move it to the guard that performs the abort, or remove it.';
|
|
105
|
+
const MSG_AGENT_PROFILE = "'agent_profile' is only valid on execution: agent steps — its content is resolved into the " +
|
|
106
|
+
'model prompt, and only an agent step makes a model request, so here it would reach no ' +
|
|
107
|
+
'model. Move it to the agent step whose prompt it should shape, or remove it.';
|
|
108
|
+
const MSG_LLM_TIMEOUT = "'llm_timeout_seconds' is only valid on execution: agent steps — it bounds one model " +
|
|
109
|
+
'request, and no other kind makes one, so here it would bound nothing. Move it to the agent ' +
|
|
110
|
+
"step whose request it should bound, or remove it. An auto step's dispatch is bounded by " +
|
|
111
|
+
"'timeout_seconds', and a finalizer's handler by its own 'timeout_seconds'.";
|
|
112
|
+
const MSG_IDEMPOTENT = "'idempotent' is only valid on execution: auto steps — it gates 'retry.on_timeout' and " +
|
|
113
|
+
'reclaim eligibility, and both act on auto dispatch, so here it would gate nothing. Remove ' +
|
|
114
|
+
'it, or move the work to an auto step if you need either.';
|
|
115
|
+
const MSG_TIMEOUT_ON_AGENT = "'timeout_seconds' is not valid on execution: agent steps — the engine never enforces it " +
|
|
116
|
+
'there (agent dispatch is never wrapped in a timeout), so the step would LOOK time-bounded ' +
|
|
117
|
+
"while nothing enforced the bound. In realm's own drive the model request is bounded by " +
|
|
118
|
+
"'llm_timeout_seconds' (or --llm-timeout) and tool calls by 'tool_timeout'.";
|
|
119
|
+
const MSG_PRECONDITIONS_GUARD = "'preconditions' is not valid on execution: guard steps — the engine never evaluates it " +
|
|
120
|
+
"there (a guard's execution evaluates only 'abort_unless'), so the run would LOOK guarded " +
|
|
121
|
+
"while the declared check never ran. Move the condition into 'abort_unless'. Whether guards " +
|
|
122
|
+
'gain a live condition surface is an open design question (issue #366) — if admitted later, ' +
|
|
123
|
+
'existing workflows are unaffected.';
|
|
124
|
+
const MSG_TOOL_TIMEOUT = "'tool_timeout' requires 'tools' (a declared, non-empty list) — without tool calls there is " +
|
|
125
|
+
'nothing for it to bound, so the step would carry a bound with nothing to bind. In ' +
|
|
126
|
+
"realm's own drive each tool call is capped at tool_timeout seconds (default 30); declare " +
|
|
127
|
+
'at least one tool or remove the key.';
|
|
128
|
+
// ——— surviving hand-written by-witnesses (#517): only the except-bearing trust×finalizer
|
|
129
|
+
// value-conditional check and the blocked_transitive tool_timeout companion check keep live
|
|
130
|
+
// per-key firing conditions in the loader; every other prohibition is minted (MINT, above) ———
|
|
131
|
+
const BY_TOOL_TIMEOUT = {
|
|
132
|
+
file: YL,
|
|
133
|
+
pattern: "if (step['tool_timeout'] !== undefined && toolsMissing) {",
|
|
134
|
+
};
|
|
135
|
+
const BY_TRUST_FINALIZER = {
|
|
136
|
+
file: YL,
|
|
137
|
+
pattern: "if (step['trust'] !== undefined && step['trust'] !== 'auto') {",
|
|
138
|
+
};
|
|
139
|
+
// ——— recurring consumed witnesses (shared across more than one cell, and — new in #517 — also
|
|
140
|
+
// referenced as a CONSUMED_HOME.site: the message's factual citation IS the tested witness) ———
|
|
141
|
+
const W_WHEN_ELIG = {
|
|
142
|
+
file: ELIG,
|
|
143
|
+
pattern: 'if (!evaluateWhen(step.when, evidenceByStep, run.params)) continue;',
|
|
144
|
+
count: 2, // DAG eligibility's own check + the guard-selection walk share the same evaluator call
|
|
145
|
+
};
|
|
146
|
+
const W_DEPENDS_ON = {
|
|
147
|
+
file: ELIG,
|
|
148
|
+
pattern: 'const deps = step.depends_on ?? [];',
|
|
149
|
+
count: 3, // trigger-rule satisfaction, the skip-propagation pass, and the skip-cascade walk
|
|
150
|
+
};
|
|
151
|
+
const W_TRIGGER_RULE = {
|
|
152
|
+
file: ELIG,
|
|
153
|
+
pattern: "const rule: TriggerRule = step.trigger_rule ?? 'all_success';",
|
|
154
|
+
count: 2, // trigger-rule satisfaction and skip-propagation resolve it the same way
|
|
155
|
+
};
|
|
156
|
+
// Deliberately the Step-2a READ shape, never the checkPreconditions CALL text: the #369
|
|
157
|
+
// call-site walker (yaml-loader.test.ts) counts every non-test line carrying that call text —
|
|
158
|
+
// comments included, since it is line-based — so spelling the call itself here would register as
|
|
159
|
+
// a second call site and red that unrelated walker (witness-collision class, header above). This
|
|
160
|
+
// read shape is the same consumption evidence without the collision.
|
|
161
|
+
const W_PRECONDITIONS = {
|
|
162
|
+
file: EL,
|
|
163
|
+
pattern: 'if (stepDef?.preconditions !== undefined && stepDef.preconditions.length > 0) {',
|
|
164
|
+
};
|
|
165
|
+
const W_GATE_MINT_TRUST = {
|
|
166
|
+
file: EL,
|
|
167
|
+
// single-sourced via isGateTrust (was two hand-copied literals, the drift the
|
|
168
|
+
// TRUST_LEVELS/GATE_TRUST_LEVELS vocabulary exists to close).
|
|
169
|
+
pattern: 'if (isGateTrust(stepDef!.trust)) {',
|
|
170
|
+
};
|
|
171
|
+
// The engine's fail-closed backstop: a step whose trust value is neither absent nor a
|
|
172
|
+
// recognized member is refused at dispatch, pre-claim — this is what closes the un-gate hole
|
|
173
|
+
// W_GATE_MINT_TRUST alone left open (an unrecognized value used to fall through the mint
|
|
174
|
+
// untouched and run un-gated; now it never reaches the mint at all).
|
|
175
|
+
const W_TRUST_VALUE_REFUSAL = {
|
|
176
|
+
file: EL,
|
|
177
|
+
pattern: "classifyStepTrust(stepDef?.execution, stepDef?.trust) === 'refuse'",
|
|
178
|
+
};
|
|
179
|
+
const W_GATE_CHOICES = {
|
|
180
|
+
file: EL,
|
|
181
|
+
pattern: "stepDef!.gate?.choices ?? stepDef!.input_schema?.properties?.['choice']?.enum;",
|
|
182
|
+
};
|
|
183
|
+
const W_INPUT_SCHEMA_2B = {
|
|
184
|
+
file: EL,
|
|
185
|
+
pattern: 'validateInputSchema(effectiveInput, stepDef.input_schema, options.command);',
|
|
186
|
+
};
|
|
187
|
+
const W_DESCRIPTION_GEN = { file: GEN, pattern: 'description: step.description,' };
|
|
188
|
+
const W_TOOLS_PATH = {
|
|
189
|
+
file: RA,
|
|
190
|
+
pattern: 'if (stepDef.tools && stepDef.tools.length > 0 && mcpClient) {',
|
|
191
|
+
};
|
|
192
|
+
const W_PROMPT_NEXTACTION = {
|
|
193
|
+
file: EL,
|
|
194
|
+
pattern: 'step.prompt !== undefined ? renderTemplate(step.prompt, context) : undefined;',
|
|
195
|
+
};
|
|
196
|
+
const W_ADAPTER_DISPATCH = {
|
|
197
|
+
file: EL,
|
|
198
|
+
pattern: "if (stepDef?.execution === 'auto' && stepDef.uses_service !== undefined) {",
|
|
199
|
+
};
|
|
200
|
+
const W_SERVICE_METHOD_READ = {
|
|
201
|
+
file: EL,
|
|
202
|
+
pattern: "const method = stepDef.service_method ?? 'fetch';",
|
|
203
|
+
};
|
|
204
|
+
const W_OPERATION_READ = {
|
|
205
|
+
file: EL,
|
|
206
|
+
pattern: 'const operation = stepDef.operation ?? options.command;',
|
|
207
|
+
};
|
|
208
|
+
const W_INPUT_MAP_RESOLVE = {
|
|
209
|
+
file: EL,
|
|
210
|
+
pattern: 'const adapterParams = resolveInputMap(stepDef.input_map, options, pendingRun);',
|
|
211
|
+
};
|
|
212
|
+
const W_HANDLER_AUTO_DISPATCH = {
|
|
213
|
+
file: EL,
|
|
214
|
+
pattern: "} else if (stepDef?.execution === 'auto' && stepDef.handler !== undefined) {",
|
|
215
|
+
};
|
|
216
|
+
const W_OUTPUT_SCHEMA_READ = {
|
|
217
|
+
file: EL,
|
|
218
|
+
pattern: "stepDef?.execution === 'agent' && stepDef.output_schema !== undefined",
|
|
219
|
+
};
|
|
220
|
+
const W_TRACE_SCHEMA_READ = {
|
|
221
|
+
file: EL,
|
|
222
|
+
pattern: 'if (stepDef.trace_schema !== undefined) {',
|
|
223
|
+
};
|
|
224
|
+
const W_TRACE_MODE_READ = {
|
|
225
|
+
file: EL,
|
|
226
|
+
pattern: "const mode = stepDef.trace_validation_mode ?? 'warn';",
|
|
227
|
+
};
|
|
228
|
+
const W_RETRY_READ = { file: EL, pattern: 'const retryConfig = stepDef?.retry;' };
|
|
229
|
+
const W_VALIDATION_EXHAUSTION_READ = {
|
|
230
|
+
file: EL,
|
|
231
|
+
pattern: 'stepDef.validation_exhaustion?.threshold ?? DEFAULT_VALIDATION_EXHAUSTION_THRESHOLD;',
|
|
232
|
+
};
|
|
233
|
+
const W_STRUCTURED_OUTPUT_READ = {
|
|
234
|
+
file: EL,
|
|
235
|
+
pattern: '...(stepDef?.structured_output !== undefined',
|
|
236
|
+
count: 3, // the attempt disclosure is minted at all three seal shapes (census lane 2)
|
|
237
|
+
};
|
|
238
|
+
const W_TIMEOUT_ENFORCE = {
|
|
239
|
+
file: EL,
|
|
240
|
+
pattern: 'const enforceTimeout = stepDef !== undefined && shouldEnforceTimeout(stepDef);',
|
|
241
|
+
};
|
|
242
|
+
/** #517 rung 2: file-shorthand → the operator phrase a consequence clause names it by. TOTAL over
|
|
243
|
+
* every file this registry cites as a witness (conformance-checked below — a missing entry is a
|
|
244
|
+
* red cell, not a silent fallback). Operator words, never file basenames (D7-5). */
|
|
245
|
+
export const SURFACE_NAME = {
|
|
246
|
+
[EL]: "the engine's execution loop",
|
|
247
|
+
[ELIG]: 'step eligibility',
|
|
248
|
+
[SETTLE]: 'finalizer selection',
|
|
249
|
+
[CL]: 'claim liveness',
|
|
250
|
+
[YL]: 'the workflow loader',
|
|
251
|
+
[RA]: "realm's own drive",
|
|
252
|
+
[RECLAIM]: 'the reclaim command',
|
|
253
|
+
[GEN]: 'the protocol briefing',
|
|
254
|
+
};
|
|
255
|
+
/** The minted text for one refused kind: the per-kind arm when one exists for it, else the
|
|
256
|
+
* shared default. */
|
|
257
|
+
export function homeText(text, kind) {
|
|
258
|
+
if (typeof text === 'string')
|
|
259
|
+
return text;
|
|
260
|
+
return text[kind] ?? text.default;
|
|
261
|
+
}
|
|
262
|
+
/** Every DISTINCT string a `PerKindText` can mint, across all kinds — what the truth cells
|
|
263
|
+
* assert over (strictly stronger than asserting only the `default` arm). */
|
|
264
|
+
export function homeTextVariants(text) {
|
|
265
|
+
if (typeof text === 'string')
|
|
266
|
+
return [text];
|
|
267
|
+
return [...new Set(Object.values(text))];
|
|
268
|
+
}
|
|
269
|
+
export const CONSUMED_HOME = {
|
|
270
|
+
depends_on: {
|
|
271
|
+
kinds: ['auto', 'agent', 'guard'],
|
|
272
|
+
mechanism: 'step eligibility reads it to gate when a DAG step becomes runnable, and a finalizer is ' +
|
|
273
|
+
"selected by 'on_outcome' at settlement, never through the DAG, so here it would order " +
|
|
274
|
+
'nothing.',
|
|
275
|
+
site: W_DEPENDS_ON,
|
|
276
|
+
// #417 wording defect: 'Sequence' overclaimed depends_on's own job — depends_on only ORDERS
|
|
277
|
+
// (a precondition on WHEN a step becomes eligible); 'on_outcome' is what actually SELECTS
|
|
278
|
+
// which finalizers run for a given outcome. 'Trigger' names the device that does the job.
|
|
279
|
+
remedy: "Trigger the finalizer with 'on_outcome' instead, or remove it.",
|
|
280
|
+
},
|
|
281
|
+
trigger_rule: {
|
|
282
|
+
kinds: ['auto', 'agent'],
|
|
283
|
+
// #417 wording defect (falsity): a guard's OWN cell is gated by trigger_rule identically to
|
|
284
|
+
// a DAG step — the loader forbids the DECLARATION, not the mechanism; "would gate nothing"
|
|
285
|
+
// and "only auto/agent steps are gated that way" were both false for the guard population.
|
|
286
|
+
mechanism: {
|
|
287
|
+
default: 'step eligibility reads it to decide how dependency outcomes gate a DAG step, and a ' +
|
|
288
|
+
"finalizer is selected by 'on_outcome' at settlement, never through the DAG, so here " +
|
|
289
|
+
'it would gate nothing.',
|
|
290
|
+
guard: 'step eligibility reads it on a guard exactly as on a DAG step, so it would silently ' +
|
|
291
|
+
'change when the guard runs and when it is skipped; a guard is deliberately gated by ' +
|
|
292
|
+
'the plain success of its dependencies.',
|
|
293
|
+
},
|
|
294
|
+
site: W_TRIGGER_RULE,
|
|
295
|
+
remedy: {
|
|
296
|
+
default: "Trigger the finalizer with 'on_outcome' instead, or remove it.",
|
|
297
|
+
// issue #366 tracks widening guards to a configurable trigger rule — the in-tree
|
|
298
|
+
// precedent for a re-admission clause on a per-kind remedy arm.
|
|
299
|
+
guard: 'Move it to the auto or agent step it should gate, or remove it — a guard itself ' +
|
|
300
|
+
"always gates on 'all_success' (issue #366 tracks widening guards).",
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
when: {
|
|
304
|
+
kinds: ['auto', 'agent', 'guard'],
|
|
305
|
+
mechanism: 'step eligibility evaluates it before a step may run, and a finalizer is selected by the ' +
|
|
306
|
+
"run's outcome at settlement, never by eligibility, so here it would route nothing.",
|
|
307
|
+
site: W_WHEN_ELIG,
|
|
308
|
+
// issue #360 tracks a mint-time 'when' evaluation for finalizers (routing a cleanup step on
|
|
309
|
+
// which dependency failed) — the re-admission clause the four-clause policy asks for where a
|
|
310
|
+
// genuine widening is on the board. Today's honest remedy: the failure context 'when' would
|
|
311
|
+
// have carried is already reachable inside the handler.
|
|
312
|
+
remedy: "Route the finalizer with 'on_outcome' instead, or remove it. 'on_outcome' matches run " +
|
|
313
|
+
'outcomes only — a condition (run params, step evidence) branches inside the handler, ' +
|
|
314
|
+
"whose context carries run_params and resources['$settlement'].<step>.failed (issue " +
|
|
315
|
+
"#360 tracks widening finalizers with a mint-time 'when').",
|
|
316
|
+
},
|
|
317
|
+
uses_service: {
|
|
318
|
+
kinds: ['auto'],
|
|
319
|
+
mechanism: "the engine's execution loop routes a step's work through the named service adapter only " +
|
|
320
|
+
'on the auto dispatch path, so here it would dispatch nothing.',
|
|
321
|
+
site: W_ADAPTER_DISPATCH,
|
|
322
|
+
remedy: {
|
|
323
|
+
default: 'Move it to an auto step, or remove it.',
|
|
324
|
+
// #417 wording defect (overclaim): "move it to an auto step" implies EVERY auto step
|
|
325
|
+
// reaches the adapter path; a finalizer's own home for the same service call is its
|
|
326
|
+
// handler, not a DAG relocation.
|
|
327
|
+
finalizer: "Do the service call inside the finalizer's 'handler' instead (a finalizer runs " +
|
|
328
|
+
'handler-only), or remove it.',
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
service_method: {
|
|
332
|
+
kinds: ['auto'],
|
|
333
|
+
// #417 wording defect (falsity): named the SIBLING key's axis — service_method picks the
|
|
334
|
+
// adapter METHOD, not the operation (that's `operation`, below) — and the "auto dispatch
|
|
335
|
+
// path" overclaimed scope: only a step that dispatches through 'uses_service' reads it.
|
|
336
|
+
mechanism: "the engine's execution loop reads it to pick the adapter method on the uses_service " +
|
|
337
|
+
'adapter dispatch path, so here it would pick nothing.',
|
|
338
|
+
site: W_SERVICE_METHOD_READ,
|
|
339
|
+
remedy: "Move it to an auto step that dispatches through 'uses_service', or remove it.",
|
|
340
|
+
},
|
|
341
|
+
operation: {
|
|
342
|
+
kinds: ['auto'],
|
|
343
|
+
// #417 wording defect (overclaim): "the auto dispatch path" implied every auto step reads
|
|
344
|
+
// it; only the 'uses_service' adapter arm does.
|
|
345
|
+
mechanism: "the engine's execution loop reads it as the adapter operation name on the uses_service " +
|
|
346
|
+
'adapter dispatch path, so here it would name nothing.',
|
|
347
|
+
site: W_OPERATION_READ,
|
|
348
|
+
remedy: "Move it to an auto step that dispatches through 'uses_service', or remove it.",
|
|
349
|
+
},
|
|
350
|
+
input_map: {
|
|
351
|
+
kinds: ['auto'],
|
|
352
|
+
mechanism: {
|
|
353
|
+
// #417 wording defect (overclaim + underclaim): "on the auto path" implied every auto
|
|
354
|
+
// step resolves it; only the two dispatch arms (uses_service, handler) do.
|
|
355
|
+
default: "the engine's execution loop resolves it into dispatch parameters when an auto step " +
|
|
356
|
+
"dispatches through 'uses_service' or a handler, so here it would map nothing.",
|
|
357
|
+
// #417 wording defect (falsity, probe-executed): a finalizer's drain shares the SAME
|
|
358
|
+
// handler-dispatch code path that resolves input_map on auto — "would map nothing" is
|
|
359
|
+
// false; it would map something the finalizer's contract never wanted. Refused outright,
|
|
360
|
+
// not left to a true-but-misleading inertness claim.
|
|
361
|
+
finalizer: "the engine's execution loop resolves it into dispatch parameters at handler dispatch " +
|
|
362
|
+
'— the finalizer drain shares that dispatch — so it is refused here outright rather ' +
|
|
363
|
+
"than trusted to be inert: a finalizer's handler takes no mapped input, and run data " +
|
|
364
|
+
'reaches it through its context instead.',
|
|
365
|
+
},
|
|
366
|
+
site: W_INPUT_MAP_RESOLVE,
|
|
367
|
+
remedy: {
|
|
368
|
+
default: "Move it to an auto step that dispatches through 'uses_service' or a handler, or " +
|
|
369
|
+
'remove it.',
|
|
370
|
+
finalizer: "Move it to an auto step that dispatches through 'uses_service' or a handler, or " +
|
|
371
|
+
"remove it — a finalizer's handler already receives run params and step evidence " +
|
|
372
|
+
"through its context, and static values through 'config'.",
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
handler: {
|
|
376
|
+
kinds: ['auto', 'agent', 'finalizer'],
|
|
377
|
+
// #417 wording defect (falsity, agent conjunct): the agent path never DISPATCHES through
|
|
378
|
+
// `handler` — the NextAction only ADVERTISES it as the tool name for the model to call; the
|
|
379
|
+
// auto conjunct also overclaimed (an auto step declaring BOTH uses_service and handler
|
|
380
|
+
// dispatches through the adapter arm first — the handler arm is shadowed, tracked #511).
|
|
381
|
+
mechanism: "the engine's execution loop dispatches work through it on auto steps that do not also " +
|
|
382
|
+
"declare 'uses_service' and on finalizer steps, on an agent step the NextAction only " +
|
|
383
|
+
"names it as the tool for the agent to call, and a guard's execution evaluates only " +
|
|
384
|
+
"'abort_unless', so here it would run nothing.",
|
|
385
|
+
site: W_HANDLER_AUTO_DISPATCH,
|
|
386
|
+
// single string, NOT per-kind: handler's only GENERIC-prohibited mint is ×guard (auto/agent/
|
|
387
|
+
// finalizer are all `consumed`), so one remedy suffices — no per-kind fork is needed here.
|
|
388
|
+
remedy: "Move it to an auto step without 'uses_service' or to a finalizer step, or remove it.",
|
|
389
|
+
},
|
|
390
|
+
input_schema: {
|
|
391
|
+
kinds: ['auto', 'agent'],
|
|
392
|
+
mechanism: "the engine's execution loop validates a step's effective input against it at execution " +
|
|
393
|
+
"time, and a guard's execution evaluates only 'abort_unless', so here it would validate " +
|
|
394
|
+
'nothing.',
|
|
395
|
+
site: W_INPUT_SCHEMA_2B,
|
|
396
|
+
remedy: 'Move it to an auto or agent step whose input it should check, or remove it.',
|
|
397
|
+
},
|
|
398
|
+
output_schema: {
|
|
399
|
+
kinds: ['agent'],
|
|
400
|
+
mechanism: "the engine's execution loop validates an agent step's submitted output against it, and " +
|
|
401
|
+
'only agent steps submit output that way, so here it would validate nothing.',
|
|
402
|
+
site: W_OUTPUT_SCHEMA_READ,
|
|
403
|
+
remedy: 'Move it to an agent step whose output it should check, or remove it.',
|
|
404
|
+
},
|
|
405
|
+
trace_schema: {
|
|
406
|
+
kinds: ['agent'],
|
|
407
|
+
// #417 wording defect (minor): "appended trace" presupposed a trace already exists to
|
|
408
|
+
// append to — the schema validates the step's whole canonical trace, appended or not.
|
|
409
|
+
mechanism: "the engine's execution loop validates an agent step's canonical trace against it, and " +
|
|
410
|
+
'only agent steps carry a validated trace, so here it would validate nothing.',
|
|
411
|
+
site: W_TRACE_SCHEMA_READ,
|
|
412
|
+
remedy: 'Move it to an agent step whose trace it should check, or remove it.',
|
|
413
|
+
},
|
|
414
|
+
trace_validation_mode: {
|
|
415
|
+
kinds: ['agent'],
|
|
416
|
+
mechanism: "the engine's execution loop reads it to choose warn-or-enforce for 'trace_schema' " +
|
|
417
|
+
'validation, which only agent steps carry, so here it would choose nothing.',
|
|
418
|
+
site: W_TRACE_MODE_READ,
|
|
419
|
+
remedy: 'Move it to an agent step whose trace validation it should set, or remove it.',
|
|
420
|
+
},
|
|
421
|
+
trust: {
|
|
422
|
+
kinds: ['auto', 'agent'],
|
|
423
|
+
// #417 wording defect (falsity): the human gate does NOT open "before the step runs" — it
|
|
424
|
+
// opens on the step's PRODUCED output, after the work (and any side effects) already ran.
|
|
425
|
+
mechanism: "the engine's execution loop reads it to mint a human gate on the step's produced output " +
|
|
426
|
+
'before it settles, and a guard is never gated that way, so here it would gate nothing.',
|
|
427
|
+
site: W_GATE_MINT_TRUST,
|
|
428
|
+
// #417 wording defect (overclaim): "the auto or agent step that needs the gate" implied
|
|
429
|
+
// every trust value opens one — only the two human-gate literals do; any other declared
|
|
430
|
+
// value is refused outright at load or dispatch, never silently left un-gated (see the
|
|
431
|
+
// registry's own trust×auto/trust×agent cells for the refusal witness).
|
|
432
|
+
//
|
|
433
|
+
// #508 correction (item 6): D2 §8's fix here was never actually shipped — only the comment
|
|
434
|
+
// above changed, the string did not — and "move it to the auto or agent step" is advice
|
|
435
|
+
// that DOES NOT WORK for the dominant measured wrong value, the service-trust literal
|
|
436
|
+
// (`engine_delivered`): auto/agent refuse it too (L1, yaml-loader.ts), so relocating it
|
|
437
|
+
// fixes nothing. Lead with what IS accepted, so a reader with that value learns immediately
|
|
438
|
+
// that moving it will not help.
|
|
439
|
+
remedy: "'trust' accepts 'auto', 'human_confirmed', or 'human_reviewed' — only the latter two " +
|
|
440
|
+
'open a gate, and only on an auto or agent step. If you meant to gate an auto/agent ' +
|
|
441
|
+
'step, move it there; if the value is something else (a typo, or a service-level ' +
|
|
442
|
+
"'trust:' declared on the wrong step), remove it instead — an auto/agent step refuses " +
|
|
443
|
+
'anything outside that set too.',
|
|
444
|
+
},
|
|
445
|
+
timeout_seconds: {
|
|
446
|
+
kinds: ['auto', 'finalizer'],
|
|
447
|
+
mechanism: "the engine's execution loop enforces it as the time-bound on auto dispatch and on a " +
|
|
448
|
+
"finalizer's drain, and a guard's evaluation is never time-bounded, so here it would " +
|
|
449
|
+
'bound nothing.',
|
|
450
|
+
site: W_TIMEOUT_ENFORCE,
|
|
451
|
+
remedy: 'Move it to an auto or finalizer step it should bound, or remove it.',
|
|
452
|
+
},
|
|
453
|
+
retry: {
|
|
454
|
+
kinds: ['auto'],
|
|
455
|
+
// #417 wording defect (overclaim, board #26): "only auto attempts are retried that way"
|
|
456
|
+
// implied auto is the retry mechanism's OWN exclusivity boundary — but an embedder-supplied
|
|
457
|
+
// dispatcher on another kind could retry through the identical loop; the true boundary is
|
|
458
|
+
// structural: a finalizer never REACHES the dispatch loop at all (it runs on the seal-time
|
|
459
|
+
// drain, which never reads this key), so re-grounded on that mechanism instead.
|
|
460
|
+
mechanism: "the engine's execution loop reads it to re-attempt failed dispatch, and a finalizer " +
|
|
461
|
+
'never reaches that dispatch loop — it runs on the seal-time drain, which never reads ' +
|
|
462
|
+
'this key — so here it would retry nothing.',
|
|
463
|
+
site: W_RETRY_READ,
|
|
464
|
+
remedy: 'Move it to an auto step whose attempts it should govern, or remove it.',
|
|
465
|
+
},
|
|
466
|
+
validation_exhaustion: {
|
|
467
|
+
kinds: ['agent'],
|
|
468
|
+
// #417 wording defect (overclaim): "schema rejections" without qualification undercounted
|
|
469
|
+
// the counted class — both input- and output-schema rejections count against the threshold.
|
|
470
|
+
mechanism: "the engine's execution loop counts an agent step's input- and output-schema rejections " +
|
|
471
|
+
'against its threshold, and only agent submissions are counted that way, so here it ' +
|
|
472
|
+
'would count nothing.',
|
|
473
|
+
site: W_VALIDATION_EXHAUSTION_READ,
|
|
474
|
+
remedy: 'Move it to an agent step whose rejections it should bound, or remove it.',
|
|
475
|
+
},
|
|
476
|
+
tools: {
|
|
477
|
+
kinds: ['agent'],
|
|
478
|
+
mechanism: "in realm's own drive it is the tool list offered to the model on an agent step, and " +
|
|
479
|
+
'only agent steps make model requests, so here it would offer nothing.',
|
|
480
|
+
site: W_TOOLS_PATH,
|
|
481
|
+
remedy: 'Move it to an agent step that should call the tools, or remove it.',
|
|
482
|
+
},
|
|
483
|
+
structured_output: {
|
|
484
|
+
kinds: ['agent'],
|
|
485
|
+
// #417 wording defect (board #32, verb weakened per D8-6): the OLD text presented the
|
|
486
|
+
// engine's EVIDENCE RECORDING as the key's consumption home and let 'constrain' pivot on
|
|
487
|
+
// that recording as if it did the constraining. The engine never enforces the strict shape
|
|
488
|
+
// on the wire — it only records the mode it asked for. 'asks the model for schema-
|
|
489
|
+
// constrained output' names the real mechanism; recording stays a separate, accurate clause.
|
|
490
|
+
mechanism: "in realm's own drive it asks the model for schema-constrained output, and the engine's " +
|
|
491
|
+
'execution loop records that strict-output mode on the attempt evidence — only agent ' +
|
|
492
|
+
'steps make model requests, so here it would constrain nothing.',
|
|
493
|
+
site: W_STRUCTURED_OUTPUT_READ,
|
|
494
|
+
remedy: 'Move it to an agent step whose output it should constrain, or remove it.',
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
/** #517: the TRUE prohibited set per kind — every key whose cell on `mode` is `prohibited`
|
|
498
|
+
* WITHOUT an `except` arm (the except cell, today exactly trust×finalizer, keeps its
|
|
499
|
+
* value-conditional hand-written check and is deliberately absent). The loader's exported
|
|
500
|
+
* `GUARD_PROHIBITED_STEP_KEYS` / `FINALIZER_PROHIBITED_STEP_KEYS` are computed from this — one
|
|
501
|
+
* source, no membership drift possible. */
|
|
502
|
+
export function prohibitedKeysFor(mode) {
|
|
503
|
+
return Object.keys(STEP_KEY_REGISTRY).filter((key) => {
|
|
504
|
+
const cell = STEP_KEY_REGISTRY[key][mode];
|
|
505
|
+
return cell.c === 'prohibited' && cell.except === undefined;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
/** #517: the kinds a key is actually CONSUMED on — the derived valid-kind set behind an
|
|
509
|
+
* 'only_valid' front clause (and truth cell 1's comparator for consumed_home.kinds). */
|
|
510
|
+
export function consumedKindsFor(key) {
|
|
511
|
+
const modes = ['auto', 'agent', 'guard', 'finalizer'];
|
|
512
|
+
return modes.filter((mode) => STEP_KEY_REGISTRY[key][mode].c === 'consumed');
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Real program defects on a key×kind surface that cannot be expressed as a cell arm — the key
|
|
516
|
+
* itself IS consumed (or the arm is otherwise fully accounted for); the defect lives in an
|
|
517
|
+
* adjacent mechanism. Recorded here so the #417 program's fate-line contract covers them from
|
|
518
|
+
* the registry itself, not just from the PR body. Via-hygiene-checked exactly like a tracked
|
|
519
|
+
* citation inside a cell.
|
|
520
|
+
*/
|
|
521
|
+
export const TRACKED_RESIDUALS = [
|
|
522
|
+
{
|
|
523
|
+
issue: '#515',
|
|
524
|
+
desc: 'handler×finalizer: capability preflight excludes finalizer handlers entirely — an ' +
|
|
525
|
+
'unregistered finalizer handler is caught only at drain time, as a pending-forever ' +
|
|
526
|
+
'liveness gap. The key itself is consumed and required; the gap is in when the ' +
|
|
527
|
+
'requirement gets checked.',
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
issue: '#519',
|
|
531
|
+
desc: 'the whole-registry loader-bypass class: a WorkflowDefinition that reaches the engine ' +
|
|
532
|
+
'without going through this loader (a store-injected definition) satisfies none of these ' +
|
|
533
|
+
'prohibitions at all — a registry-driven runtime mirror at the engine boundary is its ' +
|
|
534
|
+
'own, separate design arc.',
|
|
535
|
+
},
|
|
536
|
+
];
|
|
537
|
+
export const STEP_KEY_REGISTRY = {
|
|
538
|
+
description: {
|
|
539
|
+
auto: {
|
|
540
|
+
c: 'consumed',
|
|
541
|
+
where: [
|
|
542
|
+
{ file: EL, pattern: "human_readable: `Execute step '${stepName}': ${step.description}`," },
|
|
543
|
+
],
|
|
544
|
+
},
|
|
545
|
+
agent: {
|
|
546
|
+
c: 'consumed',
|
|
547
|
+
where: [{ file: RA, pattern: 'const prompt = nextAction?.prompt ?? stepDef.description;' }],
|
|
548
|
+
},
|
|
549
|
+
guard: {
|
|
550
|
+
c: 'consumed',
|
|
551
|
+
where: [W_DESCRIPTION_GEN],
|
|
552
|
+
when: {
|
|
553
|
+
desc: 'disclosure-only: required on every kind, surfaced in the protocol briefing, but no engine-execution path ever reads it for a guard',
|
|
554
|
+
witness: W_DESCRIPTION_GEN,
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
finalizer: {
|
|
558
|
+
c: 'consumed',
|
|
559
|
+
where: [W_DESCRIPTION_GEN],
|
|
560
|
+
when: {
|
|
561
|
+
desc: 'disclosure-only, same as ×guard',
|
|
562
|
+
witness: W_DESCRIPTION_GEN,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
execution: {
|
|
567
|
+
auto: {
|
|
568
|
+
c: 'consumed',
|
|
569
|
+
where: [W_ADAPTER_DISPATCH],
|
|
570
|
+
},
|
|
571
|
+
agent: {
|
|
572
|
+
c: 'consumed',
|
|
573
|
+
where: [{ file: EL, pattern: "definition.steps[name]?.execution === 'agent' ||" }],
|
|
574
|
+
},
|
|
575
|
+
guard: {
|
|
576
|
+
c: 'consumed',
|
|
577
|
+
where: [{ file: ELIG, pattern: "if (step.execution !== 'guard') continue;" }],
|
|
578
|
+
},
|
|
579
|
+
finalizer: {
|
|
580
|
+
c: 'consumed',
|
|
581
|
+
where: [{ file: SETTLE, pattern: "if (step.execution !== 'finalizer') continue;" }],
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
depends_on: {
|
|
585
|
+
auto: { c: 'consumed', where: [W_DEPENDS_ON] },
|
|
586
|
+
agent: { c: 'consumed', where: [W_DEPENDS_ON] },
|
|
587
|
+
guard: { c: 'consumed', where: [W_DEPENDS_ON] },
|
|
588
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
589
|
+
},
|
|
590
|
+
trigger_rule: {
|
|
591
|
+
auto: { c: 'consumed', where: [W_TRIGGER_RULE] },
|
|
592
|
+
agent: { c: 'consumed', where: [W_TRIGGER_RULE] },
|
|
593
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
594
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
595
|
+
},
|
|
596
|
+
when: {
|
|
597
|
+
auto: { c: 'consumed', where: [W_WHEN_ELIG] },
|
|
598
|
+
agent: { c: 'consumed', where: [W_WHEN_ELIG] },
|
|
599
|
+
guard: {
|
|
600
|
+
c: 'consumed',
|
|
601
|
+
where: [W_WHEN_ELIG],
|
|
602
|
+
when: {
|
|
603
|
+
desc: "guard selection evaluates when before executeGuardStep ever runs — 'guards evaluate only abort_unless' is true of execution, false of eligibility (census lane-1 contradiction 2)",
|
|
604
|
+
witness: {
|
|
605
|
+
file: ELIG,
|
|
606
|
+
pattern: 'const evidenceByStep = buildEvidenceByStep(run); if (!evaluateWhen(step.when, evidenceByStep, run.params)) continue;',
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
611
|
+
},
|
|
612
|
+
abort_unless: {
|
|
613
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ABORT_UNLESS },
|
|
614
|
+
agent: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ABORT_UNLESS },
|
|
615
|
+
guard: {
|
|
616
|
+
c: 'consumed',
|
|
617
|
+
where: [
|
|
618
|
+
{
|
|
619
|
+
file: EL,
|
|
620
|
+
pattern: 'const conditions = Array.isArray(stepDef.abort_unless) ? stepDef.abort_unless : [stepDef.abort_unless!];',
|
|
621
|
+
},
|
|
622
|
+
],
|
|
623
|
+
},
|
|
624
|
+
finalizer: {
|
|
625
|
+
c: 'prohibited',
|
|
626
|
+
by: [MINT],
|
|
627
|
+
line: 'key',
|
|
628
|
+
message_data: MSG_ABORT_UNLESS,
|
|
629
|
+
},
|
|
630
|
+
},
|
|
631
|
+
abort_message: {
|
|
632
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ABORT_MESSAGE },
|
|
633
|
+
agent: {
|
|
634
|
+
c: 'prohibited',
|
|
635
|
+
by: [MINT],
|
|
636
|
+
line: 'key',
|
|
637
|
+
message_data: MSG_ABORT_MESSAGE,
|
|
638
|
+
},
|
|
639
|
+
guard: {
|
|
640
|
+
c: 'consumed',
|
|
641
|
+
where: [
|
|
642
|
+
{
|
|
643
|
+
file: EL,
|
|
644
|
+
pattern: '...(stepDef.abort_message !== undefined ? { abort_message: stepDef.abort_message } : {}),',
|
|
645
|
+
count: 2, // both guard-abort output branches carry the disclosure (census lane-1 correction)
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
file: EL,
|
|
649
|
+
pattern: "error: stepDef.abort_message ?? `Guard step '${stepName}' aborted the run.`,",
|
|
650
|
+
},
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
finalizer: {
|
|
654
|
+
c: 'prohibited',
|
|
655
|
+
by: [MINT],
|
|
656
|
+
line: 'key',
|
|
657
|
+
message_data: MSG_ABORT_MESSAGE,
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
on_outcome: {
|
|
661
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ON_OUTCOME },
|
|
662
|
+
agent: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ON_OUTCOME },
|
|
663
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_ON_OUTCOME },
|
|
664
|
+
finalizer: {
|
|
665
|
+
c: 'consumed',
|
|
666
|
+
where: [{ file: SETTLE, pattern: 'const raw = stepDef.on_outcome;' }],
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
idempotent: {
|
|
670
|
+
auto: {
|
|
671
|
+
c: 'consumed',
|
|
672
|
+
where: [
|
|
673
|
+
{ file: EL, pattern: 'stepDef!.idempotent === true &&' },
|
|
674
|
+
{ file: RECLAIM, pattern: 'if (stepDef?.idempotent !== true) return false;' },
|
|
675
|
+
],
|
|
676
|
+
inert_subpop: [
|
|
677
|
+
{
|
|
678
|
+
desc: 'on the auto step of a finalizer-bearing workflow: the reclaim half is inert (a claim with no deadline is never selected by reclaim --all); the retry.on_timeout gate half stays live',
|
|
679
|
+
via: { kind: 'advisory', code: 'IDEMPOTENT_INERT_IN_FINALIZER' },
|
|
680
|
+
},
|
|
681
|
+
],
|
|
682
|
+
},
|
|
683
|
+
agent: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_IDEMPOTENT },
|
|
684
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_IDEMPOTENT },
|
|
685
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_IDEMPOTENT },
|
|
686
|
+
},
|
|
687
|
+
uses_service: {
|
|
688
|
+
auto: {
|
|
689
|
+
c: 'consumed',
|
|
690
|
+
where: [W_ADAPTER_DISPATCH],
|
|
691
|
+
},
|
|
692
|
+
agent: { c: 'inert', via: { kind: 'tracked', issue: '#511' } },
|
|
693
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
694
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
695
|
+
},
|
|
696
|
+
service_method: {
|
|
697
|
+
auto: {
|
|
698
|
+
c: 'consumed',
|
|
699
|
+
where: [W_SERVICE_METHOD_READ],
|
|
700
|
+
when: {
|
|
701
|
+
desc: 'dispatch-arm-keyed: read only on the uses_service adapter dispatch path',
|
|
702
|
+
witness: W_ADAPTER_DISPATCH,
|
|
703
|
+
},
|
|
704
|
+
inert_subpop: [
|
|
705
|
+
{
|
|
706
|
+
desc: 'declared without uses_service: the adapter dispatch path never runs, so this is never read',
|
|
707
|
+
via: {
|
|
708
|
+
kind: 'waived',
|
|
709
|
+
reason: 'a dispatch-arm companion field, meaningful only beside uses_service — the dead-config policing call for the whole dispatch family is #511 territory and undecided',
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
],
|
|
713
|
+
},
|
|
714
|
+
agent: { c: 'inert', via: { kind: 'tracked', issue: '#511' } },
|
|
715
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
716
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
717
|
+
},
|
|
718
|
+
operation: {
|
|
719
|
+
auto: {
|
|
720
|
+
c: 'consumed',
|
|
721
|
+
where: [W_OPERATION_READ],
|
|
722
|
+
when: {
|
|
723
|
+
desc: 'dispatch-arm-keyed: read only on the uses_service adapter dispatch path',
|
|
724
|
+
witness: W_ADAPTER_DISPATCH,
|
|
725
|
+
},
|
|
726
|
+
inert_subpop: [
|
|
727
|
+
{
|
|
728
|
+
desc: 'declared without uses_service: never read',
|
|
729
|
+
via: {
|
|
730
|
+
kind: 'waived',
|
|
731
|
+
reason: 'dispatch-arm companion, same family as service_method — #511 territory and undecided',
|
|
732
|
+
},
|
|
733
|
+
},
|
|
734
|
+
],
|
|
735
|
+
},
|
|
736
|
+
agent: { c: 'inert', via: { kind: 'tracked', issue: '#511' } },
|
|
737
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
738
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
739
|
+
},
|
|
740
|
+
input_map: {
|
|
741
|
+
auto: {
|
|
742
|
+
c: 'consumed',
|
|
743
|
+
where: [W_INPUT_MAP_RESOLVE],
|
|
744
|
+
when: {
|
|
745
|
+
desc: 'dispatch-arm-keyed: resolved on the adapter path, and delivered to handlers via the resolved params',
|
|
746
|
+
witness: W_ADAPTER_DISPATCH,
|
|
747
|
+
},
|
|
748
|
+
inert_subpop: [
|
|
749
|
+
{
|
|
750
|
+
desc: 'declared with neither uses_service nor handler: a bare auto step dispatches nothing, so nothing consumes it',
|
|
751
|
+
via: {
|
|
752
|
+
kind: 'waived',
|
|
753
|
+
reason: 'dispatch-arm companion, same family call as service_method/operation',
|
|
754
|
+
},
|
|
755
|
+
},
|
|
756
|
+
],
|
|
757
|
+
},
|
|
758
|
+
agent: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
759
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
760
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
761
|
+
},
|
|
762
|
+
handler: {
|
|
763
|
+
auto: {
|
|
764
|
+
c: 'consumed',
|
|
765
|
+
where: [W_HANDLER_AUTO_DISPATCH],
|
|
766
|
+
inert_subpop: [
|
|
767
|
+
{
|
|
768
|
+
desc: 'shadowed when uses_service is also declared: dispatch precedence tries the adapter arm first, and no both-declared check exists to flag it',
|
|
769
|
+
via: { kind: 'tracked', issue: '#511' },
|
|
770
|
+
},
|
|
771
|
+
],
|
|
772
|
+
},
|
|
773
|
+
agent: {
|
|
774
|
+
c: 'consumed',
|
|
775
|
+
where: [
|
|
776
|
+
{
|
|
777
|
+
file: EL,
|
|
778
|
+
pattern: 'step.handler !== undefined ? { tool: step.handler, params: {}, call_with: {} }',
|
|
779
|
+
},
|
|
780
|
+
],
|
|
781
|
+
when: {
|
|
782
|
+
desc: 'handler-bearing agent step: the NextAction names the handler as the tool to call, and this arm OUTRANKS the plain execute_step instruction — semantics are under #516, but the read itself is real (D4-2)',
|
|
783
|
+
witness: {
|
|
784
|
+
file: EL,
|
|
785
|
+
pattern: 'step.handler !== undefined ? { tool: step.handler, params: {}, call_with: {} }',
|
|
786
|
+
},
|
|
787
|
+
},
|
|
788
|
+
},
|
|
789
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
790
|
+
finalizer: {
|
|
791
|
+
c: 'consumed',
|
|
792
|
+
where: [{ file: EL, pattern: 'const handlerName = stepDef?.handler;' }],
|
|
793
|
+
when: {
|
|
794
|
+
desc: 'REQUIRED (handler-only in v1) — drained via callHandler, never through executeStep',
|
|
795
|
+
witness: { file: EL, pattern: 'const handlerName = stepDef?.handler;' },
|
|
796
|
+
},
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
config: {
|
|
800
|
+
auto: {
|
|
801
|
+
c: 'consumed',
|
|
802
|
+
where: [{ file: EL, pattern: '...(stepDef.config ?? {}),' }],
|
|
803
|
+
inert_subpop: [
|
|
804
|
+
{
|
|
805
|
+
desc: 'declared with neither uses_service nor handler: never delivered to anything',
|
|
806
|
+
via: {
|
|
807
|
+
kind: 'waived',
|
|
808
|
+
reason: 'dispatch-arm companion, same family call as service_method/operation/input_map',
|
|
809
|
+
},
|
|
810
|
+
},
|
|
811
|
+
],
|
|
812
|
+
},
|
|
813
|
+
agent: { c: 'inert', via: { kind: 'tracked', issue: '#511' } },
|
|
814
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#511' } },
|
|
815
|
+
finalizer: {
|
|
816
|
+
c: 'consumed',
|
|
817
|
+
where: [{ file: EL, pattern: 'config: stepDef.config ?? {},' }],
|
|
818
|
+
when: {
|
|
819
|
+
desc: 'delivered to the finalizer handler via callHandler context — genuinely consumed on this kind, deliberately NOT part of the #511 dispatch-family tracking (census lane 2)',
|
|
820
|
+
witness: { file: EL, pattern: 'config: stepDef.config ?? {},' },
|
|
821
|
+
},
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
input_schema: {
|
|
825
|
+
auto: {
|
|
826
|
+
c: 'consumed',
|
|
827
|
+
where: [W_INPUT_SCHEMA_2B],
|
|
828
|
+
when: {
|
|
829
|
+
desc: 'Step 2b validates the effective input against it with no kind conjunct at all; also the gate-choice fallback source on gate-trusted steps',
|
|
830
|
+
witness: W_INPUT_SCHEMA_2B,
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
agent: { c: 'consumed', where: [W_INPUT_SCHEMA_2B] },
|
|
834
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
835
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#512' } },
|
|
836
|
+
},
|
|
837
|
+
output_schema: {
|
|
838
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
839
|
+
agent: {
|
|
840
|
+
c: 'consumed',
|
|
841
|
+
where: [W_OUTPUT_SCHEMA_READ],
|
|
842
|
+
},
|
|
843
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
844
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
845
|
+
},
|
|
846
|
+
trace_schema: {
|
|
847
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
848
|
+
agent: {
|
|
849
|
+
c: 'consumed',
|
|
850
|
+
where: [W_TRACE_SCHEMA_READ],
|
|
851
|
+
},
|
|
852
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
853
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
854
|
+
},
|
|
855
|
+
trace_validation_mode: {
|
|
856
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
857
|
+
agent: {
|
|
858
|
+
c: 'consumed',
|
|
859
|
+
where: [W_TRACE_MODE_READ],
|
|
860
|
+
inert_subpop: [
|
|
861
|
+
{
|
|
862
|
+
desc: 'declared without trace_schema: the only read sits inside the trace_schema branch and is never reached — silently ignored, with no dead-config advisory today despite two in-file precedents for that shape',
|
|
863
|
+
via: { kind: 'tracked', issue: '#514' },
|
|
864
|
+
},
|
|
865
|
+
],
|
|
866
|
+
},
|
|
867
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
868
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
869
|
+
},
|
|
870
|
+
preconditions: {
|
|
871
|
+
auto: { c: 'consumed', where: [W_PRECONDITIONS] },
|
|
872
|
+
agent: { c: 'consumed', where: [W_PRECONDITIONS] },
|
|
873
|
+
guard: {
|
|
874
|
+
c: 'prohibited',
|
|
875
|
+
by: [MINT],
|
|
876
|
+
line: 'key',
|
|
877
|
+
message_data: MSG_PRECONDITIONS_GUARD,
|
|
878
|
+
},
|
|
879
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#509' } },
|
|
880
|
+
},
|
|
881
|
+
trust: {
|
|
882
|
+
auto: {
|
|
883
|
+
c: 'consumed',
|
|
884
|
+
where: [W_GATE_MINT_TRUST, W_TRUST_VALUE_REFUSAL],
|
|
885
|
+
},
|
|
886
|
+
agent: {
|
|
887
|
+
c: 'consumed',
|
|
888
|
+
where: [W_GATE_MINT_TRUST, W_TRUST_VALUE_REFUSAL],
|
|
889
|
+
},
|
|
890
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
891
|
+
finalizer: {
|
|
892
|
+
c: 'prohibited',
|
|
893
|
+
by: [BY_TRUST_FINALIZER],
|
|
894
|
+
line: 'step',
|
|
895
|
+
except: {
|
|
896
|
+
desc: "the literal 'auto' is accepted and unread on a finalizer — redundant, harmless (D4-1)",
|
|
897
|
+
via: {
|
|
898
|
+
kind: 'waived',
|
|
899
|
+
reason: "'auto' is the only lawful trust literal on a finalizer, so refusing it would refuse a truthful no-op declaration",
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
},
|
|
903
|
+
},
|
|
904
|
+
timeout_seconds: {
|
|
905
|
+
auto: {
|
|
906
|
+
c: 'consumed',
|
|
907
|
+
where: [
|
|
908
|
+
W_TIMEOUT_ENFORCE,
|
|
909
|
+
{
|
|
910
|
+
file: CL,
|
|
911
|
+
pattern: 'const perAttemptSec = step.timeout_seconds ?? DEFAULT_EXECUTION_TIMEOUT_SECONDS;',
|
|
912
|
+
},
|
|
913
|
+
],
|
|
914
|
+
when: {
|
|
915
|
+
desc: "shouldEnforceTimeout is the auto-only predicate — the reason #402's prohibition on agent steps is a hard 'not valid', while the same key stays consumed on finalizers (drain + lease, below)",
|
|
916
|
+
witness: { file: CL, pattern: "return step.execution === 'auto';" },
|
|
917
|
+
},
|
|
918
|
+
},
|
|
919
|
+
agent: {
|
|
920
|
+
c: 'prohibited',
|
|
921
|
+
by: [MINT],
|
|
922
|
+
line: 'key',
|
|
923
|
+
message_data: MSG_TIMEOUT_ON_AGENT,
|
|
924
|
+
},
|
|
925
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
926
|
+
finalizer: {
|
|
927
|
+
c: 'consumed',
|
|
928
|
+
where: [
|
|
929
|
+
{
|
|
930
|
+
file: EL,
|
|
931
|
+
pattern: 'const timeoutMs = (step.timeout_seconds ?? DRAIN_CEILING_SECONDS) * 1000;',
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
file: EL,
|
|
935
|
+
pattern: 'const leaseSeconds = stepDef.timeout_seconds ?? DRAIN_CEILING_SECONDS;',
|
|
936
|
+
},
|
|
937
|
+
],
|
|
938
|
+
},
|
|
939
|
+
},
|
|
940
|
+
retry: {
|
|
941
|
+
auto: {
|
|
942
|
+
c: 'consumed',
|
|
943
|
+
where: [W_RETRY_READ],
|
|
944
|
+
},
|
|
945
|
+
agent: { c: 'inert', via: { kind: 'advisory', code: 'RETRY_INERT_NON_AUTO' } },
|
|
946
|
+
guard: { c: 'inert', via: { kind: 'advisory', code: 'RETRY_INERT_NON_AUTO' } },
|
|
947
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
948
|
+
},
|
|
949
|
+
validation_exhaustion: {
|
|
950
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
951
|
+
agent: {
|
|
952
|
+
c: 'consumed',
|
|
953
|
+
where: [W_VALIDATION_EXHAUSTION_READ],
|
|
954
|
+
},
|
|
955
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
956
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
957
|
+
},
|
|
958
|
+
instructions: {
|
|
959
|
+
auto: {
|
|
960
|
+
c: 'consumed',
|
|
961
|
+
where: [
|
|
962
|
+
{
|
|
963
|
+
file: EL,
|
|
964
|
+
pattern: 'stepDef!.instructions !== undefined ? renderTemplate(stepDef!.instructions, {',
|
|
965
|
+
},
|
|
966
|
+
],
|
|
967
|
+
when: {
|
|
968
|
+
desc: 'gate-path: rendered into the gate envelope for gated autos; the same value is also protocol-surfaced for every step regardless of kind',
|
|
969
|
+
witness: W_GATE_MINT_TRUST,
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
agent: {
|
|
973
|
+
c: 'consumed',
|
|
974
|
+
where: [{ file: GEN, pattern: 'protocolStep.instructions = step.instructions;' }],
|
|
975
|
+
when: {
|
|
976
|
+
desc: "disclosure-only in realm's own drive — run-agent builds the model task from prompt ?? description and never feeds instructions to the model at all (a cross-drive asymmetry vs. an external MCP agent, which does see it; census lane-1 contradiction 4)",
|
|
977
|
+
witness: { file: GEN, pattern: 'protocolStep.instructions = step.instructions;' },
|
|
978
|
+
},
|
|
979
|
+
},
|
|
980
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
981
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
982
|
+
},
|
|
983
|
+
prompt: {
|
|
984
|
+
auto: {
|
|
985
|
+
c: 'consumed',
|
|
986
|
+
where: [W_PROMPT_NEXTACTION],
|
|
987
|
+
when: {
|
|
988
|
+
desc: 'handler-bearing or gated autos only — a gateless, handler-less auto never reads it',
|
|
989
|
+
witness: W_PROMPT_NEXTACTION,
|
|
990
|
+
},
|
|
991
|
+
inert_subpop: [
|
|
992
|
+
{
|
|
993
|
+
desc: 'gateless, handler-less auto: never read anywhere',
|
|
994
|
+
via: {
|
|
995
|
+
kind: 'waived',
|
|
996
|
+
reason: 'this sub-population is exactly the complement of the two documented read paths — surface-conditional by design',
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
],
|
|
1000
|
+
},
|
|
1001
|
+
agent: { c: 'consumed', where: [W_PROMPT_NEXTACTION] },
|
|
1002
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
1003
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
1004
|
+
},
|
|
1005
|
+
display: {
|
|
1006
|
+
auto: {
|
|
1007
|
+
c: 'consumed',
|
|
1008
|
+
where: [
|
|
1009
|
+
{
|
|
1010
|
+
file: RA,
|
|
1011
|
+
pattern: '(gateStepDef?.display !== undefined ? renderDisplay(gateStepDef.display, gate.preview)',
|
|
1012
|
+
},
|
|
1013
|
+
],
|
|
1014
|
+
when: {
|
|
1015
|
+
desc: "gate-trusted only — rendered on the gate surface; the run-completion result render is agent-only (see this PR's JSDoc truth fix on StepDefinition.display)",
|
|
1016
|
+
witness: {
|
|
1017
|
+
file: RA,
|
|
1018
|
+
pattern: '(gateStepDef?.display !== undefined ? renderDisplay(gateStepDef.display, gate.preview)',
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
inert_subpop: [
|
|
1022
|
+
{
|
|
1023
|
+
desc: 'gateless auto: never read by anything',
|
|
1024
|
+
via: {
|
|
1025
|
+
kind: 'waived',
|
|
1026
|
+
reason: 'documented-inert after the JSDoc truth fix — the type doc no longer promises run-completion rendering for a non-agent step (D4-3)',
|
|
1027
|
+
},
|
|
1028
|
+
},
|
|
1029
|
+
],
|
|
1030
|
+
},
|
|
1031
|
+
agent: {
|
|
1032
|
+
c: 'consumed',
|
|
1033
|
+
where: [
|
|
1034
|
+
{
|
|
1035
|
+
file: RA,
|
|
1036
|
+
pattern: 'stepDef?.display !== undefined ? renderDisplay(stepDef.display, lastAgentEvidence.output_summary)',
|
|
1037
|
+
},
|
|
1038
|
+
],
|
|
1039
|
+
},
|
|
1040
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
1041
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#513' } },
|
|
1042
|
+
},
|
|
1043
|
+
use_template: {
|
|
1044
|
+
auto: {
|
|
1045
|
+
c: 'na',
|
|
1046
|
+
reason: 'resolved away before any step validation runs: the template resolver REPLACES the entry entirely, so it is never present in a WorkflowDefinition returned to any caller (census lane 1)',
|
|
1047
|
+
},
|
|
1048
|
+
agent: { c: 'na', reason: 'resolved away pre-validation (see ×auto)' },
|
|
1049
|
+
guard: { c: 'na', reason: 'resolved away pre-validation (see ×auto)' },
|
|
1050
|
+
finalizer: { c: 'na', reason: 'resolved away pre-validation (see ×auto)' },
|
|
1051
|
+
},
|
|
1052
|
+
gate: {
|
|
1053
|
+
auto: {
|
|
1054
|
+
c: 'consumed',
|
|
1055
|
+
where: [W_GATE_CHOICES],
|
|
1056
|
+
when: {
|
|
1057
|
+
desc: 'gate-trusted only: the mint reads the gate config exactly once — every later enactment read sees only the already-FROZEN PendingGate',
|
|
1058
|
+
witness: W_GATE_MINT_TRUST,
|
|
1059
|
+
},
|
|
1060
|
+
inert_subpop: [
|
|
1061
|
+
{
|
|
1062
|
+
desc: 'without gate trust: fully validated at load time (#291/#433) and never minted',
|
|
1063
|
+
// issue #524: was `waived` quoting the loader's own header comment — not a witness,
|
|
1064
|
+
// and nothing pinned the text (mutating it left the registry suite 205/205 green). The
|
|
1065
|
+
// loader now emits ONE advisory naming the true cause on this exact population.
|
|
1066
|
+
via: { kind: 'advisory', code: 'DEAD_GATE_CONFIG' },
|
|
1067
|
+
},
|
|
1068
|
+
],
|
|
1069
|
+
},
|
|
1070
|
+
agent: {
|
|
1071
|
+
c: 'consumed',
|
|
1072
|
+
where: [W_GATE_CHOICES],
|
|
1073
|
+
when: {
|
|
1074
|
+
desc: 'gate-trusted only, the same mint site',
|
|
1075
|
+
witness: W_GATE_MINT_TRUST,
|
|
1076
|
+
},
|
|
1077
|
+
inert_subpop: [
|
|
1078
|
+
{
|
|
1079
|
+
desc: 'without gate trust: validated, never minted',
|
|
1080
|
+
via: { kind: 'advisory', code: 'DEAD_GATE_CONFIG' }, // issue #524, see ×auto
|
|
1081
|
+
},
|
|
1082
|
+
],
|
|
1083
|
+
},
|
|
1084
|
+
// issue #524: was `tracked #512` (a gate×guard/finalizer PROHIBITION is #512's own proposal,
|
|
1085
|
+
// still open) — until #512 ships, the loader's #524 block advisory covers this population
|
|
1086
|
+
// too (guard/finalizer never reach the gate mint at all, Step 5b `execution-loop.ts`), so it
|
|
1087
|
+
// is `advisory`, not merely `tracked`, today. This pair is #512's red-first once it lands.
|
|
1088
|
+
guard: { c: 'inert', via: { kind: 'advisory', code: 'DEAD_GATE_CONFIG' } },
|
|
1089
|
+
finalizer: { c: 'inert', via: { kind: 'advisory', code: 'DEAD_GATE_CONFIG' } },
|
|
1090
|
+
},
|
|
1091
|
+
agent_profile: {
|
|
1092
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_AGENT_PROFILE },
|
|
1093
|
+
agent: {
|
|
1094
|
+
c: 'consumed',
|
|
1095
|
+
where: [
|
|
1096
|
+
{ file: EL, pattern: 'const profile = stepDef?.agent_profile;' },
|
|
1097
|
+
{
|
|
1098
|
+
file: RA,
|
|
1099
|
+
pattern: 'stepDef.agent_profile !== undefined ? definition.resolved_profiles?.[stepDef.agent_profile]?.content : undefined;',
|
|
1100
|
+
},
|
|
1101
|
+
],
|
|
1102
|
+
},
|
|
1103
|
+
guard: {
|
|
1104
|
+
c: 'prohibited',
|
|
1105
|
+
by: [MINT],
|
|
1106
|
+
line: 'key',
|
|
1107
|
+
message_data: MSG_AGENT_PROFILE,
|
|
1108
|
+
},
|
|
1109
|
+
finalizer: {
|
|
1110
|
+
c: 'prohibited',
|
|
1111
|
+
by: [MINT],
|
|
1112
|
+
line: 'key',
|
|
1113
|
+
message_data: MSG_AGENT_PROFILE,
|
|
1114
|
+
},
|
|
1115
|
+
},
|
|
1116
|
+
tools: {
|
|
1117
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
1118
|
+
agent: {
|
|
1119
|
+
c: 'consumed',
|
|
1120
|
+
where: [W_TOOLS_PATH],
|
|
1121
|
+
inert_subpop: [
|
|
1122
|
+
{
|
|
1123
|
+
desc: 'tools: [] is treated as toolless — it loads with zero tools diagnostics, is runtime-toolless, and in turn inerts the tool-budget keys below',
|
|
1124
|
+
via: { kind: 'tracked', issue: '#510' },
|
|
1125
|
+
},
|
|
1126
|
+
],
|
|
1127
|
+
},
|
|
1128
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
1129
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'not_valid' },
|
|
1130
|
+
},
|
|
1131
|
+
max_tool_calls: {
|
|
1132
|
+
auto: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1133
|
+
agent: {
|
|
1134
|
+
c: 'consumed',
|
|
1135
|
+
where: [{ file: RA, pattern: 'maxToolCalls: stepDef.max_tool_calls ?? 20,' }],
|
|
1136
|
+
when: { desc: 'tools-path only', witness: W_TOOLS_PATH },
|
|
1137
|
+
inert_subpop: [
|
|
1138
|
+
{
|
|
1139
|
+
desc: 'tools-less agent step: consumption sits behind the tools-path gate — a bound with nothing to bind',
|
|
1140
|
+
via: { kind: 'tracked', issue: '#510' },
|
|
1141
|
+
},
|
|
1142
|
+
],
|
|
1143
|
+
},
|
|
1144
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1145
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1146
|
+
},
|
|
1147
|
+
max_fan_out: {
|
|
1148
|
+
auto: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1149
|
+
agent: {
|
|
1150
|
+
c: 'consumed',
|
|
1151
|
+
where: [{ file: RA, pattern: 'const maxFanOut = stepDef.max_fan_out;' }],
|
|
1152
|
+
when: { desc: 'tools-path only', witness: W_TOOLS_PATH },
|
|
1153
|
+
inert_subpop: [
|
|
1154
|
+
{
|
|
1155
|
+
desc: 'tools-less agent step: never read',
|
|
1156
|
+
via: { kind: 'tracked', issue: '#510' },
|
|
1157
|
+
},
|
|
1158
|
+
],
|
|
1159
|
+
},
|
|
1160
|
+
guard: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1161
|
+
finalizer: { c: 'inert', via: { kind: 'tracked', issue: '#510' } },
|
|
1162
|
+
},
|
|
1163
|
+
tool_timeout: {
|
|
1164
|
+
auto: {
|
|
1165
|
+
c: 'blocked_transitive',
|
|
1166
|
+
via: 'tools',
|
|
1167
|
+
by: [BY_TOOL_TIMEOUT],
|
|
1168
|
+
message_data: MSG_TOOL_TIMEOUT,
|
|
1169
|
+
},
|
|
1170
|
+
agent: {
|
|
1171
|
+
c: 'consumed',
|
|
1172
|
+
where: [{ file: RA, pattern: 'toolTimeoutMs: (stepDef.tool_timeout ?? 30) * 1000,' }],
|
|
1173
|
+
when: { desc: 'non-empty tools declared', witness: W_TOOLS_PATH },
|
|
1174
|
+
},
|
|
1175
|
+
guard: {
|
|
1176
|
+
c: 'blocked_transitive',
|
|
1177
|
+
via: 'tools',
|
|
1178
|
+
by: [BY_TOOL_TIMEOUT],
|
|
1179
|
+
message_data: MSG_TOOL_TIMEOUT,
|
|
1180
|
+
},
|
|
1181
|
+
finalizer: {
|
|
1182
|
+
c: 'blocked_transitive',
|
|
1183
|
+
via: 'tools',
|
|
1184
|
+
by: [BY_TOOL_TIMEOUT],
|
|
1185
|
+
message_data: MSG_TOOL_TIMEOUT,
|
|
1186
|
+
},
|
|
1187
|
+
},
|
|
1188
|
+
structured_output: {
|
|
1189
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
1190
|
+
agent: {
|
|
1191
|
+
c: 'consumed',
|
|
1192
|
+
where: [W_STRUCTURED_OUTPUT_READ],
|
|
1193
|
+
},
|
|
1194
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
1195
|
+
finalizer: { c: 'prohibited', by: [MINT], line: 'key', front: 'only_valid' },
|
|
1196
|
+
},
|
|
1197
|
+
llm_timeout_seconds: {
|
|
1198
|
+
auto: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_LLM_TIMEOUT },
|
|
1199
|
+
agent: {
|
|
1200
|
+
c: 'consumed',
|
|
1201
|
+
where: [
|
|
1202
|
+
{
|
|
1203
|
+
file: RA,
|
|
1204
|
+
pattern: '(stepDef.llm_timeout_seconds ?? fallbackLlmTimeoutSeconds) * 1000,',
|
|
1205
|
+
},
|
|
1206
|
+
],
|
|
1207
|
+
},
|
|
1208
|
+
guard: { c: 'prohibited', by: [MINT], line: 'key', message_data: MSG_LLM_TIMEOUT },
|
|
1209
|
+
finalizer: {
|
|
1210
|
+
c: 'prohibited',
|
|
1211
|
+
by: [MINT],
|
|
1212
|
+
line: 'key',
|
|
1213
|
+
message_data: MSG_LLM_TIMEOUT,
|
|
1214
|
+
},
|
|
1215
|
+
},
|
|
1216
|
+
};
|
|
1217
|
+
//# sourceMappingURL=step-key-registry.js.map
|