@sanity/ailf 4.1.0 → 4.3.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/config/package-surface.ts +37 -0
- package/config/preflight-scoring.ts +26 -0
- package/dist/_vendor/ailf-core/artifact-registry.d.ts +1 -1
- package/dist/_vendor/ailf-core/artifact-registry.js +47 -0
- package/dist/_vendor/ailf-core/config-helpers.d.ts +35 -0
- package/dist/_vendor/ailf-core/config-helpers.js +67 -0
- package/dist/_vendor/ailf-core/index.d.ts +1 -1
- package/dist/_vendor/ailf-core/index.js +1 -1
- package/dist/_vendor/ailf-core/ports/context.d.ts +18 -0
- package/dist/_vendor/ailf-core/ports/doc-fetcher.d.ts +30 -0
- package/dist/_vendor/ailf-core/ports/index.d.ts +3 -1
- package/dist/_vendor/ailf-core/ports/index.js +1 -0
- package/dist/_vendor/ailf-core/ports/mode-handler.d.ts +23 -0
- package/dist/_vendor/ailf-core/ports/package-surface-resolver.d.ts +71 -0
- package/dist/_vendor/ailf-core/ports/package-surface-resolver.js +36 -0
- package/dist/_vendor/ailf-core/schemas/eval-config.d.ts +6 -0
- package/dist/_vendor/ailf-core/schemas/eval-config.js +14 -0
- package/dist/_vendor/ailf-core/schemas/index.d.ts +1 -0
- package/dist/_vendor/ailf-core/schemas/index.js +1 -0
- package/dist/_vendor/ailf-core/schemas/symbol-preflight-report.d.ts +51 -0
- package/dist/_vendor/ailf-core/schemas/symbol-preflight-report.js +57 -0
- package/dist/_vendor/ailf-core/types/generalized-task.d.ts +20 -3
- package/dist/_vendor/ailf-core/types/index.d.ts +13 -1
- package/dist/_vendor/ailf-core/types/index.js +1 -0
- package/dist/_vendor/ailf-core/types/package-surface.d.ts +36 -0
- package/dist/_vendor/ailf-core/types/package-surface.js +13 -0
- package/dist/_vendor/ailf-core/types/preflight-scoring.d.ts +52 -0
- package/dist/_vendor/ailf-core/types/preflight-scoring.js +18 -0
- package/dist/_vendor/ailf-core/types/repo-config.d.ts +14 -0
- package/dist/_vendor/ailf-core/types/symbol-preflight-report.d.ts +66 -0
- package/dist/_vendor/ailf-core/types/symbol-preflight-report.js +25 -0
- package/dist/adapters/config-sources/file-config-adapter.js +1 -0
- package/dist/adapters/doc-fetchers/sanity-doc-fetcher.d.ts +25 -5
- package/dist/adapters/doc-fetchers/sanity-doc-fetcher.js +276 -95
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/package-surface/dts-package-surface.d.ts +46 -0
- package/dist/adapters/package-surface/dts-package-surface.js +173 -0
- package/dist/adapters/package-surface/in-memory-package-surface.d.ts +15 -0
- package/dist/adapters/package-surface/in-memory-package-surface.js +28 -0
- package/dist/adapters/package-surface/index.d.ts +9 -0
- package/dist/adapters/package-surface/index.js +8 -0
- package/dist/adapters/package-surface/parse-dts-exports.d.ts +31 -0
- package/dist/adapters/package-surface/parse-dts-exports.js +54 -0
- package/dist/adapters/task-sources/repo-schemas.d.ts +22 -0
- package/dist/adapters/task-sources/repo-schemas.js +93 -1
- package/dist/adapters/task-sources/repo-task-source.js +11 -2
- package/dist/commands/pipeline-action.d.ts +2 -0
- package/dist/commands/pipeline-action.js +12 -0
- package/dist/commands/remote-pipeline.js +9 -2
- package/dist/commands/remote-results.d.ts +12 -1
- package/dist/commands/remote-results.js +25 -5
- package/dist/commands/validate-tasks.js +8 -2
- package/dist/composition-root.js +9 -0
- package/dist/config/package-surface.ts +37 -0
- package/dist/config/preflight-scoring.ts +26 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/orchestration/build-app-context.js +1 -0
- package/dist/orchestration/pipeline-orchestrator.d.ts +19 -1
- package/dist/orchestration/pipeline-orchestrator.js +38 -0
- package/dist/orchestration/steps/calculate-scores-step.js +11 -0
- package/dist/orchestration/steps/generate-configs-step.js +16 -1
- package/dist/orchestration/steps/run-eval-step.js +27 -0
- package/dist/pipeline/calculate-scores.d.ts +66 -5
- package/dist/pipeline/calculate-scores.js +141 -27
- package/dist/pipeline/compiler/index.d.ts +1 -1
- package/dist/pipeline/compiler/index.js +1 -1
- package/dist/pipeline/compiler/literacy-bridge.d.ts +9 -0
- package/dist/pipeline/compiler/literacy-bridge.js +2 -0
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/agent-harness-example-tasks.js +0 -12
- package/dist/pipeline/compiler/mode-handlers/__fixtures__/knowledge-probe-example-tasks.js +0 -12
- package/dist/pipeline/compiler/mode-handlers/literacy/assertions.d.ts +1 -1
- package/dist/pipeline/compiler/mode-handlers/literacy/assertions.js +31 -4
- package/dist/pipeline/compiler/mode-handlers/literacy/compiler.js +190 -6
- package/dist/pipeline/compiler/mode-handlers/literacy/index.js +2 -0
- package/dist/pipeline/compiler/mode-handlers/literacy/types.d.ts +17 -2
- package/dist/pipeline/compiler/rubric-resolution.d.ts +17 -1
- package/dist/pipeline/compiler/rubric-resolution.js +78 -2
- package/dist/pipeline/compiler/scoring-bridge.d.ts +49 -2
- package/dist/pipeline/compiler/scoring-bridge.js +104 -10
- package/dist/pipeline/eval-fingerprint.d.ts +9 -0
- package/dist/pipeline/eval-fingerprint.js +7 -1
- package/dist/pipeline/preflight/compute-preflight.d.ts +67 -0
- package/dist/pipeline/preflight/compute-preflight.js +118 -0
- package/dist/pipeline/preflight/emit-symbol-preflight.d.ts +51 -0
- package/dist/pipeline/preflight/emit-symbol-preflight.js +102 -0
- package/dist/pipeline/preflight/load-package-surface.d.ts +14 -0
- package/dist/pipeline/preflight/load-package-surface.js +19 -0
- package/dist/pipeline/preflight/load-preflight-context.d.ts +13 -0
- package/dist/pipeline/preflight/load-preflight-context.js +25 -0
- package/dist/pipeline/preflight/load-preflight-scoring.d.ts +12 -0
- package/dist/pipeline/preflight/load-preflight-scoring.js +17 -0
- package/dist/pipeline/preflight/parse-imports.d.ts +62 -0
- package/dist/pipeline/preflight/parse-imports.js +125 -0
- package/dist/report-store.d.ts +8 -0
- package/dist/report-store.js +55 -6
- package/dist/sanity/document-renderers.d.ts +106 -0
- package/dist/sanity/document-renderers.js +307 -0
- package/dist/sanity/queries.d.ts +32 -11
- package/dist/sanity/queries.js +78 -0
- package/dist/sanity/symbol-index.d.ts +98 -0
- package/dist/sanity/symbol-index.js +615 -0
- package/dist/tasks/knowledge-probe/define-type-api.task.ts +2 -6
- package/dist/tasks/knowledge-probe/groq-projections.task.ts +0 -5
- package/dist/tasks/literacy/content-lake.task.ts +4 -10
- package/dist/tasks/literacy/frameworks.task.ts +2 -8
- package/dist/tasks/literacy/functions.task.ts +1 -4
- package/dist/tasks/literacy/groq.task.ts +3 -12
- package/dist/tasks/literacy/image-handling.task.ts +1 -4
- package/dist/tasks/literacy/nextjs-live.task.ts +1 -4
- package/dist/tasks/literacy/portable-text.task.ts +2 -8
- package/dist/tasks/literacy/studio-setup.task.ts +2 -8
- package/dist/tasks/literacy/visual-editing.task.ts +2 -8
- package/package.json +2 -1
- package/tasks/knowledge-probe/define-type-api.task.ts +2 -6
- package/tasks/knowledge-probe/groq-projections.task.ts +0 -5
- package/tasks/literacy/content-lake.task.ts +4 -10
- package/tasks/literacy/frameworks.task.ts +2 -8
- package/tasks/literacy/functions.task.ts +1 -4
- package/tasks/literacy/groq.task.ts +3 -12
- package/tasks/literacy/image-handling.task.ts +1 -4
- package/tasks/literacy/nextjs-live.task.ts +1 -4
- package/tasks/literacy/portable-text.task.ts +2 -8
- package/tasks/literacy/studio-setup.task.ts +2 -8
- package/tasks/literacy/visual-editing.task.ts +2 -8
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* load-preflight-scoring — read the W0198 preflight scoring config
|
|
3
|
+
* (`config/preflight-scoring.ts`) authored via `definePreflightScoring()`.
|
|
4
|
+
*
|
|
5
|
+
* Returns `undefined` when the file is absent so callers fall back to
|
|
6
|
+
* `DEFAULT_PREFLIGHT_CODE_CORRECTNESS_WEIGHT`. The eval package itself
|
|
7
|
+
* ships a config so the live pipeline always finds one; the optional
|
|
8
|
+
* return path exists for downstream / external callers that may not
|
|
9
|
+
* have authored one yet.
|
|
10
|
+
*/
|
|
11
|
+
import { tryLoadConfigFile } from "../compiler/config-loader.js";
|
|
12
|
+
export async function loadPreflightScoring(rootDir) {
|
|
13
|
+
const result = tryLoadConfigFile("preflight-scoring", rootDir);
|
|
14
|
+
if (!result)
|
|
15
|
+
return undefined;
|
|
16
|
+
return result.data;
|
|
17
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parse-imports — pure function that extracts every `import` declaration
|
|
3
|
+
* from a candidate code block as a flat list of per-binding entries.
|
|
4
|
+
*
|
|
5
|
+
* Output shape is intentionally flat: the W0198 preflight checks each
|
|
6
|
+
* `(source, imported)` pair against the resolved package surface, so a
|
|
7
|
+
* flat list is the natural input. Multi-binding declarations
|
|
8
|
+
* (`import { a, b as c } from "pkg"`) produce one entry per binding;
|
|
9
|
+
* default + named combos (`import def, { a } from "pkg"`) likewise.
|
|
10
|
+
*
|
|
11
|
+
* Implementation: delegates to `oxc-parser`'s `staticImports` view, which
|
|
12
|
+
* already decomposes each import statement into entries with explicit
|
|
13
|
+
* `importName` / `localName` / `isType` fields. The TS-aware grammar
|
|
14
|
+
* means dynamic `import(...)`, `import.meta`, and malformed statements
|
|
15
|
+
* are all handled by the parser itself — we just translate the entries
|
|
16
|
+
* into our `CandidateImportBinding` shape.
|
|
17
|
+
*
|
|
18
|
+
* Recognized grammar (handled by oxc-parser):
|
|
19
|
+
* - `import { a, b as c } from "pkg"`
|
|
20
|
+
* - `import def from "pkg"`
|
|
21
|
+
* - `import * as ns from "pkg"`
|
|
22
|
+
* - `import def, { a } from "pkg"` and `import def, * as ns from "pkg"`
|
|
23
|
+
* - `import type { ... } from "pkg"` and `import { type a, b } from "pkg"`
|
|
24
|
+
* - `import "pkg"` (side-effect; surfaced as a single `side-effect` entry)
|
|
25
|
+
* - Multi-line variants of all of the above.
|
|
26
|
+
*
|
|
27
|
+
* Out of scope (intentionally — both regex and oxc-parser ignore these):
|
|
28
|
+
* - Dynamic `import("pkg")` — runtime, not statically resolvable here.
|
|
29
|
+
* - `export { a } from "pkg"` re-exports from candidate code.
|
|
30
|
+
* - TypeScript `import = require()` and `import("...").Type` ambient
|
|
31
|
+
* references — neither pattern shows up in the App SDK / Studio
|
|
32
|
+
* candidate corpus the preflight grades against.
|
|
33
|
+
*/
|
|
34
|
+
export type CandidateImportKind = "named" | "default" | "namespace" | "side-effect";
|
|
35
|
+
export interface CandidateImportBinding {
|
|
36
|
+
/** Source specifier as written by the candidate (e.g. `"@sanity/sdk-react"`). */
|
|
37
|
+
source: string;
|
|
38
|
+
/** Which import-clause shape this binding came from. */
|
|
39
|
+
kind: CandidateImportKind;
|
|
40
|
+
/**
|
|
41
|
+
* Name to look up against the package surface:
|
|
42
|
+
* - `kind: "named"` — the imported identifier.
|
|
43
|
+
* - `kind: "default"` — the literal string `"default"`.
|
|
44
|
+
* - `kind: "namespace"` — the literal string `"*"`.
|
|
45
|
+
* - `kind: "side-effect"` — empty string (no binding).
|
|
46
|
+
*/
|
|
47
|
+
imported: string;
|
|
48
|
+
/** Local alias used in the candidate's body. Same as `imported` when no alias. */
|
|
49
|
+
local: string;
|
|
50
|
+
/**
|
|
51
|
+
* Whether this binding is type-only — either the whole declaration was
|
|
52
|
+
* `import type`, or this specifier was prefixed with `type`
|
|
53
|
+
* (`import { type X, Y } from "pkg"`).
|
|
54
|
+
*/
|
|
55
|
+
isType: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* 1-based line number where the import declaration starts in the
|
|
58
|
+
* source. Useful for surfacing findings back to a reviewer.
|
|
59
|
+
*/
|
|
60
|
+
line: number;
|
|
61
|
+
}
|
|
62
|
+
export declare function parseImports(src: string): CandidateImportBinding[];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parse-imports — pure function that extracts every `import` declaration
|
|
3
|
+
* from a candidate code block as a flat list of per-binding entries.
|
|
4
|
+
*
|
|
5
|
+
* Output shape is intentionally flat: the W0198 preflight checks each
|
|
6
|
+
* `(source, imported)` pair against the resolved package surface, so a
|
|
7
|
+
* flat list is the natural input. Multi-binding declarations
|
|
8
|
+
* (`import { a, b as c } from "pkg"`) produce one entry per binding;
|
|
9
|
+
* default + named combos (`import def, { a } from "pkg"`) likewise.
|
|
10
|
+
*
|
|
11
|
+
* Implementation: delegates to `oxc-parser`'s `staticImports` view, which
|
|
12
|
+
* already decomposes each import statement into entries with explicit
|
|
13
|
+
* `importName` / `localName` / `isType` fields. The TS-aware grammar
|
|
14
|
+
* means dynamic `import(...)`, `import.meta`, and malformed statements
|
|
15
|
+
* are all handled by the parser itself — we just translate the entries
|
|
16
|
+
* into our `CandidateImportBinding` shape.
|
|
17
|
+
*
|
|
18
|
+
* Recognized grammar (handled by oxc-parser):
|
|
19
|
+
* - `import { a, b as c } from "pkg"`
|
|
20
|
+
* - `import def from "pkg"`
|
|
21
|
+
* - `import * as ns from "pkg"`
|
|
22
|
+
* - `import def, { a } from "pkg"` and `import def, * as ns from "pkg"`
|
|
23
|
+
* - `import type { ... } from "pkg"` and `import { type a, b } from "pkg"`
|
|
24
|
+
* - `import "pkg"` (side-effect; surfaced as a single `side-effect` entry)
|
|
25
|
+
* - Multi-line variants of all of the above.
|
|
26
|
+
*
|
|
27
|
+
* Out of scope (intentionally — both regex and oxc-parser ignore these):
|
|
28
|
+
* - Dynamic `import("pkg")` — runtime, not statically resolvable here.
|
|
29
|
+
* - `export { a } from "pkg"` re-exports from candidate code.
|
|
30
|
+
* - TypeScript `import = require()` and `import("...").Type` ambient
|
|
31
|
+
* references — neither pattern shows up in the App SDK / Studio
|
|
32
|
+
* candidate corpus the preflight grades against.
|
|
33
|
+
*/
|
|
34
|
+
import { parseSync } from "oxc-parser";
|
|
35
|
+
export function parseImports(src) {
|
|
36
|
+
// Use the `.tsx` filename hint so the parser tolerates JSX in candidate
|
|
37
|
+
// code (App SDK literacy tasks frequently include JSX in their answers).
|
|
38
|
+
const result = parseSync("input.tsx", src, { lang: "tsx" });
|
|
39
|
+
const lineStarts = computeLineStarts(src);
|
|
40
|
+
const offsetToLine = (offset) => binarySearchLine(lineStarts, offset) + 1;
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const imp of result.module.staticImports) {
|
|
43
|
+
const source = imp.moduleRequest.value;
|
|
44
|
+
// The parser recovers from malformed specifiers (e.g. backtick-quoted
|
|
45
|
+
// module requests) by emitting an empty source; the W0198 preflight
|
|
46
|
+
// can't do anything useful with that, so drop those entries.
|
|
47
|
+
if (!source)
|
|
48
|
+
continue;
|
|
49
|
+
const line = offsetToLine(imp.start);
|
|
50
|
+
if (imp.entries.length === 0) {
|
|
51
|
+
// Side-effect form: `import "pkg"`.
|
|
52
|
+
out.push({
|
|
53
|
+
source,
|
|
54
|
+
kind: "side-effect",
|
|
55
|
+
imported: "",
|
|
56
|
+
local: "",
|
|
57
|
+
isType: false,
|
|
58
|
+
line,
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
for (const entry of imp.entries) {
|
|
63
|
+
const local = entry.localName.value;
|
|
64
|
+
const isType = entry.isType;
|
|
65
|
+
switch (entry.importName.kind) {
|
|
66
|
+
case "Name":
|
|
67
|
+
out.push({
|
|
68
|
+
source,
|
|
69
|
+
kind: "named",
|
|
70
|
+
imported: entry.importName.name ?? local,
|
|
71
|
+
local,
|
|
72
|
+
isType,
|
|
73
|
+
line,
|
|
74
|
+
});
|
|
75
|
+
break;
|
|
76
|
+
case "Default":
|
|
77
|
+
out.push({
|
|
78
|
+
source,
|
|
79
|
+
kind: "default",
|
|
80
|
+
imported: "default",
|
|
81
|
+
local,
|
|
82
|
+
isType,
|
|
83
|
+
line,
|
|
84
|
+
});
|
|
85
|
+
break;
|
|
86
|
+
case "NamespaceObject":
|
|
87
|
+
out.push({
|
|
88
|
+
source,
|
|
89
|
+
kind: "namespace",
|
|
90
|
+
imported: "*",
|
|
91
|
+
local,
|
|
92
|
+
isType,
|
|
93
|
+
line,
|
|
94
|
+
});
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Line-number helpers — oxc-parser returns byte offsets; the W0198
|
|
103
|
+
// preflight surfaces 1-based line numbers in findings so reviewers can
|
|
104
|
+
// jump straight to the citing line.
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
function computeLineStarts(src) {
|
|
107
|
+
const offsets = [0];
|
|
108
|
+
for (let i = 0; i < src.length; i++) {
|
|
109
|
+
if (src[i] === "\n")
|
|
110
|
+
offsets.push(i + 1);
|
|
111
|
+
}
|
|
112
|
+
return offsets;
|
|
113
|
+
}
|
|
114
|
+
function binarySearchLine(offsets, target) {
|
|
115
|
+
let lo = 0;
|
|
116
|
+
let hi = offsets.length - 1;
|
|
117
|
+
while (lo < hi) {
|
|
118
|
+
const mid = (lo + hi + 1) >>> 1;
|
|
119
|
+
if (offsets[mid] <= target)
|
|
120
|
+
lo = mid;
|
|
121
|
+
else
|
|
122
|
+
hi = mid - 1;
|
|
123
|
+
}
|
|
124
|
+
return lo;
|
|
125
|
+
}
|
package/dist/report-store.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ export declare class ReportStore {
|
|
|
65
65
|
* matching `evalFingerprint`. Used by the pipeline to skip the expensive
|
|
66
66
|
* eval step when identical inputs have already been evaluated.
|
|
67
67
|
*
|
|
68
|
+
* Advisory lookup: a `ReportSchemaValidationError` from a corrupt prior
|
|
69
|
+
* doc is logged + counted, then null is returned so the current eval
|
|
70
|
+
* proceeds. Use `read(id)` when callers ask for a specific document by id.
|
|
71
|
+
*
|
|
68
72
|
* @returns The cached report, or null if no match or on error
|
|
69
73
|
* @see docs/design-docs/content-lake-eval-caching.md
|
|
70
74
|
*/
|
|
@@ -78,6 +82,10 @@ export declare class ReportStore {
|
|
|
78
82
|
* "Comparable" means: same evaluation mode + same source name.
|
|
79
83
|
* More granular matching (areas, models) can be added as needed.
|
|
80
84
|
*
|
|
85
|
+
* Advisory lookup: see `findByFingerprint` — a malformed prior baseline
|
|
86
|
+
* is logged + counted and null is returned so the current run still
|
|
87
|
+
* publishes its report.
|
|
88
|
+
*
|
|
81
89
|
* @see docs/design-docs/report-store/architecture.md — Auto-comparison
|
|
82
90
|
*/
|
|
83
91
|
findComparableBaseline(query: LineageQuery): Promise<null | Report>;
|
package/dist/report-store.js
CHANGED
|
@@ -119,6 +119,10 @@ export class ReportStore {
|
|
|
119
119
|
* matching `evalFingerprint`. Used by the pipeline to skip the expensive
|
|
120
120
|
* eval step when identical inputs have already been evaluated.
|
|
121
121
|
*
|
|
122
|
+
* Advisory lookup: a `ReportSchemaValidationError` from a corrupt prior
|
|
123
|
+
* doc is logged + counted, then null is returned so the current eval
|
|
124
|
+
* proceeds. Use `read(id)` when callers ask for a specific document by id.
|
|
125
|
+
*
|
|
122
126
|
* @returns The cached report, or null if no match or on error
|
|
123
127
|
* @see docs/design-docs/content-lake-eval-caching.md
|
|
124
128
|
*/
|
|
@@ -131,9 +135,19 @@ export class ReportStore {
|
|
|
131
135
|
return doc ? toReport(doc) : null;
|
|
132
136
|
}
|
|
133
137
|
catch (error) {
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
// Advisory lookup — a single corrupt prior doc must not break the
|
|
139
|
+
// current eval. Log loudly + emit a counter so ops can alert, and
|
|
140
|
+
// return null so the caller treats it as "no comparable cache hit".
|
|
141
|
+
// Direct read(id) keeps the rethrow behavior because the caller asked
|
|
142
|
+
// for that specific document and silent-null would mask the bug.
|
|
143
|
+
if (error instanceof ReportSchemaValidationError) {
|
|
144
|
+
logAdvisoryQuerySchemaFailure({
|
|
145
|
+
query: "findByFingerprint",
|
|
146
|
+
context: { fingerprint },
|
|
147
|
+
error,
|
|
148
|
+
});
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
137
151
|
console.warn(` ⚠️ Failed to query cached report by fingerprint: ${error instanceof Error ? error.message : String(error)}`);
|
|
138
152
|
return null;
|
|
139
153
|
}
|
|
@@ -147,6 +161,10 @@ export class ReportStore {
|
|
|
147
161
|
* "Comparable" means: same evaluation mode + same source name.
|
|
148
162
|
* More granular matching (areas, models) can be added as needed.
|
|
149
163
|
*
|
|
164
|
+
* Advisory lookup: see `findByFingerprint` — a malformed prior baseline
|
|
165
|
+
* is logged + counted and null is returned so the current run still
|
|
166
|
+
* publishes its report.
|
|
167
|
+
*
|
|
150
168
|
* @see docs/design-docs/report-store/architecture.md — Auto-comparison
|
|
151
169
|
*/
|
|
152
170
|
async findComparableBaseline(query) {
|
|
@@ -170,9 +188,21 @@ export class ReportStore {
|
|
|
170
188
|
return doc ? toReport(doc) : null;
|
|
171
189
|
}
|
|
172
190
|
catch (error) {
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
191
|
+
// Advisory lookup — see findByFingerprint for rationale. A malformed
|
|
192
|
+
// prior baseline returns null + counter so the current run still
|
|
193
|
+
// publishes; direct read(id) preserves the rethrow.
|
|
194
|
+
if (error instanceof ReportSchemaValidationError) {
|
|
195
|
+
logAdvisoryQuerySchemaFailure({
|
|
196
|
+
query: "findComparableBaseline",
|
|
197
|
+
context: {
|
|
198
|
+
mode: query.mode,
|
|
199
|
+
sourceName: query.source?.name,
|
|
200
|
+
before: query.before,
|
|
201
|
+
},
|
|
202
|
+
error,
|
|
203
|
+
});
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
176
206
|
console.warn(` ⚠️ Failed to query comparable baseline: ${error instanceof Error ? error.message : String(error)}`);
|
|
177
207
|
return null;
|
|
178
208
|
}
|
|
@@ -299,6 +329,25 @@ export class ReportSchemaValidationError extends Error {
|
|
|
299
329
|
this.name = "ReportSchemaValidationError";
|
|
300
330
|
}
|
|
301
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Stable log marker for log-aggregator counters. Operators alert on the
|
|
334
|
+
* count of `[report-store.advisory] schema_validation_error` lines per
|
|
335
|
+
* window; the trailing JSON carries enough context (which advisory query,
|
|
336
|
+
* what filter values, error message) to find the offending document
|
|
337
|
+
* without spelunking through GROQ.
|
|
338
|
+
*
|
|
339
|
+
* Emitted via console.error rather than console.warn so it surfaces in
|
|
340
|
+
* the same severity tier as a real failure even though we're swallowing
|
|
341
|
+
* it for the current run.
|
|
342
|
+
*/
|
|
343
|
+
function logAdvisoryQuerySchemaFailure(input) {
|
|
344
|
+
const payload = {
|
|
345
|
+
query: input.query,
|
|
346
|
+
context: input.context,
|
|
347
|
+
error: input.error.message,
|
|
348
|
+
};
|
|
349
|
+
console.error(`[report-store.advisory] schema_validation_error ${JSON.stringify(payload)}`);
|
|
350
|
+
}
|
|
302
351
|
export function toSanityReportDoc(report) {
|
|
303
352
|
const comparison = report.comparison
|
|
304
353
|
? stripComparisonBulk(report.comparison)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* document-renderers.ts
|
|
3
|
+
*
|
|
4
|
+
* Renderer registry that turns a Sanity document into both:
|
|
5
|
+
*
|
|
6
|
+
* - Markdown content for inclusion in a literacy task's grader/candidate
|
|
7
|
+
* context (existing surface, used by the doc fetcher).
|
|
8
|
+
* - A symbol-reference index for the W0197 grader-context pathway —
|
|
9
|
+
* a flat list of identifiers the doc legitimizes, with provenance.
|
|
10
|
+
* The grader prefers this over the rendered markdown when available
|
|
11
|
+
* (smaller, deterministic, harder for the grader's prior to override).
|
|
12
|
+
*
|
|
13
|
+
* Both surfaces dispatch through the same registry. Articles and
|
|
14
|
+
* typesReference docs have hand-written renderers; everything else falls
|
|
15
|
+
* through to the default walker. This keeps "what to do with a document
|
|
16
|
+
* of type X" a single decision point regardless of whether the doc was
|
|
17
|
+
* looked up by slug, path, perspective, or id.
|
|
18
|
+
*
|
|
19
|
+
* Two tiers of fidelity (rendered output):
|
|
20
|
+
*
|
|
21
|
+
* 1. Registered renderers (high fidelity) — `article`, `typesReference`.
|
|
22
|
+
* Hand-written for the document shapes we care about most.
|
|
23
|
+
* 2. Default renderer (best effort) — walks the doc, flattens portable-text
|
|
24
|
+
* fields, surfaces top-level scalars, follows references one level deep,
|
|
25
|
+
* skips framework-internal fields. Lets pinning a `marketingPage`,
|
|
26
|
+
* `glossaryEntry`, etc. work without AILF code changes.
|
|
27
|
+
*
|
|
28
|
+
* Adding a new high-fidelity renderer: implement a `DocumentRenderer`
|
|
29
|
+
* (both `render` and `extractSymbols`) and register it in
|
|
30
|
+
* `BUILT_IN_RENDERERS` keyed by `_type`.
|
|
31
|
+
*/
|
|
32
|
+
import { type SymbolIndex } from "./symbol-index.js";
|
|
33
|
+
/**
|
|
34
|
+
* A Sanity document plus any references we've already resolved for it.
|
|
35
|
+
* The resolver fetches the doc once and may include common deref payloads
|
|
36
|
+
* (e.g. `latestVersion->{...}` for typesReference) so renderers don't need
|
|
37
|
+
* to issue additional client.fetch calls themselves.
|
|
38
|
+
*/
|
|
39
|
+
export interface DocumentForRender {
|
|
40
|
+
_id: string;
|
|
41
|
+
_type: string;
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
export interface RenderContext {
|
|
45
|
+
/**
|
|
46
|
+
* Async URL fetcher for renderers that need to follow `sanity.fileAsset`
|
|
47
|
+
* URLs (e.g. typedoc JSON for `typesReference` docs). Returns the raw
|
|
48
|
+
* body text or `null` on failure.
|
|
49
|
+
*/
|
|
50
|
+
fetchUrl?: (url: string) => Promise<string | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Soft cap on rendered content length, in bytes. Renderers should respect
|
|
53
|
+
* this and append a truncation notice rather than blow up grader context.
|
|
54
|
+
*/
|
|
55
|
+
maxBytes?: number;
|
|
56
|
+
}
|
|
57
|
+
export interface RenderResult {
|
|
58
|
+
/** The rendered Markdown. Empty string is permitted but produces a warn. */
|
|
59
|
+
content: string;
|
|
60
|
+
/**
|
|
61
|
+
* The fidelity tier used. Resolvers can log differently based on this:
|
|
62
|
+
* - "high" — a registered renderer ran
|
|
63
|
+
* - "default" — fell through to the generic walker (info log)
|
|
64
|
+
*/
|
|
65
|
+
fidelity: "high" | "default";
|
|
66
|
+
/**
|
|
67
|
+
* Stable display slug for this document. Articles use `slug.current`;
|
|
68
|
+
* other types fall back to a `<_type>:<_id>` form when no slug exists.
|
|
69
|
+
* Surfaces in `DocContext.slugs` for retrieval-metric attribution.
|
|
70
|
+
*/
|
|
71
|
+
slug: string;
|
|
72
|
+
}
|
|
73
|
+
export interface DocumentRenderer {
|
|
74
|
+
/**
|
|
75
|
+
* Produce rendered Markdown for the doc's content surface (for grader
|
|
76
|
+
* + candidate context inclusion).
|
|
77
|
+
*/
|
|
78
|
+
render(doc: DocumentForRender, ctx: RenderContext): Promise<RenderResult> | RenderResult;
|
|
79
|
+
/**
|
|
80
|
+
* Produce a symbol-reference index for the doc — a flat list of
|
|
81
|
+
* identifiers the doc legitimizes plus provenance snippets. Used by
|
|
82
|
+
* the grader-context pathway (W0197) instead of injecting the full
|
|
83
|
+
* rendered doc. Returning an empty index signals the caller to fall
|
|
84
|
+
* back to the rendered markdown.
|
|
85
|
+
*/
|
|
86
|
+
extractSymbols(doc: DocumentForRender, ctx: RenderContext): Promise<SymbolIndex> | SymbolIndex;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Render a document using the registered renderer for its `_type`, falling
|
|
90
|
+
* back to the default walker. The returned `fidelity` flag tells callers
|
|
91
|
+
* whether to emit the "info: dedicated renderer would help" log.
|
|
92
|
+
*/
|
|
93
|
+
export declare function renderDocument(doc: DocumentForRender, ctx?: RenderContext): Promise<RenderResult>;
|
|
94
|
+
/**
|
|
95
|
+
* Extract a symbol-reference index for a document using its registered
|
|
96
|
+
* renderer (or the default walker for unknown types). Used by the
|
|
97
|
+
* grader-context pathway (W0197) to feed the LLM judge a compact
|
|
98
|
+
* deterministic recognition reference instead of the full rendered doc.
|
|
99
|
+
*
|
|
100
|
+
* Returns an empty `SymbolIndex` (`{ symbols: [] }`) when extraction
|
|
101
|
+
* yields nothing — callers interpret this as the signal to fall back to
|
|
102
|
+
* the rendered markdown.
|
|
103
|
+
*/
|
|
104
|
+
export declare function extractSymbolsForDoc(doc: DocumentForRender, ctx?: RenderContext): Promise<SymbolIndex>;
|
|
105
|
+
/** Exported for tests and consumers that want the registered set. */
|
|
106
|
+
export declare const REGISTERED_RENDERER_TYPES: string[];
|