agent-qa 0.2.3 → 0.2.5
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/capability-catalog/capability-catalog.json +51 -327
- package/dist/cli-main.cjs +22287 -29005
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.d.cts +2 -5
- package/dist/cli-main.d.ts +2 -5
- package/dist/cli-main.js +22244 -29447
- package/dist/cli-main.js.map +1 -1
- package/dist/cli.cjs +16 -26
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +17 -25
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +2972 -6663
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +221 -567
- package/dist/index.d.ts +221 -567
- package/dist/index.js +2923 -6837
- package/dist/index.js.map +1 -1
- package/package.json +45 -32
- package/skills/agent-qa-authoring/SKILL.md +5 -11
- package/skills/agent-qa-authoring/references/agent-qa-contracts.json +2 -4
- package/skills/agent-qa-debug-fix/SKILL.md +1 -4
- package/skills/agent-qa-knowledge/SKILL.md +2 -4
- package/skills/agent-qa-knowledge/references/knowledge-reads.md +19 -22
- package/skills/agent-qa-result-triage/SKILL.md +0 -2
- package/skills/agent-qa-result-triage/references/triage-categories.md +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,653 +1,307 @@
|
|
|
1
|
-
import { AgentQaConfig, resolveKnowledgeRoot } from
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { ModelProfile, ResolvedModelAuth, createModel,
|
|
6
|
-
import { KnowledgeHintReader } from
|
|
7
|
-
import { loadCompletedRunHandoff } from
|
|
8
|
-
import { runSafetyScope } from
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* jsonl. A caller that wants to recognise the case (F-03's typed-refusal arm, later) needs
|
|
17
|
-
* something better than a substring match on a sentence; `name` and `configPath` are that. The
|
|
18
|
-
* message itself carries the path because the surfaces this reaches print a message and nothing
|
|
19
|
-
* else.
|
|
20
|
-
*
|
|
21
|
-
* NO MEMBER INTERPOLATES THE CAUGHT ERROR'S OWN TEXT. `yaml` pretty-prints its parse errors with a
|
|
22
|
-
* verbatim excerpt of the person's source, which was measured carrying a planted credential out of
|
|
23
|
-
* three ops.
|
|
24
|
-
*
|
|
25
|
-
* AND THE CAUSE IS SANITIZED TOO, BECAUSE THE RUNTIME READS THE CAUSE CHAIN (395-16 · CR-01).
|
|
26
|
-
* An earlier revision of this class attached the raw `YAMLParseError` as `cause` on the reasoning
|
|
27
|
-
* that no composed member reads it. That reasoning was false of the runtime, and shipped as a
|
|
28
|
-
* defect: a thrown value is read by far more than the code that composed it. Node's DEFAULT
|
|
29
|
-
* UNCAUGHT PRINTER renders an error with `util.inspect`, which walks `cause` and prints it under a
|
|
30
|
-
* `[cause]:` header — `agent-qa config show` awaited this loader bare and crash-printed the
|
|
31
|
-
* person's own file back at them. `console.error(err)` does the same thing, structured loggers
|
|
32
|
-
* (pino, winston) serialize the chain, and crash reporters upload it. So the cause carried here is
|
|
33
|
-
* a fresh `Error` holding THE SAME POSITION-ONLY SENTENCE as the message: a debugger still gets a
|
|
34
|
-
* chain to walk, and every one of those readers gets a position and nothing else. The caught value
|
|
35
|
-
* is not reachable from this error by any property.
|
|
36
|
-
*/
|
|
37
|
-
declare class ConfigFileNotYamlError extends Error {
|
|
38
|
-
readonly configPath: string;
|
|
39
|
-
constructor(configPath: string, cause: unknown);
|
|
1
|
+
import { AgentQaConfig, resolveKnowledgeRoot } from "@vostride/agent-qa-core";
|
|
2
|
+
import { Anchor, CanaryOutcome, CompletedRunHandoff, CurationSnapshot, MaskFn, RecordId, RunAnalysisArtifact } from "@vostride/agent-qa-schema";
|
|
3
|
+
import "commander";
|
|
4
|
+
import { CurationCandidateProjection, CuratorAuthor, EnqueueCurationCandidateProjectionOutcome, LocalCurationCapabilities, OpenServingKnowledgeReaderConfig } from "@vostride/agent-qa-agent-local";
|
|
5
|
+
import { ModelProfile, ResolvedModelAuth, createModel, createTokenAccounting, resolveCapabilities } from "@vostride/agent-qa-model";
|
|
6
|
+
import { KnowledgeHintReader } from "@vostride/agent-qa-runner";
|
|
7
|
+
import { loadCompletedRunHandoff } from "@vostride/agent-qa-runner-local";
|
|
8
|
+
import { runSafetyScope } from "@vostride/agent-qa-safety-local";
|
|
9
|
+
import "@vostride/agent-qa-agent";
|
|
10
|
+
import "@vostride/agent-qa-analytics";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export * from "@vostride/agent-qa-core";
|
|
13
|
+
export declare class ConfigFileNotYamlError extends Error {
|
|
14
|
+
readonly configPath: string;
|
|
15
|
+
constructor(configPath: string, cause: unknown);
|
|
40
16
|
}
|
|
41
17
|
/**
|
|
42
18
|
* THE READ AND THE PARSE GET SEPARATE CATCHES, and that separation is load-bearing.
|
|
43
19
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
20
|
+
* A missing file reads as `{}` here; `loadRequiredConfigFile` throws `ConfigFileNotFoundError`,
|
|
21
|
+
* whose message is `Config file not found: <path>`. A non-ENOENT read fault (EISDIR, EACCES) is a
|
|
22
|
+
* fact about the filesystem and not about the file's content, and is rethrown untouched. Only the
|
|
23
|
+
* PARSE throw is reworded — one guard, aimed at one channel.
|
|
48
24
|
*/
|
|
49
|
-
declare function loadConfigFile(configPath: string): Promise<unknown>;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* The message is BYTE-IDENTICAL to the bare `Error` this replaces, because that exact string is
|
|
54
|
-
* matched by the live lane's third-arm detection (`scripts/395-live-from-zero.sh:514`), folded by
|
|
55
|
-
* `coveringGrantInForce`, and pinned by `(E1)`. Nothing about what any surface PRINTS changes.
|
|
56
|
-
*
|
|
57
|
-
* What changes is that `showAction` can now ask WHICH fault this is by `instanceof` instead of by
|
|
58
|
-
* `message.startsWith(...)` — the reasoning `ConfigFileNotYamlError` above already wrote down: a
|
|
59
|
-
* caller that wants to recognise the case needs something better than a substring match on a
|
|
60
|
-
* sentence, and a sentence-matching caller is one rewording away from silently taking the wrong arm.
|
|
61
|
-
*/
|
|
62
|
-
declare class ConfigFileNotFoundError extends Error {
|
|
63
|
-
readonly configPath: string;
|
|
64
|
-
constructor(configPath: string);
|
|
25
|
+
export declare function loadConfigFile(configPath: string): Promise<unknown>;
|
|
26
|
+
export declare class ConfigFileNotFoundError extends Error {
|
|
27
|
+
readonly configPath: string;
|
|
28
|
+
constructor(configPath: string);
|
|
65
29
|
}
|
|
66
|
-
declare function loadRequiredConfigFile(configPath: string): Promise<unknown>;
|
|
67
|
-
declare function loadEnvOverrides(): Record<string, unknown>;
|
|
68
|
-
declare function mergeConfigs(file: unknown, env: Record<string, unknown>, flags: Record<string, unknown>): unknown;
|
|
69
|
-
declare function deepMerge(base: unknown, override: unknown): unknown;
|
|
70
|
-
declare function mergeWithTestConfig(globalConfig: unknown, testConfig: unknown, flagOverrides: Record<string, unknown>): unknown;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
declare function normalizeConfigForValidation(config: unknown): unknown;
|
|
79
|
-
declare function mergeUseBlocks(globalUse: Record<string, unknown> | undefined, suiteUse: Record<string, unknown> | undefined, testUse: Record<string, unknown> | undefined, cliFlags: Record<string, unknown>): Record<string, unknown>;
|
|
80
|
-
declare function formatConfigDebug(globalConfig: unknown, testConfig: unknown, flagOverrides: Record<string, unknown>, mask: MaskFn): string;
|
|
81
|
-
/**
|
|
82
|
-
* The privacy declaration alone, read out of the RAW document without validating it
|
|
83
|
-
* (Phase 398 gap round — finding F-1 / review CR-01).
|
|
84
|
-
*
|
|
85
|
-
* WHY THIS EXISTS. The composition roots that emit telemetry read their config through a tolerant
|
|
86
|
-
* `try { resolveConfig() } catch { undefined }`, because refusing a surface over its telemetry
|
|
87
|
-
* configuration would be refusing the capability over the telemetry (T-398-32). That posture is
|
|
88
|
-
* right and is unchanged. What was wrong is that the `catch` collapsed TWO different states into
|
|
89
|
-
* one `undefined`:
|
|
90
|
-
*
|
|
91
|
-
* 1. there is no config file — nothing was ever declared, and
|
|
92
|
-
* 2. there IS one, it declares `analytics.privacy: true`, and it failed schema validation for
|
|
93
|
-
* some unrelated reason (a missing `use.mobile.appState`, a legacy key, a typo three levels
|
|
94
|
-
* away).
|
|
95
|
-
*
|
|
96
|
-
* In state 2 a user set a shipped privacy control and was transmitted anyway, silently, with the
|
|
97
|
-
* surface working normally so nothing ever looked wrong. A product cannot ship a config field and
|
|
98
|
-
* then honour it only when the REST of the document happens to validate.
|
|
99
|
-
*
|
|
100
|
-
* READING IS NOT VALIDATING. Extracting one boolean from a parsed document does not require the
|
|
101
|
-
* document to be well-formed anywhere else, so honouring the declaration costs the availability
|
|
102
|
-
* posture nothing: the surface still opens, still scaffolds, still runs.
|
|
103
|
-
*
|
|
104
|
-
* IT READS THE SAME FILE THE VALIDATOR READ. The path expression and the loader are literally the
|
|
105
|
-
* ones `resolveConfig` uses, immediately below — not a second spelling of "where the config lives".
|
|
106
|
-
* A privacy read that consults a different file than the validator did would be a new defect
|
|
107
|
-
* wearing this fix's clothes.
|
|
108
|
-
*
|
|
109
|
-
* THE UNPARSEABLE ARM FAILS CLOSED. If the file exists but is not YAML at all, no reader can tell
|
|
110
|
-
* whether the declaration is in there. The cost of opting out is lost telemetry; the cost of the
|
|
111
|
-
* other choice is transmitting against a declaration that may be sitting in the file. For a
|
|
112
|
-
* privacy control the doubt resolves toward the user. A MISSING file is not doubt — nothing was
|
|
113
|
-
* declared — so it stays `undefined`.
|
|
114
|
-
*/
|
|
115
|
-
declare function readAnalyticsPrivacyDeclaration(configPath?: string): Promise<{
|
|
116
|
-
analytics: {
|
|
117
|
-
privacy: boolean;
|
|
118
|
-
};
|
|
30
|
+
export declare function loadRequiredConfigFile(configPath: string): Promise<unknown>;
|
|
31
|
+
export declare function loadEnvOverrides(): Record<string, unknown>;
|
|
32
|
+
export declare function mergeConfigs(file: unknown, env: Record<string, unknown>, flags: Record<string, unknown>): unknown;
|
|
33
|
+
export declare function deepMerge(base: unknown, override: unknown): unknown;
|
|
34
|
+
export declare function mergeWithTestConfig(globalConfig: unknown, testConfig: unknown, flagOverrides: Record<string, unknown>): unknown;
|
|
35
|
+
export declare function normalizeConfigForValidation(config: unknown): unknown;
|
|
36
|
+
export declare function mergeUseBlocks(globalUse: Record<string, unknown> | undefined, suiteUse: Record<string, unknown> | undefined, testUse: Record<string, unknown> | undefined, cliFlags: Record<string, unknown>): Record<string, unknown>;
|
|
37
|
+
export declare function formatConfigDebug(globalConfig: unknown, testConfig: unknown, flagOverrides: Record<string, unknown>, mask: MaskFn): string;
|
|
38
|
+
export declare function readAnalyticsPrivacyDeclaration(configPath?: string): Promise<{
|
|
39
|
+
analytics: {
|
|
40
|
+
privacy: boolean;
|
|
41
|
+
};
|
|
119
42
|
} | undefined>;
|
|
120
|
-
declare function resolveConfig(options: {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
43
|
+
export declare function resolveConfig(options: {
|
|
44
|
+
configPath?: string;
|
|
45
|
+
flags?: Record<string, unknown>;
|
|
46
|
+
loadAuthPlugins?: boolean;
|
|
124
47
|
}): Promise<AgentQaConfig>;
|
|
125
|
-
declare function loadConfigPlugins(config: AgentQaConfig, configPath: string): Promise<void>;
|
|
48
|
+
export declare function loadConfigPlugins(config: AgentQaConfig, configPath: string): Promise<void>;
|
|
126
49
|
/** Resolve the writer-gated knowledge root without making each CLI surface import core directly. */
|
|
127
|
-
declare function resolveConfiguredKnowledgeRoot(config: AgentQaConfig, configDir: string): string;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
* and "not configured" read the same to a resolver and differently to a person.
|
|
140
|
-
*/
|
|
141
|
-
declare function resolveRawConfigKnowledgeRoot(config: Record<string, unknown> | null, configPath: string): string | null;
|
|
142
|
-
|
|
143
|
-
interface ResolvedTarget {
|
|
144
|
-
name: string;
|
|
145
|
-
product: string;
|
|
146
|
-
platform: 'web' | 'android' | 'ios';
|
|
147
|
-
url?: string;
|
|
148
|
-
bundleId?: string;
|
|
149
|
-
appPackage?: string;
|
|
150
|
-
appActivity?: string;
|
|
151
|
-
device?: string;
|
|
152
|
-
/** D-06 (phase 401), 432 D-18: the target's declared environment; `undefined` means undeclared. */
|
|
153
|
-
environment?: 'local' | 'shared' | 'production';
|
|
50
|
+
export declare function resolveConfiguredKnowledgeRoot(config: AgentQaConfig, configDir: string): string;
|
|
51
|
+
export declare function resolveRawConfigKnowledgeRoot(config: Record<string, unknown> | null, configPath: string): string | null;
|
|
52
|
+
export interface ResolvedTarget {
|
|
53
|
+
name: string;
|
|
54
|
+
product: string;
|
|
55
|
+
platform: 'web' | 'android' | 'ios';
|
|
56
|
+
url?: string;
|
|
57
|
+
bundleId?: string;
|
|
58
|
+
appPackage?: string;
|
|
59
|
+
appActivity?: string;
|
|
60
|
+
device?: string;
|
|
61
|
+
environment?: 'local' | 'shared' | 'production';
|
|
154
62
|
}
|
|
155
|
-
interface TargetSummary {
|
|
156
|
-
|
|
157
|
-
|
|
63
|
+
export interface TargetSummary {
|
|
64
|
+
name: string;
|
|
65
|
+
platform: 'web' | 'android' | 'ios';
|
|
158
66
|
}
|
|
159
|
-
declare function resolveTarget(config: AgentQaConfig, targetName: string): ResolvedTarget;
|
|
160
|
-
declare function listTargets(config: AgentQaConfig): TargetSummary[];
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
* the requested test's stale plans are guaranteed gone.
|
|
167
|
-
*/
|
|
168
|
-
declare function purgeTest(_testPath: string, cacheDir: string): Promise<number>;
|
|
169
|
-
declare function purgeAll(cacheDir: string): Promise<number>;
|
|
170
|
-
|
|
171
|
-
/** Provisional M2 malformed-output retry cap; intentionally not a user-facing config key. */
|
|
172
|
-
declare const CURATOR_RETRY_CAP = 2;
|
|
173
|
-
/** Provisional M2 neighbor presentation cap; intentionally not a user-facing config key. */
|
|
174
|
-
declare const CURATOR_MAX_NEIGHBORS = 12;
|
|
67
|
+
export declare function resolveTarget(config: AgentQaConfig, targetName: string): ResolvedTarget;
|
|
68
|
+
export declare function listTargets(config: AgentQaConfig): TargetSummary[];
|
|
69
|
+
export declare function purgeAll(cacheDir: string): Promise<number>;
|
|
70
|
+
/** Malformed-output retry cap; deliberately not a user-facing config key. */
|
|
71
|
+
export declare const CURATOR_RETRY_CAP = 2;
|
|
72
|
+
/** Neighbor presentation cap; deliberately not a user-facing config key. */
|
|
73
|
+
export declare const CURATOR_MAX_NEIGHBORS = 12;
|
|
175
74
|
interface BuildCuratorAuthorDependencies {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
75
|
+
/** The run's already-resolved registry profile. It is reused verbatim. */
|
|
76
|
+
profile: ModelProfile;
|
|
77
|
+
auth: ResolvedModelAuth;
|
|
78
|
+
mask: MaskFn;
|
|
79
|
+
createModelImpl?: typeof createModel;
|
|
80
|
+
resolveCapabilitiesImpl?: typeof resolveCapabilities;
|
|
81
|
+
createTokenAccountingImpl?: typeof createTokenAccounting;
|
|
82
|
+
signal?: AbortSignal;
|
|
184
83
|
}
|
|
185
84
|
/**
|
|
186
85
|
* Build the CLI-owned Curator author over the run's already-resolved model. The returned function
|
|
187
86
|
* reads no config and every provider call therefore traverses createModel's registry middleware.
|
|
188
87
|
*/
|
|
189
|
-
declare function buildCuratorAuthor(deps: BuildCuratorAuthorDependencies): CuratorAuthor;
|
|
190
|
-
|
|
88
|
+
export declare function buildCuratorAuthor(deps: BuildCuratorAuthorDependencies): CuratorAuthor;
|
|
191
89
|
declare const nudgeResponseSchema: z.ZodObject<{
|
|
192
|
-
|
|
90
|
+
sessionId: z.ZodString;
|
|
193
91
|
}, z.core.$strict>;
|
|
194
92
|
type NudgeResponse = z.infer<typeof nudgeResponseSchema>;
|
|
195
|
-
|
|
196
93
|
interface NudgeDaemonOptions {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
94
|
+
/** Resolved configured root; defaults only for legacy project-local callers. */
|
|
95
|
+
readonly knowledgeRoot?: string;
|
|
96
|
+
/** Absolute wall-clock deadline shared with the caller's complete operation. */
|
|
97
|
+
readonly deadlineMs?: number;
|
|
98
|
+
/** Request an empty terminal receipt when the caller gates completion on it. */
|
|
99
|
+
readonly requireReceipt?: boolean;
|
|
100
|
+
readonly signal?: AbortSignal;
|
|
204
101
|
}
|
|
205
102
|
/** Best-effort curation wake-up returning the durable session identity when acknowledged. */
|
|
206
103
|
declare function nudgeDaemon(agentQaRoot: string, options?: NudgeDaemonOptions): Promise<NudgeResponse | undefined>;
|
|
207
|
-
|
|
208
|
-
declare const completionSchema: z.ZodObject<{
|
|
209
|
-
schemaVersion: z.ZodLiteral<2>;
|
|
210
|
-
runId: z.ZodString;
|
|
211
|
-
candidateId: z.ZodString;
|
|
212
|
-
attributedObservationId: z.ZodString;
|
|
213
|
-
observedStateDigest: z.ZodString;
|
|
214
|
-
result: z.ZodUnion<readonly [z.ZodObject<{
|
|
215
|
-
kind: z.ZodLiteral<"ablated">;
|
|
216
|
-
crossCheck: z.ZodEnum<{
|
|
217
|
-
flipped: "flipped";
|
|
218
|
-
held: "held";
|
|
219
|
-
inconclusive: "inconclusive";
|
|
220
|
-
"not-run": "not-run";
|
|
221
|
-
}>;
|
|
222
|
-
corpusDigest: z.ZodString;
|
|
223
|
-
k: z.ZodNumber;
|
|
224
|
-
baseSeed: z.ZodNumber;
|
|
225
|
-
seeds: z.ZodArray<z.ZodNumber>;
|
|
226
|
-
seedHonored: z.ZodBoolean;
|
|
227
|
-
spend: z.ZodObject<{
|
|
228
|
-
modelCalls: z.ZodNumber;
|
|
229
|
-
screens: z.ZodNumber;
|
|
230
|
-
promptTokens: z.ZodNumber;
|
|
231
|
-
completionTokens: z.ZodNumber;
|
|
232
|
-
}, z.core.$strict>;
|
|
233
|
-
gate2Dir: z.ZodString;
|
|
234
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
235
|
-
kind: z.ZodLiteral<"error">;
|
|
236
|
-
message: z.ZodLiteral<"ablation-error">;
|
|
237
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
238
|
-
kind: z.ZodLiteral<"unavailable">;
|
|
239
|
-
reason: z.ZodLiteral<"ablation-unavailable">;
|
|
240
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
241
|
-
kind: z.ZodLiteral<"no-eval-root">;
|
|
242
|
-
}, z.core.$strict>]>;
|
|
243
|
-
}, z.core.$strict>;
|
|
244
|
-
type CompletedCanaryAblation = z.infer<typeof completionSchema>;
|
|
245
|
-
|
|
246
|
-
interface CanaryAblationInput {
|
|
247
|
-
handoff: CompletedRunHandoff;
|
|
248
|
-
runDir: string;
|
|
249
|
-
candidateId: string;
|
|
250
|
-
runId: string;
|
|
251
|
-
testId: string;
|
|
252
|
-
testIndex: number;
|
|
253
|
-
stepIndex: number;
|
|
254
|
-
attributedObservationId: string;
|
|
255
|
-
}
|
|
256
|
-
type CanaryAblationResult = {
|
|
257
|
-
kind: 'ablated';
|
|
258
|
-
crossCheck: CrossCheck;
|
|
259
|
-
corpusDigest: string;
|
|
260
|
-
k: number;
|
|
261
|
-
baseSeed: number;
|
|
262
|
-
seeds: number[];
|
|
263
|
-
seedHonored: boolean;
|
|
264
|
-
spend: {
|
|
265
|
-
modelCalls: number;
|
|
266
|
-
screens: number;
|
|
267
|
-
promptTokens: number;
|
|
268
|
-
completionTokens: number;
|
|
269
|
-
};
|
|
270
|
-
gate2Dir: string;
|
|
271
|
-
} | {
|
|
272
|
-
kind: 'no-eval-root';
|
|
273
|
-
} | {
|
|
274
|
-
kind: 'unavailable';
|
|
275
|
-
reason: string;
|
|
276
|
-
} | {
|
|
277
|
-
kind: 'error';
|
|
278
|
-
message: string;
|
|
279
|
-
};
|
|
280
|
-
type CanaryCorpusDigestResult = {
|
|
281
|
-
kind: 'digest';
|
|
282
|
-
corpusDigest: string;
|
|
283
|
-
} | {
|
|
284
|
-
kind: 'no-eval-root';
|
|
285
|
-
} | {
|
|
286
|
-
kind: 'unavailable';
|
|
287
|
-
reason: string;
|
|
288
|
-
};
|
|
289
|
-
interface CanaryAblation {
|
|
290
|
-
isNovel(input: {
|
|
291
|
-
product: string;
|
|
292
|
-
stateDigest: string;
|
|
293
|
-
}): Promise<boolean>;
|
|
294
|
-
stage(input: CanaryAblationInput & {
|
|
295
|
-
product: string;
|
|
296
|
-
stateDigest: string;
|
|
297
|
-
benefit: Benefit;
|
|
298
|
-
}): Promise<{
|
|
299
|
-
kind: 'staged' | 'already-staged' | 'not-novel' | 'no-eval-root' | 'target-unavailable' | 'write-conflict';
|
|
300
|
-
} | {
|
|
301
|
-
kind: 'unavailable';
|
|
302
|
-
reason: string;
|
|
303
|
-
} | {
|
|
304
|
-
kind: 'error';
|
|
305
|
-
message: string;
|
|
306
|
-
}>;
|
|
307
|
-
ablate(input: CanaryAblationInput): Promise<CanaryAblationResult>;
|
|
308
|
-
corpusDigest(): Promise<CanaryCorpusDigestResult>;
|
|
309
|
-
resolveCaps?(): Promise<{
|
|
310
|
-
maxAblations: number;
|
|
311
|
-
source: string;
|
|
312
|
-
}>;
|
|
313
|
-
}
|
|
314
104
|
interface CanaryCreditCounters {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
ablationHeld: number;
|
|
319
|
-
ablationInconclusive: number;
|
|
320
|
-
ablationError: number;
|
|
321
|
-
rerunExcluded: number;
|
|
322
|
-
nonSignal: Record<NonSignalClass, number>;
|
|
323
|
-
staged: number;
|
|
324
|
-
stagingRefused: number;
|
|
325
|
-
}
|
|
326
|
-
interface CanaryCreditInput {
|
|
327
|
-
completedAblations: readonly CompletedCanaryAblation[];
|
|
328
|
-
saveCompletedAblation: (entry: CompletedCanaryAblation) => void;
|
|
329
|
-
maxAblations: number;
|
|
330
|
-
knowledgeRoot: string;
|
|
331
|
-
readBundleStateDigests: LocalCurationCapabilities['readCanonicalBundleStateDigests'];
|
|
332
|
-
attributions: readonly ProjectedCanaryAttribution[];
|
|
333
|
-
ablation?: CanaryAblation;
|
|
334
|
-
handoff: CompletedRunHandoff;
|
|
335
|
-
runDir: string;
|
|
336
|
-
observationIdOf: (outcome: CanaryOutcome) => string;
|
|
105
|
+
rideAlongUncredited: number;
|
|
106
|
+
rerunExcluded: number;
|
|
107
|
+
nonSignal: Record<NonSignalClass, number>;
|
|
337
108
|
}
|
|
338
|
-
|
|
339
109
|
type NonSignalClass = 'environment' | 'timeout' | 'flake';
|
|
340
110
|
interface ProjectCanaryOutcomesInput {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
* `emitCanaryOutcomes` loads it from the fold's own `runDir`; the pure projection takes it
|
|
345
|
-
* as an argument so identical (handoff, artifact) bytes keep yielding identical outcomes.
|
|
346
|
-
*/
|
|
347
|
-
artifact?: RunAnalysisArtifact;
|
|
348
|
-
/**
|
|
349
|
-
* The circularity arbiter's per-record rows (422-16, D-20), when the handoff's own published
|
|
350
|
-
* sidecar is not the copy the caller holds — `emitCanaryOutcomes` supplies this only for the
|
|
351
|
-
* durable-recovery case below. ABSENT here means "read `handoff.misdirectionEvidence`", which
|
|
352
|
-
* is itself absent on every run written before 422. Data, never a port.
|
|
353
|
-
*/
|
|
354
|
-
misdirectionEvidence?: readonly MisdirectionRecordResult[];
|
|
355
|
-
resolveCandidateAnchors: (id: RecordId) => CandidateAnchorResolution;
|
|
111
|
+
handoff: CompletedRunHandoff;
|
|
112
|
+
artifact?: RunAnalysisArtifact;
|
|
113
|
+
resolveCandidateAnchors: (id: RecordId) => CandidateAnchorResolution;
|
|
356
114
|
}
|
|
357
115
|
type CandidateAnchorResolution = {
|
|
358
|
-
|
|
359
|
-
|
|
116
|
+
kind: 'resolved';
|
|
117
|
+
anchors: Anchor[];
|
|
360
118
|
} | {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
119
|
+
kind: 'unresolved';
|
|
120
|
+
reason: 'not-found' | 'invalid' | 'lookup-error';
|
|
121
|
+
detail?: string;
|
|
364
122
|
};
|
|
365
123
|
type EmitCanaryOutcomeResult = {
|
|
366
|
-
|
|
367
|
-
|
|
124
|
+
kind: 'non-signal';
|
|
125
|
+
class: NonSignalClass;
|
|
368
126
|
} | {
|
|
369
|
-
|
|
127
|
+
kind: 'emitted';
|
|
370
128
|
} | {
|
|
371
|
-
|
|
372
|
-
|
|
129
|
+
kind: 'refused';
|
|
130
|
+
reason: 'emit-error';
|
|
373
131
|
} | {
|
|
132
|
+
kind: 'unresolved';
|
|
133
|
+
reason: Extract<CandidateAnchorResolution, {
|
|
374
134
|
kind: 'unresolved';
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
}>['reason'];
|
|
378
|
-
detail?: string;
|
|
135
|
+
}>['reason'];
|
|
136
|
+
detail?: string;
|
|
379
137
|
};
|
|
380
138
|
type EmitCanaryOutcomeDetail = {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
testIndex: number;
|
|
390
|
-
outcome: {
|
|
391
|
-
kind: 'rerun-excluded';
|
|
392
|
-
};
|
|
139
|
+
benefit?: never;
|
|
140
|
+
candidateId?: never;
|
|
141
|
+
stepIndex?: never;
|
|
142
|
+
testId: string;
|
|
143
|
+
testIndex: number;
|
|
144
|
+
outcome: {
|
|
145
|
+
kind: 'rerun-excluded';
|
|
146
|
+
};
|
|
393
147
|
} | {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
* not on anchor contact. Distinct from `crossCheck` beside it, which is the Gate-2 ABLATION's
|
|
401
|
-
* answer about a positive — two different cross-checks, and conflating them would read a
|
|
402
|
-
* removal that proved harm as a removal that proved benefit.
|
|
403
|
-
*/
|
|
404
|
-
misdirectionFlipped?: true;
|
|
405
|
-
candidateId: RecordId;
|
|
406
|
-
testId: string;
|
|
407
|
-
testIndex: number;
|
|
408
|
-
stepIndex: number;
|
|
409
|
-
outcome: EmitCanaryOutcomeResult;
|
|
148
|
+
benefit: CanaryOutcome['benefit'];
|
|
149
|
+
candidateId: RecordId;
|
|
150
|
+
testId: string;
|
|
151
|
+
testIndex: number;
|
|
152
|
+
stepIndex: number;
|
|
153
|
+
outcome: EmitCanaryOutcomeResult;
|
|
410
154
|
};
|
|
411
155
|
interface EmitCanaryOutcomeReport {
|
|
412
|
-
|
|
156
|
+
canary: CanaryCreditCounters;
|
|
157
|
+
emitted: number;
|
|
158
|
+
refused: number;
|
|
159
|
+
unresolved: number;
|
|
160
|
+
procedure: {
|
|
413
161
|
emitted: number;
|
|
414
162
|
refused: number;
|
|
415
163
|
unresolved: number;
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
emitted: number;
|
|
419
|
-
refused: number;
|
|
420
|
-
unresolved: number;
|
|
421
|
-
};
|
|
422
|
-
/**
|
|
423
|
-
* 422-16 (D-20): rows the arbiter's FLIPPED evidence sent to the harmed-outcome writer carry
|
|
424
|
-
* `misdirectionFlipped` on their DETAIL, and are counted from there rather than from a
|
|
425
|
-
* fourth total here. Two reasons, both deliberate. The consequence is the ordinary harmed
|
|
426
|
-
* outcome, so a parallel total would invite a reader to add it to `emitted`. And a required
|
|
427
|
-
* new member on this report would break every existing `emitCanaryOutcomes` double in the
|
|
428
|
-
* tree — the tail reads the rows it already renders, exactly as `candidateSummaryLine` does.
|
|
429
|
-
*/
|
|
430
|
-
details: EmitCanaryOutcomeDetail[];
|
|
164
|
+
};
|
|
165
|
+
details: EmitCanaryOutcomeDetail[];
|
|
431
166
|
}
|
|
432
167
|
interface EmitCanaryOutcomesOptions {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
emit: (outcome: CanaryOutcome) => void;
|
|
168
|
+
handoff: CompletedRunHandoff;
|
|
169
|
+
/** Absolute agent-qa-knowledge root used for store lookup and durable queue emission. */
|
|
170
|
+
knowledgeRoot: string;
|
|
171
|
+
/** Absolute completed-run directory retained to keep the two post-verdict emit seams aligned. */
|
|
172
|
+
runDir: string;
|
|
173
|
+
emit: (outcome: CanaryOutcome) => void;
|
|
440
174
|
}
|
|
441
|
-
type AttributionSource = 'served-brief' | 'procedure-replay';
|
|
442
|
-
type ProjectedCanaryAttribution = {
|
|
443
|
-
kind: 'rerun-excluded';
|
|
444
|
-
testId: string;
|
|
445
|
-
testIndex: number;
|
|
446
|
-
} | {
|
|
447
|
-
kind: 'non-signal';
|
|
448
|
-
source: AttributionSource;
|
|
449
|
-
class: NonSignalClass;
|
|
450
|
-
candidateId: RecordId;
|
|
451
|
-
testId: string;
|
|
452
|
-
testIndex: number;
|
|
453
|
-
stepIndex: number;
|
|
454
|
-
} | {
|
|
455
|
-
kind: 'outcome';
|
|
456
|
-
source: AttributionSource;
|
|
457
|
-
outcome: CanaryOutcome;
|
|
458
|
-
/** 422-16 (D-20): selected by the arbiter's flipped row rather than by anchor contact. */
|
|
459
|
-
misdirectionFlipped?: true;
|
|
460
|
-
} | {
|
|
461
|
-
kind: 'unresolved';
|
|
462
|
-
source: AttributionSource;
|
|
463
|
-
candidateId: RecordId;
|
|
464
|
-
testId: string;
|
|
465
|
-
testIndex: number;
|
|
466
|
-
stepIndex: number;
|
|
467
|
-
reason: Extract<CandidateAnchorResolution, {
|
|
468
|
-
kind: 'unresolved';
|
|
469
|
-
}>['reason'];
|
|
470
|
-
detail?: string;
|
|
471
|
-
};
|
|
472
175
|
/** Pure Pin-1 projection: identical handoff + canonical snapshot yields identical outcome bytes. */
|
|
473
|
-
declare function projectCanaryOutcomes(input: ProjectCanaryOutcomesInput): CanaryOutcome[];
|
|
474
|
-
/** Resolves anchors read-only,
|
|
475
|
-
declare function emitCanaryOutcomes(opts: EmitCanaryOutcomesOptions): Promise<EmitCanaryOutcomeReport>;
|
|
476
|
-
|
|
176
|
+
export declare function projectCanaryOutcomes(input: ProjectCanaryOutcomesInput): CanaryOutcome[];
|
|
177
|
+
/** Resolves anchors read-only, sets each benefit, then emits every attribution in isolation. */
|
|
178
|
+
export declare function emitCanaryOutcomes(opts: EmitCanaryOutcomesOptions): Promise<EmitCanaryOutcomeReport>;
|
|
477
179
|
interface EmitCurationCandidatesOptions {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
180
|
+
handoff: CompletedRunHandoff;
|
|
181
|
+
/** Absolute completed-run directory containing runner-local's blobs/ subdirectory. */
|
|
182
|
+
runDir: string;
|
|
183
|
+
/** Absolute agent-qa-knowledge root that owns the durable queue. */
|
|
184
|
+
knowledgeRoot: string;
|
|
185
|
+
mask?: MaskFn;
|
|
484
186
|
}
|
|
485
187
|
type EmitCandidateOutcome = EnqueueCurationCandidateProjectionOutcome | {
|
|
486
|
-
|
|
487
|
-
|
|
188
|
+
kind: 'refused';
|
|
189
|
+
reason: 'artifact-io-error';
|
|
488
190
|
};
|
|
489
191
|
interface EmitCandidateDetail {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
192
|
+
candidateId?: string;
|
|
193
|
+
/** The projecting candidate's kind: per-kind outcome attribution from the report alone. */
|
|
194
|
+
kind: CurationCandidateProjection['kind'];
|
|
195
|
+
outcome: EmitCandidateOutcome;
|
|
494
196
|
}
|
|
495
197
|
interface EmitReport {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
198
|
+
enqueued: number;
|
|
199
|
+
coalesced: number;
|
|
200
|
+
capExceeded: number;
|
|
201
|
+
refused: number;
|
|
202
|
+
details: EmitCandidateDetail[];
|
|
501
203
|
}
|
|
502
204
|
/**
|
|
503
205
|
* Resolves runner-local artifact blobs and synchronously publishes each candidate in isolation.
|
|
504
206
|
* Queue publication owns temp-write, fsync, cap enforcement, and atomic rename semantics.
|
|
505
207
|
*/
|
|
506
208
|
declare function emitCurationCandidates(opts: EmitCurationCandidatesOptions): EmitReport;
|
|
507
|
-
|
|
508
|
-
type ResolveTrustPriors = () => TrustPriorTable | undefined;
|
|
509
|
-
|
|
510
209
|
type RunCurationContext = {
|
|
511
|
-
|
|
512
|
-
|
|
210
|
+
readonly mask: MaskFn;
|
|
211
|
+
readonly knowledgeRoot: string;
|
|
513
212
|
} | {
|
|
514
|
-
|
|
213
|
+
readonly handBack: string;
|
|
515
214
|
};
|
|
516
215
|
declare function resolveRunCurationContext(input: {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
216
|
+
readonly agentQaRoot: string;
|
|
217
|
+
readonly runId: string;
|
|
218
|
+
readonly drainerKnowledgeRoot: string;
|
|
520
219
|
}): Promise<RunCurationContext>;
|
|
521
|
-
|
|
522
|
-
declare const CURATION_TAIL_RECEIPT_FILE = "curation-tail-receipt.json";
|
|
220
|
+
export declare const CURATION_TAIL_RECEIPT_FILE = "curation-tail-receipt.json";
|
|
523
221
|
/** The receipt's key set and stamp must match exactly; anything else refolds the run once. */
|
|
524
|
-
declare const CURATION_TAIL_RECEIPT_SCHEMA_VERSION = 2;
|
|
222
|
+
export declare const CURATION_TAIL_RECEIPT_SCHEMA_VERSION = 2;
|
|
525
223
|
interface CurationTailReceipt {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
* new version through this same sweep.
|
|
542
|
-
*/
|
|
543
|
-
projectionVersion: number;
|
|
544
|
-
drainKind: 'drained' | 'handed-off';
|
|
545
|
-
/** The standing writer that accepted the handoff; null when this run drained inline. */
|
|
546
|
-
handoffHolderPid: number | null;
|
|
547
|
-
/** Stable run-side provenance, ordered before the receipt bytes are committed. */
|
|
548
|
-
candidateIds: string[];
|
|
224
|
+
/** Fixed successful membership; absent on handed-off receipts and when no validated snapshot was recorded. */
|
|
225
|
+
snapshot?: CurationSnapshot;
|
|
226
|
+
/** Counts recorded beside the snapshot. */
|
|
227
|
+
curated?: number;
|
|
228
|
+
deprecated?: number;
|
|
229
|
+
canary: CanaryCreditCounters;
|
|
230
|
+
schemaVersion: typeof CURATION_TAIL_RECEIPT_SCHEMA_VERSION;
|
|
231
|
+
runId: string;
|
|
232
|
+
handoffDigest: string;
|
|
233
|
+
projectionVersion: number;
|
|
234
|
+
drainKind: 'drained' | 'handed-off';
|
|
235
|
+
/** The standing writer that accepted the handoff; null when this run drained inline. */
|
|
236
|
+
handoffHolderPid: number | null;
|
|
237
|
+
/** Stable run-side provenance, ordered before the receipt bytes are committed. */
|
|
238
|
+
candidateIds: string[];
|
|
549
239
|
}
|
|
550
240
|
type CurationTailModelDeps = Pick<BuildCuratorAuthorDependencies, 'profile' | 'auth'>;
|
|
551
241
|
interface CurationTailLogger {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
info?(message: string): void;
|
|
242
|
+
warn(message: string): void;
|
|
243
|
+
info?(message: string): void;
|
|
555
244
|
}
|
|
556
245
|
interface CurationTailOperations {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
nudgeDaemon: typeof nudgeDaemon;
|
|
575
|
-
resolveRunCurationContext: typeof resolveRunCurationContext;
|
|
246
|
+
loadCompletedRunHandoff: typeof loadCompletedRunHandoff;
|
|
247
|
+
resolveKnowledgeRoot: typeof resolveKnowledgeRoot;
|
|
248
|
+
runSafetyScope: typeof runSafetyScope;
|
|
249
|
+
emitCurationCandidates: typeof emitCurationCandidates;
|
|
250
|
+
openKnowledgeReader(config: OpenServingKnowledgeReaderConfig): KnowledgeHintReader;
|
|
251
|
+
emitCanaryOutcomes: typeof emitCanaryOutcomes;
|
|
252
|
+
foldRunOutcomes: LocalCurationCapabilities['foldRunOutcomes'];
|
|
253
|
+
reconcileRunOutcomesProjection: LocalCurationCapabilities['reconcileRunOutcomesProjection'];
|
|
254
|
+
acquireWriterLease: LocalCurationCapabilities['maintenance']['acquireWriterLease'];
|
|
255
|
+
releaseLease: LocalCurationCapabilities['maintenance']['releaseLease'];
|
|
256
|
+
buildCuratorAuthor: typeof buildCuratorAuthor;
|
|
257
|
+
drainQueue: LocalCurationCapabilities['drainQueue'];
|
|
258
|
+
listCompletedRunDirs(agentQaRoot: string): string[];
|
|
259
|
+
readCurationTailReceipt(runDir: string): CurationTailReceipt | undefined;
|
|
260
|
+
writeCurationTailReceipt(runDir: string, receipt: CurationTailReceipt): void;
|
|
261
|
+
nudgeDaemon: typeof nudgeDaemon;
|
|
262
|
+
resolveRunCurationContext: typeof resolveRunCurationContext;
|
|
576
263
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Writer authority the CALLER already holds (388-02, Pitfall 7).
|
|
579
|
-
*
|
|
580
|
-
* The fold acquires no lease of its own when this is present. That is not an optimisation: a
|
|
581
|
-
* process holding the writer lease that calls `acquireWriterLease` again is told `held` — by
|
|
582
|
-
* itself — and would hand its own work off to nobody (the 387-08 D-18 shape).
|
|
583
|
-
*/
|
|
584
264
|
interface CurationWriterAuthority {
|
|
585
|
-
|
|
586
|
-
|
|
265
|
+
leaseId: string;
|
|
266
|
+
epoch: number;
|
|
587
267
|
}
|
|
588
268
|
interface RunCurationTailOptions {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
signal?: AbortSignal;
|
|
606
|
-
log: CurationTailLogger;
|
|
607
|
-
/** 388-02: the sweep runs under the post-run tail's held lease when there is one. */
|
|
608
|
-
authority?: CurationWriterAuthority;
|
|
609
|
-
/** 388-02 (D-03): absolute wall-clock stop point shared with the one post-run budget. */
|
|
610
|
-
deadlineMs?: number;
|
|
611
|
-
/** Focused test seam. Production callers omit it. */
|
|
612
|
-
operations?: Partial<CurationTailOperations>;
|
|
269
|
+
runId: string;
|
|
270
|
+
/** Absolute `.agent-qa` runtime root the run handoff lives under. */
|
|
271
|
+
agentQaRoot: string;
|
|
272
|
+
knowledgeConfig: {
|
|
273
|
+
dir: string;
|
|
274
|
+
};
|
|
275
|
+
configDir: string;
|
|
276
|
+
mask?: MaskFn;
|
|
277
|
+
/** The exact already-resolved planner profile and auth used by the run. */
|
|
278
|
+
modelDeps?: CurationTailModelDeps;
|
|
279
|
+
signal?: AbortSignal;
|
|
280
|
+
log: CurationTailLogger;
|
|
281
|
+
authority?: CurationWriterAuthority;
|
|
282
|
+
deadlineMs?: number;
|
|
283
|
+
/** Focused test seam. Production callers omit it. */
|
|
284
|
+
operations?: Partial<CurationTailOperations>;
|
|
613
285
|
}
|
|
614
|
-
declare function curationTailHandoffDigest(handoff: unknown): string;
|
|
286
|
+
export declare function curationTailHandoffDigest(handoff: unknown): string;
|
|
615
287
|
/**
|
|
616
288
|
* Run the post-verdict curation fold. The caller fixes its exit code before awaiting this function;
|
|
617
289
|
* every failure is logged here and intentionally resolves so learning can never change the verdict.
|
|
618
290
|
*/
|
|
619
|
-
declare function runCurationTail(opts: RunCurationTailOptions): Promise<void>;
|
|
291
|
+
export declare function runCurationTail(opts: RunCurationTailOptions): Promise<void>;
|
|
620
292
|
interface RunVerdictFirstCurationTailOptions {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
*/
|
|
632
|
-
enqueue?(): Promise<void>;
|
|
633
|
-
runTail(): Promise<void>;
|
|
634
|
-
/**
|
|
635
|
-
* The user-facing close-out, run on BOTH paths (388-04, D-08).
|
|
636
|
-
*
|
|
637
|
-
* The detach short-circuit below returns before `runTail`, and the one posture that most
|
|
638
|
-
* needs a line about work left queued is exactly that one — so this cannot live inside the
|
|
639
|
-
* tail. It is told which gate was applied rather than inferring it, because the gate is
|
|
640
|
-
* this function's own knowledge and nothing downstream can see it.
|
|
641
|
-
*/
|
|
642
|
-
finish?(input: {
|
|
643
|
-
detached: boolean;
|
|
644
|
-
}): Promise<void>;
|
|
645
|
-
/** Defensive call-site boundary; runCurationTail itself already never rejects. */
|
|
646
|
-
onUnexpectedError?(error: unknown): void;
|
|
293
|
+
/** The complete verdict-derived process code, fixed before the tail begins. */
|
|
294
|
+
exitCode: number;
|
|
295
|
+
detach: boolean;
|
|
296
|
+
enqueue?(): Promise<void>;
|
|
297
|
+
runTail(): Promise<void>;
|
|
298
|
+
finish?(input: {
|
|
299
|
+
detached: boolean;
|
|
300
|
+
}): Promise<void>;
|
|
301
|
+
/** Defensive call-site boundary; runCurationTail itself already never rejects. */
|
|
302
|
+
onUnexpectedError?(error: unknown): void;
|
|
647
303
|
}
|
|
648
304
|
/** Await the optional tail without permitting it to replace the already-fixed verdict code. */
|
|
649
|
-
declare function runVerdictFirstCurationTail(opts: RunVerdictFirstCurationTailOptions): Promise<number>;
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
export { type BuildCuratorAuthorDependencies, CURATION_TAIL_RECEIPT_FILE, CURATION_TAIL_RECEIPT_SCHEMA_VERSION, CURATOR_MAX_NEIGHBORS, CURATOR_RETRY_CAP, ConfigFileNotFoundError, ConfigFileNotYamlError, type CurationTailLogger, type CurationTailModelDeps, type CurationTailOperations, type CurationTailReceipt, type EmitCanaryOutcomeDetail, type EmitCanaryOutcomeReport, type EmitCanaryOutcomeResult, type EmitCanaryOutcomesOptions, type ProjectCanaryOutcomesInput, type ResolvedTarget, type RunCurationTailOptions, type RunVerdictFirstCurationTailOptions, type TargetSummary, VERSION, buildCuratorAuthor, curationTailHandoffDigest, deepMerge, emitCanaryOutcomes, formatConfigDebug, listTargets, loadConfigFile, loadConfigPlugins, loadEnvOverrides, loadRequiredConfigFile, mergeConfigs, mergeUseBlocks, mergeWithTestConfig, normalizeConfigForValidation, projectCanaryOutcomes, purgeAll, purgeTest, readAnalyticsPrivacyDeclaration, resolveConfig, resolveConfiguredKnowledgeRoot, resolveRawConfigKnowledgeRoot, resolveTarget, runCurationTail, runVerdictFirstCurationTail };
|
|
305
|
+
export declare function runVerdictFirstCurationTail(opts: RunVerdictFirstCurationTailOptions): Promise<number>;
|
|
306
|
+
export declare const VERSION: string;
|
|
307
|
+
export type { BuildCuratorAuthorDependencies, CurationTailLogger, CurationTailModelDeps, CurationTailOperations, CurationTailReceipt, EmitCanaryOutcomeDetail, EmitCanaryOutcomeReport, EmitCanaryOutcomeResult, EmitCanaryOutcomesOptions, ProjectCanaryOutcomesInput, RunCurationTailOptions, RunVerdictFirstCurationTailOptions };
|