@sanity/ailf 6.0.0 → 6.1.1
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/config/airbyte/ai_literacy_framework.connector.yaml +276 -0
- package/config/bigquery/views/synthesis_parse_failure_rate_7d.sql +42 -0
- package/dist/_vendor/ailf-core/artifact-registry.d.ts +17 -0
- package/dist/_vendor/ailf-core/artifact-registry.js +14 -0
- package/dist/_vendor/ailf-core/ports/context.d.ts +22 -0
- package/dist/_vendor/ailf-core/schemas/eval-config.d.ts +7 -0
- package/dist/_vendor/ailf-core/schemas/eval-config.js +8 -0
- package/dist/_vendor/ailf-core/services/diagnosis/cards/__tests__/failure-mode-summary.test.js +59 -0
- package/dist/_vendor/ailf-core/services/diagnosis/cards/doc-attribution-spotlight.js +5 -1
- package/dist/_vendor/ailf-core/services/diagnosis/cards/failure-mode-summary.js +47 -3
- package/dist/_vendor/ailf-core/services/diagnosis/cards/index.d.ts +10 -0
- package/dist/_vendor/ailf-core/services/diagnosis/cards/index.js +13 -0
- package/dist/_vendor/ailf-core/services/diagnosis/cards/low-confidence-attribution.js +17 -1
- package/dist/_vendor/ailf-core/services/diagnosis/cards/no-issues.js +1 -1
- package/dist/_vendor/ailf-core/services/diagnosis/cards/regression-vs-baseline.js +5 -1
- package/dist/_vendor/ailf-core/services/diagnosis/cards/top-recommendations.js +5 -1
- package/dist/_vendor/ailf-core/services/diagnosis/cards/weakest-area.js +5 -1
- package/dist/_vendor/ailf-core/services/diagnosis/prompt-builders.js +15 -2
- package/dist/_vendor/ailf-core/services/diagnosis/prompts/weakest-area.system.d.ts +5 -3
- package/dist/_vendor/ailf-core/services/diagnosis/prompts/weakest-area.system.js +19 -31
- package/dist/_vendor/ailf-core/services/index.d.ts +1 -1
- package/dist/_vendor/ailf-core/services/index.js +1 -1
- package/dist/_vendor/ailf-core/types/diagnosis.d.ts +3 -0
- package/dist/_vendor/ailf-core/types/index.d.ts +7 -0
- package/dist/_vendor/ailf-core/types/repo-config.d.ts +16 -0
- package/dist/_vendor/ailf-core/types/synthesis-telemetry.d.ts +101 -0
- package/dist/_vendor/ailf-core/types/synthesis-telemetry.js +18 -0
- package/dist/adapters/config-sources/file-config-adapter.js +8 -6
- package/dist/adapters/llm/index.d.ts +1 -1
- package/dist/adapters/llm/index.js +1 -1
- package/dist/adapters/llm/openai-llm-client.js +7 -2
- package/dist/adapters/llm/retry.d.ts +18 -0
- package/dist/adapters/llm/retry.js +21 -0
- package/dist/adapters/synthesis/synthesis-telemetry-schema.d.ts +49 -0
- package/dist/adapters/synthesis/synthesis-telemetry-schema.js +55 -0
- package/dist/adapters/task-sources/content-lake-task-source.js +10 -5
- package/dist/adapters/task-sources/repo-schemas.d.ts +7 -0
- package/dist/adapters/task-sources/repo-schemas.js +10 -0
- package/dist/artifact-capture/api-gateway-artifact-writer.d.ts +11 -1
- package/dist/artifact-capture/api-gateway-artifact-writer.js +3 -1
- package/dist/artifact-capture/batching-api-gateway-artifact-writer.d.ts +11 -1
- package/dist/artifact-capture/batching-api-gateway-artifact-writer.js +3 -1
- package/dist/artifact-capture/gcs-artifact-writer.d.ts +11 -1
- package/dist/artifact-capture/gcs-artifact-writer.js +6 -3
- package/dist/artifact-capture/local-fs-artifact-writer.d.ts +11 -1
- package/dist/artifact-capture/local-fs-artifact-writer.js +6 -3
- package/dist/commands/interpret.d.ts +21 -1
- package/dist/commands/interpret.js +13 -4
- package/dist/commands/pipeline-action.d.ts +44 -0
- package/dist/commands/pipeline-action.js +193 -1
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +2 -0
- package/dist/composition-root.d.ts +22 -5
- package/dist/composition-root.js +78 -8
- package/dist/orchestration/pipeline-orchestrator.js +3 -0
- package/dist/orchestration/steps/gap-analysis-step.js +0 -1
- package/dist/report-store.d.ts +40 -0
- package/dist/report-store.js +88 -0
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod adapter schema for SynthesisCostTelemetry at the trust boundary.
|
|
3
|
+
*
|
|
4
|
+
* This schema sits at `packages/eval/src/adapters/**` and is therefore
|
|
5
|
+
* scanned by `pnpm check-trust-boundary-satisfies` (D0045). The
|
|
6
|
+
* `satisfies z.ZodType<SynthesisCostTelemetry>` clause makes schema/type
|
|
7
|
+
* drift a build error, not a runtime bug.
|
|
8
|
+
*
|
|
9
|
+
* Used by:
|
|
10
|
+
* - Plan 06-04 `ReportStore.patchSynthesis` — validates telemetry before
|
|
11
|
+
* writing to Sanity (process memory → Sanity write boundary, T-06-04).
|
|
12
|
+
* - Any future Sanity-side reader of `summary.synthesis.diagnosis.*`
|
|
13
|
+
* (Sanity Content Lake → eval process boundary, T-06-04).
|
|
14
|
+
*
|
|
15
|
+
* Security constraints:
|
|
16
|
+
* - No `.passthrough()` — schema is closed to prevent PII leakage from
|
|
17
|
+
* card body text into the telemetry shape (T-06-05).
|
|
18
|
+
* - Satisfies clause is load-bearing (T-06-06); no exemption marker.
|
|
19
|
+
*
|
|
20
|
+
* @see packages/core/src/types/synthesis-telemetry.ts — independently authored domain types
|
|
21
|
+
* @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
|
|
22
|
+
* @see .planning/phases/06-post-run-integration-cost-telemetry/06-CONTEXT.md §D6-09
|
|
23
|
+
*/
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
/**
|
|
26
|
+
* Enum of all valid card types — mirrors `CardType` from diagnosis.ts.
|
|
27
|
+
* Using `z.enum()` (not `z.string()`) so the schema satisfies
|
|
28
|
+
* `z.ZodType<SynthesisPerCardTelemetry>` (which requires `cardType: CardType`).
|
|
29
|
+
*/
|
|
30
|
+
const CardTypeSchema = z.enum([
|
|
31
|
+
"area-summary",
|
|
32
|
+
"failure-mode-summary",
|
|
33
|
+
"no-issues",
|
|
34
|
+
"top-recommendations",
|
|
35
|
+
"weakest-area",
|
|
36
|
+
"low-confidence-attribution",
|
|
37
|
+
"doc-attribution-spotlight",
|
|
38
|
+
"regression-vs-baseline",
|
|
39
|
+
]);
|
|
40
|
+
const SynthesisPerCardSchema = z.object({
|
|
41
|
+
cardType: CardTypeSchema,
|
|
42
|
+
cost: z.number().nonnegative().optional(),
|
|
43
|
+
parseFailed: z.boolean(),
|
|
44
|
+
latencyMs: z.number().int().nonnegative().optional(),
|
|
45
|
+
tokenInput: z.number().int().nonnegative().optional(),
|
|
46
|
+
tokenOutput: z.number().int().nonnegative().optional(),
|
|
47
|
+
cardVersion: z.string(),
|
|
48
|
+
generatedAt: z.string().datetime({ offset: false }), // ISO 8601 UTC required
|
|
49
|
+
});
|
|
50
|
+
export const SynthesisCostTelemetrySchema = z.object({
|
|
51
|
+
cost: z.number().nonnegative(),
|
|
52
|
+
parseFailureCount: z.number().int().nonnegative(),
|
|
53
|
+
parseFailureRate: z.number().min(0).max(1),
|
|
54
|
+
perCard: z.array(SynthesisPerCardSchema),
|
|
55
|
+
});
|
|
@@ -286,16 +286,21 @@ function mapAssertions(raw) {
|
|
|
286
286
|
.map((c) => ({ id: c.id, text: c.text })),
|
|
287
287
|
template: a.template,
|
|
288
288
|
type: "llm-rubric",
|
|
289
|
-
|
|
289
|
+
// Use `!= null` (loose) so we drop both `undefined` AND `null`.
|
|
290
|
+
// GROQ projects missing scalar fields as `null`, but the domain
|
|
291
|
+
// schema's `z.number().optional()` accepts `T | undefined`, not
|
|
292
|
+
// `T | null` — a strict `!== undefined` check would forward
|
|
293
|
+
// `weight: null` and trigger Zod's "Invalid input" on assertions.
|
|
294
|
+
...(a.weight != null ? { weight: a.weight } : {}),
|
|
290
295
|
};
|
|
291
296
|
}
|
|
292
|
-
// Value-based assertion
|
|
297
|
+
// Value-based assertion — same null-vs-undefined hazard as above.
|
|
293
298
|
const result = { type: a.type };
|
|
294
|
-
if (a.value
|
|
299
|
+
if (a.value != null)
|
|
295
300
|
result.value = a.value;
|
|
296
|
-
if (a.threshold
|
|
301
|
+
if (a.threshold != null)
|
|
297
302
|
result.threshold = a.threshold;
|
|
298
|
-
if (a.weight
|
|
303
|
+
if (a.weight != null)
|
|
299
304
|
result.weight = a.weight;
|
|
300
305
|
return result;
|
|
301
306
|
});
|
|
@@ -1561,6 +1561,13 @@ export declare const RepoConfigSchema: z.ZodObject<{
|
|
|
1561
1561
|
dir: z.ZodOptional<z.ZodString>;
|
|
1562
1562
|
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1563
1563
|
}, z.core.$strip>>;
|
|
1564
|
+
summary: z.ZodOptional<z.ZodObject<{
|
|
1565
|
+
onRun: z.ZodOptional<z.ZodEnum<{
|
|
1566
|
+
never: "never";
|
|
1567
|
+
always: "always";
|
|
1568
|
+
auto: "auto";
|
|
1569
|
+
}>>;
|
|
1570
|
+
}, z.core.$strip>>;
|
|
1564
1571
|
taskSource: z.ZodOptional<z.ZodObject<{
|
|
1565
1572
|
type: z.ZodOptional<z.ZodEnum<{
|
|
1566
1573
|
"content-lake": "content-lake";
|
|
@@ -646,6 +646,15 @@ const OwnerConfigSchema = z
|
|
|
646
646
|
individual: z.string().min(1).optional(),
|
|
647
647
|
})
|
|
648
648
|
.optional();
|
|
649
|
+
/**
|
|
650
|
+
* Post-run diagnosis summary policy (Phase 6 / DIAG-06).
|
|
651
|
+
* Sits in the W0077 Phase-6a auto-load pathway.
|
|
652
|
+
*/
|
|
653
|
+
const SummaryConfigSchema = z
|
|
654
|
+
.object({
|
|
655
|
+
onRun: z.enum(["auto", "always", "never"]).optional(),
|
|
656
|
+
})
|
|
657
|
+
.optional();
|
|
649
658
|
/**
|
|
650
659
|
* Agentic-mode configuration (W0077 Phase 6f). Replaces the retired
|
|
651
660
|
* `--header` and `--allowed-origin` CLI flags. `headers` is a key/value
|
|
@@ -694,6 +703,7 @@ export const RepoConfigSchema = z.object({
|
|
|
694
703
|
owner: OwnerConfigSchema,
|
|
695
704
|
agentic: AgenticConfigSchema,
|
|
696
705
|
artifacts: ArtifactsConfigSchema,
|
|
706
|
+
summary: SummaryConfigSchema,
|
|
697
707
|
taskSource: TaskSourceConfigSchema,
|
|
698
708
|
triggers: z
|
|
699
709
|
.object({
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* @see docs/decisions/D0032-run-anchored-artifact-store.md
|
|
28
28
|
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md
|
|
29
29
|
*/
|
|
30
|
-
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type AssociationValues, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
30
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type AssociationValues, type RunId, type RunManifest, type WriteSource } from "../_vendor/ailf-core/index.d.ts";
|
|
31
31
|
import { type UploadMetricsSink } from "./upload-metrics.js";
|
|
32
32
|
export interface ApiGatewayArtifactWriterOptions {
|
|
33
33
|
/** Base URL of the API gateway (e.g., "https://ailf-api.sanity.build"). */
|
|
@@ -41,10 +41,20 @@ export interface ApiGatewayArtifactWriterOptions {
|
|
|
41
41
|
* Defaults to a no-op so the hot path stays free when metrics are off.
|
|
42
42
|
*/
|
|
43
43
|
metrics?: UploadMetricsSink;
|
|
44
|
+
/**
|
|
45
|
+
* Identifies what kind of execution context owns this writer instance.
|
|
46
|
+
* The D0050 guard refuses to emit a descriptor whose `writePolicy` is
|
|
47
|
+
* different from this value. `"pipeline"` (the default) is for writers
|
|
48
|
+
* driven by an `ailf run` pipeline; `"post-hoc"` is for writers driven
|
|
49
|
+
* by deferred commands like `ailf interpret` that emit descriptors
|
|
50
|
+
* declared `writePolicy: "post-hoc"` (D0050).
|
|
51
|
+
*/
|
|
52
|
+
writerSource?: WriteSource;
|
|
44
53
|
}
|
|
45
54
|
export declare class ApiGatewayArtifactWriter implements ArtifactWriter {
|
|
46
55
|
private readonly options;
|
|
47
56
|
private readonly metrics;
|
|
57
|
+
private readonly writerSource;
|
|
48
58
|
constructor(options: ApiGatewayArtifactWriterOptions);
|
|
49
59
|
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
50
60
|
appendNdjson(): Promise<ArtifactRef | null>;
|
|
@@ -33,14 +33,16 @@ import { NO_OP_UPLOAD_METRICS, } from "./upload-metrics.js";
|
|
|
33
33
|
export class ApiGatewayArtifactWriter {
|
|
34
34
|
options;
|
|
35
35
|
metrics;
|
|
36
|
+
writerSource;
|
|
36
37
|
constructor(options) {
|
|
37
38
|
this.options = options;
|
|
38
39
|
this.metrics = options.metrics ?? NO_OP_UPLOAD_METRICS;
|
|
40
|
+
this.writerSource = options.writerSource ?? "pipeline";
|
|
39
41
|
}
|
|
40
42
|
// ---- Canonical W0049 API ------------------------------------------------
|
|
41
43
|
async emit(type, association, payload) {
|
|
42
44
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
43
|
-
assertWritePolicyMatches(
|
|
45
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
44
46
|
const runId = association.run;
|
|
45
47
|
if (!runId) {
|
|
46
48
|
console.warn(` ⚠️ emit("${type}"): association.run is required, skipping`);
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* does this writer. Traces flow through the GCS-direct writer when ADC
|
|
26
26
|
* credentials are present.
|
|
27
27
|
*/
|
|
28
|
-
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type AssociationValues, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
28
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type AssociationValues, type RunId, type RunManifest, type WriteSource } from "../_vendor/ailf-core/index.d.ts";
|
|
29
29
|
import { type UploadMetricsSink } from "./upload-metrics.js";
|
|
30
30
|
export interface BatchingApiGatewayArtifactWriterOptions {
|
|
31
31
|
/** Base URL of the API gateway (e.g., "https://ailf-api.sanity.build"). */
|
|
@@ -46,12 +46,22 @@ export interface BatchingApiGatewayArtifactWriterOptions {
|
|
|
46
46
|
putConcurrency?: number;
|
|
47
47
|
/** Optional metrics sink; defaults to no-op. */
|
|
48
48
|
metrics?: UploadMetricsSink;
|
|
49
|
+
/**
|
|
50
|
+
* Identifies what kind of execution context owns this writer instance.
|
|
51
|
+
* The D0050 guard refuses to emit a descriptor whose `writePolicy` is
|
|
52
|
+
* different from this value. `"pipeline"` (the default) is for writers
|
|
53
|
+
* driven by an `ailf run` pipeline; `"post-hoc"` is for writers driven
|
|
54
|
+
* by deferred commands like `ailf interpret` that emit descriptors
|
|
55
|
+
* declared `writePolicy: "post-hoc"` (D0050).
|
|
56
|
+
*/
|
|
57
|
+
writerSource?: WriteSource;
|
|
49
58
|
}
|
|
50
59
|
export declare class BatchingApiGatewayArtifactWriter implements ArtifactWriter {
|
|
51
60
|
private readonly options;
|
|
52
61
|
private readonly pending;
|
|
53
62
|
private flushing;
|
|
54
63
|
private microtaskScheduled;
|
|
64
|
+
private readonly writerSource;
|
|
55
65
|
constructor(options: BatchingApiGatewayArtifactWriterOptions);
|
|
56
66
|
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
57
67
|
appendNdjson(): Promise<ArtifactRef | null>;
|
|
@@ -51,6 +51,7 @@ export class BatchingApiGatewayArtifactWriter {
|
|
|
51
51
|
pending = [];
|
|
52
52
|
flushing = null;
|
|
53
53
|
microtaskScheduled = false;
|
|
54
|
+
writerSource;
|
|
54
55
|
constructor(options) {
|
|
55
56
|
this.options = {
|
|
56
57
|
apiBaseUrl: options.apiBaseUrl,
|
|
@@ -60,11 +61,12 @@ export class BatchingApiGatewayArtifactWriter {
|
|
|
60
61
|
putConcurrency: options.putConcurrency ?? DEFAULT_PUT_CONCURRENCY,
|
|
61
62
|
metrics: options.metrics ?? NO_OP_UPLOAD_METRICS,
|
|
62
63
|
};
|
|
64
|
+
this.writerSource = options.writerSource ?? "pipeline";
|
|
63
65
|
}
|
|
64
66
|
// ---- ArtifactWriter surface --------------------------------------------
|
|
65
67
|
async emit(type, association, payload) {
|
|
66
68
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
67
|
-
assertWritePolicyMatches(
|
|
69
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
68
70
|
const runId = association.run;
|
|
69
71
|
if (!runId) {
|
|
70
72
|
console.warn(` ⚠️ emit("${type}"): association.run is required, skipping`);
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md
|
|
29
29
|
*/
|
|
30
30
|
import { Storage } from "@google-cloud/storage";
|
|
31
|
-
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type ArtifactWriterProgressOptions, type AssociationValues, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
31
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type ArtifactWriterProgressOptions, type AssociationValues, type RunId, type RunManifest, type WriteSource } from "../_vendor/ailf-core/index.d.ts";
|
|
32
32
|
import { type UploadMetricsSink } from "./upload-metrics.js";
|
|
33
33
|
export interface GcsArtifactWriterOptions {
|
|
34
34
|
/** GCS bucket name (e.g., "ailf-artifacts") */
|
|
@@ -51,6 +51,15 @@ export interface GcsArtifactWriterOptions {
|
|
|
51
51
|
* Defaults to a no-op so the hot path stays free when metrics are off.
|
|
52
52
|
*/
|
|
53
53
|
metrics?: UploadMetricsSink;
|
|
54
|
+
/**
|
|
55
|
+
* Identifies what kind of execution context owns this writer instance.
|
|
56
|
+
* The D0050 guard refuses to emit a descriptor whose `writePolicy` is
|
|
57
|
+
* different from this value. `"pipeline"` (the default) is for writers
|
|
58
|
+
* driven by an `ailf run` pipeline; `"post-hoc"` is for writers driven
|
|
59
|
+
* by deferred commands like `ailf interpret` that emit descriptors
|
|
60
|
+
* declared `writePolicy: "post-hoc"` (D0050).
|
|
61
|
+
*/
|
|
62
|
+
writerSource?: WriteSource;
|
|
54
63
|
}
|
|
55
64
|
export declare class GcsArtifactWriter implements ArtifactWriter {
|
|
56
65
|
private client;
|
|
@@ -68,6 +77,7 @@ export declare class GcsArtifactWriter implements ArtifactWriter {
|
|
|
68
77
|
* measured safe, without forcing the producer to own that knob.
|
|
69
78
|
*/
|
|
70
79
|
private readonly limiter;
|
|
80
|
+
private readonly writerSource;
|
|
71
81
|
constructor(options: GcsArtifactWriterOptions);
|
|
72
82
|
private reportProgress;
|
|
73
83
|
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
@@ -57,9 +57,11 @@ export class GcsArtifactWriter {
|
|
|
57
57
|
* measured safe, without forcing the producer to own that knob.
|
|
58
58
|
*/
|
|
59
59
|
limiter;
|
|
60
|
+
writerSource;
|
|
60
61
|
constructor(options) {
|
|
61
62
|
this.options = options;
|
|
62
63
|
this.metrics = options.metrics ?? NO_OP_UPLOAD_METRICS;
|
|
64
|
+
this.writerSource = options.writerSource ?? "pipeline";
|
|
63
65
|
if (options.storage) {
|
|
64
66
|
this.client = options.storage;
|
|
65
67
|
}
|
|
@@ -79,7 +81,7 @@ export class GcsArtifactWriter {
|
|
|
79
81
|
// ---- Canonical W0049 API ------------------------------------------------
|
|
80
82
|
async emit(type, association, payload) {
|
|
81
83
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
82
|
-
assertWritePolicyMatches(
|
|
84
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
83
85
|
const runId = association.run;
|
|
84
86
|
if (!runId) {
|
|
85
87
|
console.warn(` ⚠️ emit("${type}"): association.run is required, skipping`);
|
|
@@ -92,7 +94,8 @@ export class GcsArtifactWriter {
|
|
|
92
94
|
const { body } = prepareUploadBody(payload, descriptor.mime);
|
|
93
95
|
const preview = buildManifestPreview(descriptor, payload);
|
|
94
96
|
if (descriptor.layout === "bulk") {
|
|
95
|
-
const
|
|
97
|
+
const extra = descriptor.extractPathArgs?.(association, payload) ?? [];
|
|
98
|
+
const path = descriptor.objectPath(runId, ...extra);
|
|
96
99
|
const ref = await this.putBody(path, body, {
|
|
97
100
|
layout: "bulk",
|
|
98
101
|
mime: descriptor.mime,
|
|
@@ -133,7 +136,7 @@ export class GcsArtifactWriter {
|
|
|
133
136
|
}
|
|
134
137
|
async appendNdjson(type, association, rows) {
|
|
135
138
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
136
|
-
assertWritePolicyMatches(
|
|
139
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
137
140
|
if (descriptor.mime !== "application/x-ndjson") {
|
|
138
141
|
console.warn(` ⚠️ appendNdjson("${type}"): descriptor mime is ${descriptor.mime}, not application/x-ndjson — skipping`);
|
|
139
142
|
return null;
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* @see docs/decisions/D0033-unified-run-anchored-artifact-capture.md (§ M4)
|
|
37
37
|
* @see packages/eval/src/artifact-capture/gcs-artifact-writer.ts (mirror)
|
|
38
38
|
*/
|
|
39
|
-
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type ArtifactWriterProgressOptions, type AssociationValues, type RunId, type RunManifest } from "../_vendor/ailf-core/index.d.ts";
|
|
39
|
+
import { type ArtifactEntry, type ArtifactRef, type ArtifactType, type ArtifactWriter, type ArtifactWriterProgressOptions, type AssociationValues, type RunId, type RunManifest, type WriteSource } from "../_vendor/ailf-core/index.d.ts";
|
|
40
40
|
export interface LocalFilesystemArtifactWriterOptions {
|
|
41
41
|
/**
|
|
42
42
|
* Absolute or cwd-relative root directory under which `runs/{runId}/…`
|
|
@@ -56,10 +56,20 @@ export interface LocalFilesystemArtifactWriterOptions {
|
|
|
56
56
|
* render per-batch updates during long export phases.
|
|
57
57
|
*/
|
|
58
58
|
progress?: ArtifactWriterProgressOptions;
|
|
59
|
+
/**
|
|
60
|
+
* Identifies what kind of execution context owns this writer instance.
|
|
61
|
+
* The D0050 guard refuses to emit a descriptor whose `writePolicy` is
|
|
62
|
+
* different from this value. `"pipeline"` (the default) is for writers
|
|
63
|
+
* driven by an `ailf run` pipeline; `"post-hoc"` is for writers driven
|
|
64
|
+
* by deferred commands like `ailf interpret` that emit descriptors
|
|
65
|
+
* declared `writePolicy: "post-hoc"` (D0050).
|
|
66
|
+
*/
|
|
67
|
+
writerSource?: WriteSource;
|
|
59
68
|
}
|
|
60
69
|
export declare class LocalFilesystemArtifactWriter implements ArtifactWriter {
|
|
61
70
|
private readonly options;
|
|
62
71
|
private readonly excludeSet;
|
|
72
|
+
private readonly writerSource;
|
|
63
73
|
constructor(options: LocalFilesystemArtifactWriterOptions);
|
|
64
74
|
private reportProgress;
|
|
65
75
|
emit<T extends ArtifactType>(type: T, association: AssociationValues, payload: unknown): Promise<ArtifactRef | null>;
|
|
@@ -46,9 +46,11 @@ import { redactArtifactData } from "./redact-artifact.js";
|
|
|
46
46
|
export class LocalFilesystemArtifactWriter {
|
|
47
47
|
options;
|
|
48
48
|
excludeSet;
|
|
49
|
+
writerSource;
|
|
49
50
|
constructor(options) {
|
|
50
51
|
this.options = options;
|
|
51
52
|
this.excludeSet = new Set(options.exclude ?? []);
|
|
53
|
+
this.writerSource = options.writerSource ?? "pipeline";
|
|
52
54
|
}
|
|
53
55
|
reportProgress(ref) {
|
|
54
56
|
const progress = this.options.progress;
|
|
@@ -66,7 +68,7 @@ export class LocalFilesystemArtifactWriter {
|
|
|
66
68
|
if (this.excludeSet.has(type))
|
|
67
69
|
return null;
|
|
68
70
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
69
|
-
assertWritePolicyMatches(
|
|
71
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
70
72
|
const runId = association.run;
|
|
71
73
|
if (!runId) {
|
|
72
74
|
console.warn(` ⚠️ emit("${type}"): association.run is required, skipping`);
|
|
@@ -81,7 +83,8 @@ export class LocalFilesystemArtifactWriter {
|
|
|
81
83
|
// descriptor's capBytes.
|
|
82
84
|
const preview = buildManifestPreview(descriptor, payload);
|
|
83
85
|
if (descriptor.layout === "bulk") {
|
|
84
|
-
const
|
|
86
|
+
const extra = descriptor.extractPathArgs?.(association, payload) ?? [];
|
|
87
|
+
const relPath = descriptor.objectPath(runId, ...extra);
|
|
85
88
|
const absPath = this.resolve(relPath);
|
|
86
89
|
const wrote = await this.writeAtomic(absPath, body);
|
|
87
90
|
if (!wrote)
|
|
@@ -128,7 +131,7 @@ export class LocalFilesystemArtifactWriter {
|
|
|
128
131
|
if (this.excludeSet.has(type))
|
|
129
132
|
return null;
|
|
130
133
|
const descriptor = ARTIFACT_REGISTRY[type];
|
|
131
|
-
assertWritePolicyMatches(
|
|
134
|
+
assertWritePolicyMatches(this.writerSource, descriptor);
|
|
132
135
|
if (descriptor.mime !== "application/x-ndjson") {
|
|
133
136
|
console.warn(` ⚠️ appendNdjson("${type}"): descriptor mime is ${descriptor.mime}, not application/x-ndjson — skipping`);
|
|
134
137
|
return null;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @see .planning/phases/05-diagnosis-engine-cli-llm-cards/05-AI-SPEC.md §6
|
|
17
17
|
*/
|
|
18
18
|
import { Command } from "commander";
|
|
19
|
-
import type
|
|
19
|
+
import { type DiagnosisCard, type DiagnosisRunner, type VersionedInputs } from "../_vendor/ailf-core/index.d.ts";
|
|
20
20
|
interface MinimalReportStore {
|
|
21
21
|
read(id: string): Promise<unknown | null>;
|
|
22
22
|
latest(): Promise<unknown | null>;
|
|
@@ -39,6 +39,26 @@ export interface InterpretCommandOptions {
|
|
|
39
39
|
*/
|
|
40
40
|
readonly versionsFromReport?: (report: unknown) => VersionedInputs;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Visual status markers — locked visual contract per plan Test 7:
|
|
44
|
+
* ready: "✓", degraded: "⚠", missing: "—"
|
|
45
|
+
*
|
|
46
|
+
* Exported so Plan 06-04's post-run hook imports the SAME object and
|
|
47
|
+
* D6-04's "single formatter, single visual contract" is physically
|
|
48
|
+
* enforced — no copy/paste drift possible.
|
|
49
|
+
*/
|
|
50
|
+
export declare const STATUS_ICONS: Record<DiagnosisCard["status"], string>;
|
|
51
|
+
/**
|
|
52
|
+
* Format a single card as a one-line summary string.
|
|
53
|
+
*
|
|
54
|
+
* Format: `<icon> <cardType>: <summary>`
|
|
55
|
+
* Per AI-SPEC §6: distinct icons for ready / degraded / missing.
|
|
56
|
+
*
|
|
57
|
+
* Exported so Plan 06-04's post-run hook imports the SAME function and
|
|
58
|
+
* D6-04's "single formatter, single visual contract" is physically
|
|
59
|
+
* enforced — no copy/paste drift possible.
|
|
60
|
+
*/
|
|
61
|
+
export declare function formatCardSummaryLine(card: DiagnosisCard): string;
|
|
42
62
|
/**
|
|
43
63
|
* Create the `ailf interpret <reportId>` Commander command.
|
|
44
64
|
*
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { dirname, resolve } from "path";
|
|
19
19
|
import { fileURLToPath } from "url";
|
|
20
20
|
import { Command } from "commander";
|
|
21
|
+
import { CARD_REGISTRY_VERSION, diagnosisVersion, } from "../_vendor/ailf-core/index.js";
|
|
21
22
|
import { addOutputDirOption } from "./shared/options.js";
|
|
22
23
|
import { resolveOutputDir } from "./shared/resolve-output-dir.js";
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
@@ -31,8 +32,12 @@ const ROOT = resolve(__dirname, "..", "..");
|
|
|
31
32
|
/**
|
|
32
33
|
* Visual status markers — locked visual contract per plan Test 7:
|
|
33
34
|
* ready: "✓", degraded: "⚠", missing: "—"
|
|
35
|
+
*
|
|
36
|
+
* Exported so Plan 06-04's post-run hook imports the SAME object and
|
|
37
|
+
* D6-04's "single formatter, single visual contract" is physically
|
|
38
|
+
* enforced — no copy/paste drift possible.
|
|
34
39
|
*/
|
|
35
|
-
const STATUS_ICONS = {
|
|
40
|
+
export const STATUS_ICONS = {
|
|
36
41
|
ready: "✓",
|
|
37
42
|
degraded: "⚠",
|
|
38
43
|
missing: "—",
|
|
@@ -52,8 +57,12 @@ function getCardSummaryText(card) {
|
|
|
52
57
|
*
|
|
53
58
|
* Format: `<icon> <cardType>: <summary>`
|
|
54
59
|
* Per AI-SPEC §6: distinct icons for ready / degraded / missing.
|
|
60
|
+
*
|
|
61
|
+
* Exported so Plan 06-04's post-run hook imports the SAME function and
|
|
62
|
+
* D6-04's "single formatter, single visual contract" is physically
|
|
63
|
+
* enforced — no copy/paste drift possible.
|
|
55
64
|
*/
|
|
56
|
-
function formatCardSummaryLine(card) {
|
|
65
|
+
export function formatCardSummaryLine(card) {
|
|
57
66
|
const icon = STATUS_ICONS[card.status];
|
|
58
67
|
const text = getCardSummaryText(card);
|
|
59
68
|
return `${icon} ${card.cardType}: ${text}`;
|
|
@@ -82,10 +91,10 @@ function defaultVersionsFromReport(report) {
|
|
|
82
91
|
: "unknown",
|
|
83
92
|
diagnosisVersion: typeof versions?.diagnosisVersion === "string"
|
|
84
93
|
? versions.diagnosisVersion
|
|
85
|
-
:
|
|
94
|
+
: diagnosisVersion,
|
|
86
95
|
cardVersion: typeof versions?.cardVersion === "string"
|
|
87
96
|
? versions.cardVersion
|
|
88
|
-
:
|
|
97
|
+
: CARD_REGISTRY_VERSION,
|
|
89
98
|
};
|
|
90
99
|
}
|
|
91
100
|
// ---------------------------------------------------------------------------
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { type ImpactSummary } from "../pipeline/reverse-mapping.js";
|
|
14
14
|
import type { DebugOptions, EvalMode } from "../pipeline/types.js";
|
|
15
|
+
import { type Diagnosis, type ReportStorePort, type SynthesisCostTelemetry } from "../_vendor/ailf-core/index.d.ts";
|
|
15
16
|
import type { PipelineCliOptions } from "./run.js";
|
|
16
17
|
export interface ResolvedOptions {
|
|
17
18
|
allowedOriginArgs: string[];
|
|
@@ -63,6 +64,12 @@ export interface ResolvedOptions {
|
|
|
63
64
|
studioOriginOverride?: string;
|
|
64
65
|
remote: boolean;
|
|
65
66
|
repoTasksPath?: string;
|
|
67
|
+
/** Phase 6 / DIAG-06: post-run diagnosis summary policy. Precedence
|
|
68
|
+
* resolution (CLI flag > env > config > auto) lives in
|
|
69
|
+
* shouldRunPostSummary() — this field carries only the config-file
|
|
70
|
+
* signal so the helper has a single typed input.
|
|
71
|
+
*/
|
|
72
|
+
summaryOnRun?: "auto" | "always" | "never";
|
|
66
73
|
taskOption?: string;
|
|
67
74
|
tagOption?: string[];
|
|
68
75
|
taskSourceType?: "content-lake" | "repo";
|
|
@@ -88,6 +95,43 @@ export interface ResolvedOptions {
|
|
|
88
95
|
* Exported so the plan builder can call it independently.
|
|
89
96
|
*/
|
|
90
97
|
export declare function computeResolvedOptions(opts: PipelineCliOptions): ResolvedOptions;
|
|
98
|
+
/**
|
|
99
|
+
* Determine whether the post-run diagnosis summary hook should fire.
|
|
100
|
+
*
|
|
101
|
+
* 4-level precedence chain (D6-20):
|
|
102
|
+
* Level 1 — CLI flag (absolute): if `cliOpts.summary` is boolean, use it.
|
|
103
|
+
* Level 2 — AILF_INTERPRET_ON_RUN env var (absolute): strict "1"/"0" parse;
|
|
104
|
+
* anything else falls through (T-06-11 spoofing mitigation).
|
|
105
|
+
* Level 3 — config `summary.onRun` (absolute): "always" → true; "never" → false;
|
|
106
|
+
* "auto" or absent falls through to level 4.
|
|
107
|
+
* Level 4 — default auto: TTY && !CI (SC1 default-off in CI).
|
|
108
|
+
*/
|
|
109
|
+
export declare function shouldRunPostSummary(cliOpts: PipelineCliOptions, resolvedOnRun: "auto" | "always" | "never" | undefined): boolean;
|
|
110
|
+
export declare function buildSynthesisTelemetry(diagnosis: Diagnosis): SynthesisCostTelemetry;
|
|
111
|
+
/**
|
|
112
|
+
* Run post-pipeline hooks after the pipeline completes.
|
|
113
|
+
*
|
|
114
|
+
* Fires after orchestratePipeline() + writePipelineResult() (D6-02).
|
|
115
|
+
* Hook failure prints to stderr but does NOT change exit code (D6-03).
|
|
116
|
+
* CI default-off: fires only when shouldRunPostSummary returns true (D6-20).
|
|
117
|
+
*
|
|
118
|
+
* @param ctx - App context (composition root wiring)
|
|
119
|
+
* @param result - Pipeline result (includes reportId when published)
|
|
120
|
+
* @param args - Hook options (cliOpts, summaryOnRun from config, optional runnerFactory for tests)
|
|
121
|
+
*/
|
|
122
|
+
export declare function runPostPipelineHooks(ctx: {
|
|
123
|
+
reportStore?: ReportStorePort;
|
|
124
|
+
}, result: {
|
|
125
|
+
success: boolean;
|
|
126
|
+
reportId?: string;
|
|
127
|
+
}, args: {
|
|
128
|
+
cliOpts: PipelineCliOptions;
|
|
129
|
+
summaryOnRun?: "auto" | "always" | "never";
|
|
130
|
+
/** Override runner factory for tests — avoids vi.mock of composition root */
|
|
131
|
+
runnerFactory?: (ctx: unknown) => {
|
|
132
|
+
run(opts: unknown): Promise<Diagnosis>;
|
|
133
|
+
};
|
|
134
|
+
}): Promise<void>;
|
|
91
135
|
/**
|
|
92
136
|
* Execute the evaluation pipeline.
|
|
93
137
|
*
|