@gmickel/gno 1.28.0 → 1.29.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/README.md +46 -20
- package/assets/skill/SKILL.md +33 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.1.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +1 -1
- package/spec/cli.md +41 -1
- package/spec/db/schema.sql +19 -0
- package/spec/mcp.md +66 -0
- package/spec/output-schemas/ask.schema.json +31 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +89 -2
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +30 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-results.schema.json +30 -0
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +123 -0
- package/src/config/index.ts +9 -0
- package/src/config/types.ts +50 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +111 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -132
- package/src/core/context-evidence.ts +86 -14
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter.ts +12 -1
- package/src/ingestion/record-container.ts +38 -22
- package/src/ingestion/sync.ts +15 -0
- package/src/ingestion/types.ts +2 -0
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/hybrid.ts +14 -0
- package/src/pipeline/search.ts +12 -0
- package/src/pipeline/types.ts +3 -0
- package/src/pipeline/vsearch.ts +41 -20
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +174 -0
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +6 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +170 -7
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +126 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.28.0.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
|
@@ -3,8 +3,10 @@ import { z } from "zod";
|
|
|
3
3
|
import { canonicalizeIndexName } from "../app/index-name";
|
|
4
4
|
import {
|
|
5
5
|
contextCapsulePayloadV1Schema,
|
|
6
|
-
|
|
6
|
+
contextCapsulePayloadV1_1Schema,
|
|
7
|
+
type ContextCapsulePayload,
|
|
7
8
|
} from "./context-capsule-schema";
|
|
9
|
+
import { createEgressLineage, type EgressLineage } from "./egress-provenance";
|
|
8
10
|
|
|
9
11
|
const sha256Schema = z.string().regex(/^[a-f0-9]{64}$/);
|
|
10
12
|
|
|
@@ -51,136 +53,155 @@ const normalizeSet = (values: readonly string[]): string[] =>
|
|
|
51
53
|
[...new Set(values.map(normalizeText))].sort(compareCodeUnits);
|
|
52
54
|
|
|
53
55
|
const normalizePayload = (
|
|
54
|
-
value:
|
|
55
|
-
):
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
: normalizeText(value.scope.uriPrefix),
|
|
67
|
-
tagsAll: normalizeSet(value.scope.tagsAll),
|
|
68
|
-
tagsAny: normalizeSet(value.scope.tagsAny),
|
|
69
|
-
categories: normalizeSet(value.scope.categories),
|
|
70
|
-
since: normalizeDate(value.scope.since),
|
|
71
|
-
until: normalizeDate(value.scope.until),
|
|
72
|
-
},
|
|
73
|
-
retrieval: {
|
|
74
|
-
...value.retrieval,
|
|
75
|
-
facets: normalizeSet(value.retrieval.facets),
|
|
76
|
-
queryVariants: value.retrieval.queryVariants.map(normalizeText),
|
|
77
|
-
request: {
|
|
78
|
-
...value.retrieval.request,
|
|
79
|
-
author:
|
|
80
|
-
value.retrieval.request.author === null
|
|
56
|
+
value: ContextCapsulePayload
|
|
57
|
+
): ContextCapsulePayload =>
|
|
58
|
+
({
|
|
59
|
+
...value,
|
|
60
|
+
goal: normalizeText(value.goal),
|
|
61
|
+
query: normalizeText(value.query),
|
|
62
|
+
scope: {
|
|
63
|
+
...value.scope,
|
|
64
|
+
indexName: canonicalizeIndexName(value.scope.indexName),
|
|
65
|
+
collections: normalizeSet(value.scope.collections),
|
|
66
|
+
uriPrefix:
|
|
67
|
+
value.scope.uriPrefix === null
|
|
81
68
|
? null
|
|
82
|
-
: normalizeText(value.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
69
|
+
: normalizeText(value.scope.uriPrefix),
|
|
70
|
+
tagsAll: normalizeSet(value.scope.tagsAll),
|
|
71
|
+
tagsAny: normalizeSet(value.scope.tagsAny),
|
|
72
|
+
categories: normalizeSet(value.scope.categories),
|
|
73
|
+
since: normalizeDate(value.scope.since),
|
|
74
|
+
until: normalizeDate(value.scope.until),
|
|
75
|
+
},
|
|
76
|
+
retrieval: {
|
|
77
|
+
...value.retrieval,
|
|
78
|
+
facets: normalizeSet(value.retrieval.facets),
|
|
79
|
+
queryVariants: value.retrieval.queryVariants.map(normalizeText),
|
|
80
|
+
request: {
|
|
81
|
+
...value.retrieval.request,
|
|
82
|
+
author:
|
|
83
|
+
value.retrieval.request.author === null
|
|
84
|
+
? null
|
|
85
|
+
: normalizeText(value.retrieval.request.author),
|
|
86
|
+
lang:
|
|
87
|
+
value.retrieval.request.lang === null
|
|
88
|
+
? null
|
|
89
|
+
: normalizeText(value.retrieval.request.lang),
|
|
90
|
+
...(value.retrieval.request.intent === undefined
|
|
91
|
+
? {}
|
|
92
|
+
: {
|
|
93
|
+
intent:
|
|
94
|
+
value.retrieval.request.intent === null
|
|
95
|
+
? null
|
|
96
|
+
: normalizeText(value.retrieval.request.intent),
|
|
97
|
+
}),
|
|
98
|
+
...(value.retrieval.request.exclude === undefined
|
|
99
|
+
? {}
|
|
100
|
+
: { exclude: normalizeSet(value.retrieval.request.exclude) }),
|
|
101
|
+
queryModes: value.retrieval.request.queryModes.map((mode) => ({
|
|
102
|
+
...mode,
|
|
103
|
+
text: normalizeText(mode.text),
|
|
104
|
+
})),
|
|
105
|
+
},
|
|
106
|
+
capabilityStates: Object.fromEntries(
|
|
107
|
+
Object.entries(value.retrieval.capabilityStates).map(([key, state]) => [
|
|
108
|
+
key,
|
|
109
|
+
{ ...state, fallbackReasons: normalizeSet(state.fallbackReasons) },
|
|
110
|
+
])
|
|
111
|
+
) as typeof value.retrieval.capabilityStates,
|
|
112
|
+
},
|
|
113
|
+
fallbacks: [...value.fallbacks].sort((left, right) =>
|
|
114
|
+
compareCodeUnits(
|
|
115
|
+
`${left.code}\0${left.capability}`,
|
|
116
|
+
`${right.code}\0${right.capability}`
|
|
117
|
+
)
|
|
118
|
+
),
|
|
119
|
+
...(value.schemaVersion === "1.1"
|
|
120
|
+
? {
|
|
121
|
+
egressLineage: {
|
|
122
|
+
...value.egressLineage,
|
|
123
|
+
sources: [...value.egressLineage.sources],
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
: {}),
|
|
127
|
+
evidence: value.evidence.map((item) => ({
|
|
128
|
+
...item,
|
|
129
|
+
title: item.title === null ? null : normalizeText(item.title),
|
|
130
|
+
heading: item.heading === null ? null : normalizeText(item.heading),
|
|
131
|
+
modifiedAt: normalizeDate(item.modifiedAt),
|
|
132
|
+
documentDate: normalizeDocumentDate(item.documentDate),
|
|
133
|
+
observedAt: normalizeDate(item.observedAt),
|
|
134
|
+
contextIds: normalizeSet(item.contextIds),
|
|
135
|
+
...(item.egressLineage === undefined
|
|
88
136
|
? {}
|
|
89
137
|
: {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
138
|
+
egressLineage: {
|
|
139
|
+
...item.egressLineage,
|
|
140
|
+
sources: [...item.egressLineage.sources],
|
|
141
|
+
},
|
|
94
142
|
}),
|
|
95
|
-
...(
|
|
143
|
+
...(item.retrievalSources === undefined
|
|
96
144
|
? {}
|
|
97
|
-
: {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
evidence: value.evidence.map((item) => ({
|
|
117
|
-
...item,
|
|
118
|
-
title: item.title === null ? null : normalizeText(item.title),
|
|
119
|
-
heading: item.heading === null ? null : normalizeText(item.heading),
|
|
120
|
-
modifiedAt: normalizeDate(item.modifiedAt),
|
|
121
|
-
documentDate: normalizeDocumentDate(item.documentDate),
|
|
122
|
-
observedAt: normalizeDate(item.observedAt),
|
|
123
|
-
contextIds: normalizeSet(item.contextIds),
|
|
124
|
-
...(item.retrievalSources === undefined
|
|
125
|
-
? {}
|
|
126
|
-
: {
|
|
127
|
-
retrievalSources: [...new Set(item.retrievalSources)].sort(
|
|
128
|
-
compareCodeUnits
|
|
129
|
-
),
|
|
130
|
-
}),
|
|
131
|
-
facets: normalizeSet(item.facets),
|
|
132
|
-
...(item.record === undefined
|
|
133
|
-
? {}
|
|
134
|
-
: {
|
|
135
|
-
record: {
|
|
136
|
-
...item.record,
|
|
137
|
-
anchors: item.record.anchors.map((anchor) => ({
|
|
138
|
-
...anchor,
|
|
139
|
-
value: normalizeText(anchor.value),
|
|
140
|
-
...(anchor.endValue === undefined
|
|
145
|
+
: {
|
|
146
|
+
retrievalSources: [...new Set(item.retrievalSources)].sort(
|
|
147
|
+
compareCodeUnits
|
|
148
|
+
),
|
|
149
|
+
}),
|
|
150
|
+
facets: normalizeSet(item.facets),
|
|
151
|
+
...(item.record === undefined
|
|
152
|
+
? {}
|
|
153
|
+
: {
|
|
154
|
+
record: {
|
|
155
|
+
...item.record,
|
|
156
|
+
anchors: item.record.anchors.map((anchor) => ({
|
|
157
|
+
...anchor,
|
|
158
|
+
value: normalizeText(anchor.value),
|
|
159
|
+
...(anchor.endValue === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { endValue: normalizeText(anchor.endValue) }),
|
|
162
|
+
})),
|
|
163
|
+
...(item.record.participants === undefined
|
|
141
164
|
? {}
|
|
142
|
-
: {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
.sort((left, right) =>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
165
|
+
: { participants: normalizeSet(item.record.participants) }),
|
|
166
|
+
...(item.record.categories === undefined
|
|
167
|
+
? {}
|
|
168
|
+
: { categories: normalizeSet(item.record.categories) }),
|
|
169
|
+
},
|
|
170
|
+
}),
|
|
171
|
+
})),
|
|
172
|
+
guidance: {
|
|
173
|
+
...value.guidance,
|
|
174
|
+
configuredContexts: [...value.guidance.configuredContexts]
|
|
175
|
+
.map((item) => ({
|
|
176
|
+
...item,
|
|
177
|
+
scopeKey: normalizeText(item.scopeKey),
|
|
178
|
+
text: normalizeText(item.text),
|
|
179
|
+
}))
|
|
180
|
+
.sort((left, right) =>
|
|
181
|
+
compareCodeUnits(left.contextId, right.contextId)
|
|
182
|
+
),
|
|
183
|
+
},
|
|
184
|
+
coverage: {
|
|
185
|
+
...value.coverage,
|
|
186
|
+
requestedFacets: normalizeSet(value.coverage.requestedFacets),
|
|
187
|
+
coveredFacets: [...value.coverage.coveredFacets]
|
|
188
|
+
.map((item) => ({
|
|
189
|
+
facet: normalizeText(item.facet),
|
|
190
|
+
evidenceIds: normalizeSet(item.evidenceIds),
|
|
191
|
+
}))
|
|
192
|
+
.sort((left, right) => compareCodeUnits(left.facet, right.facet)),
|
|
193
|
+
unresolvedFacets: normalizeSet(value.coverage.unresolvedFacets),
|
|
194
|
+
gaps: [...value.coverage.gaps].sort((left, right) =>
|
|
195
|
+
compareCodeUnits(
|
|
196
|
+
`${left.facet}\0${left.code}`,
|
|
197
|
+
`${right.facet}\0${right.code}`
|
|
198
|
+
)
|
|
199
|
+
),
|
|
200
|
+
},
|
|
201
|
+
warnings: [...value.warnings].sort((left, right) =>
|
|
202
|
+
compareCodeUnits(left.code, right.code)
|
|
178
203
|
),
|
|
179
|
-
}
|
|
180
|
-
warnings: [...value.warnings].sort((left, right) =>
|
|
181
|
-
compareCodeUnits(left.code, right.code)
|
|
182
|
-
),
|
|
183
|
-
});
|
|
204
|
+
}) as ContextCapsulePayload;
|
|
184
205
|
|
|
185
206
|
export type ContextCapsuleErrorCode =
|
|
186
207
|
| "identity_mismatch"
|
|
@@ -267,9 +288,14 @@ const contractError = (
|
|
|
267
288
|
);
|
|
268
289
|
};
|
|
269
290
|
|
|
270
|
-
const
|
|
291
|
+
const contextCapsulePayloadSchema = z.union([
|
|
292
|
+
contextCapsulePayloadV1Schema,
|
|
293
|
+
contextCapsulePayloadV1_1Schema,
|
|
294
|
+
]);
|
|
295
|
+
|
|
296
|
+
const parsePayload = (input: unknown): ContextCapsulePayload => {
|
|
271
297
|
try {
|
|
272
|
-
return
|
|
298
|
+
return contextCapsulePayloadSchema.parse(input);
|
|
273
299
|
} catch (error) {
|
|
274
300
|
throw contractError(input, error);
|
|
275
301
|
}
|
|
@@ -279,7 +305,7 @@ export interface ContextCapsuleCreateOptions {
|
|
|
279
305
|
countTokens?: (accountingJson: string) => number;
|
|
280
306
|
}
|
|
281
307
|
|
|
282
|
-
const identityPayload = (payload:
|
|
308
|
+
const identityPayload = (payload: ContextCapsulePayload) => {
|
|
283
309
|
const {
|
|
284
310
|
usedBytes: _usedBytes,
|
|
285
311
|
usedTokens: _usedTokens,
|
|
@@ -288,7 +314,7 @@ const identityPayload = (payload: ContextCapsulePayloadV1) => {
|
|
|
288
314
|
return { ...payload, budget: stableBudget };
|
|
289
315
|
};
|
|
290
316
|
|
|
291
|
-
const accountingPayload = <T extends
|
|
317
|
+
const accountingPayload = <T extends ContextCapsulePayload>(value: T) => {
|
|
292
318
|
const {
|
|
293
319
|
usedBytes: _usedBytes,
|
|
294
320
|
usedTokens: _usedTokens,
|
|
@@ -312,7 +338,7 @@ const activeTokenCount = (
|
|
|
312
338
|
};
|
|
313
339
|
|
|
314
340
|
const fixedPointCapsule = (
|
|
315
|
-
payloadInput:
|
|
341
|
+
payloadInput: ContextCapsulePayload,
|
|
316
342
|
options: ContextCapsuleCreateOptions
|
|
317
343
|
) => {
|
|
318
344
|
const capsuleId = hashCanonical(identityPayload(payloadInput));
|
|
@@ -362,9 +388,10 @@ const fixedPointCapsule = (
|
|
|
362
388
|
);
|
|
363
389
|
};
|
|
364
390
|
|
|
365
|
-
const contextCapsuleBaseV1Schema =
|
|
366
|
-
capsuleId: sha256Schema,
|
|
367
|
-
})
|
|
391
|
+
const contextCapsuleBaseV1Schema = z.union([
|
|
392
|
+
contextCapsulePayloadV1Schema.extend({ capsuleId: sha256Schema }),
|
|
393
|
+
contextCapsulePayloadV1_1Schema.extend({ capsuleId: sha256Schema }),
|
|
394
|
+
]);
|
|
368
395
|
|
|
369
396
|
export const contextCapsuleV1Schema = contextCapsuleBaseV1Schema.superRefine(
|
|
370
397
|
(value, context) => {
|
|
@@ -470,6 +497,24 @@ export const canonicalContextCapsuleJson = (input: unknown): string =>
|
|
|
470
497
|
export const canonicalContextCapsuleAccountingJson = (input: unknown): string =>
|
|
471
498
|
canonicalJson(accountingPayload(parseContextCapsuleV1(input)));
|
|
472
499
|
|
|
500
|
+
/**
|
|
501
|
+
* Runtime-only conservative projection for legacy 1.0 Capsules. Canonical
|
|
502
|
+
* bytes and capsuleId remain governed by the original schema.
|
|
503
|
+
*/
|
|
504
|
+
export const contextCapsuleEgressLineage = (input: unknown): EgressLineage => {
|
|
505
|
+
const capsule = parseContextCapsuleV1(input);
|
|
506
|
+
if (capsule.schemaVersion === "1.1") return capsule.egressLineage;
|
|
507
|
+
return createEgressLineage(
|
|
508
|
+
[...new Set(capsule.evidence.map(({ collection }) => collection))].map(
|
|
509
|
+
(collection) => ({
|
|
510
|
+
collection,
|
|
511
|
+
policy: "local_only" as const,
|
|
512
|
+
source: "legacy_default" as const,
|
|
513
|
+
})
|
|
514
|
+
)
|
|
515
|
+
);
|
|
516
|
+
};
|
|
517
|
+
|
|
473
518
|
export {
|
|
474
519
|
contextCapsuleVerificationEvidenceSchema,
|
|
475
520
|
contextCapsuleVerificationSchema,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Strict indexed-evidence loading for Context Capsule compilation. */
|
|
2
2
|
|
|
3
|
+
import type { EgressPolicy } from "../config/types";
|
|
3
4
|
import type { SearchResults } from "../pipeline/types";
|
|
4
5
|
import type {
|
|
5
6
|
ActivationIndexSnapshot,
|
|
@@ -12,7 +13,7 @@ import type {
|
|
|
12
13
|
ContextCanonicalProjection,
|
|
13
14
|
MaterializedContextCandidate,
|
|
14
15
|
} from "./context-budget";
|
|
15
|
-
import type {
|
|
16
|
+
import type { ContextCapsulePayloadV1_1 } from "./context-capsule-schema";
|
|
16
17
|
import type {
|
|
17
18
|
ContextCanonicalPlanDraft,
|
|
18
19
|
ContextCompilerInput,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
ContextRetrievalCandidate,
|
|
22
23
|
ContextRetrievalRequest,
|
|
23
24
|
} from "./context-compiler";
|
|
25
|
+
import type { EgressLineage } from "./egress-provenance";
|
|
24
26
|
import type { RecordEvidenceMetadata } from "./record-metadata";
|
|
25
27
|
|
|
26
28
|
import { decorateUriForIndex, deriveDocid, parseUri } from "../app/constants";
|
|
@@ -36,6 +38,7 @@ import {
|
|
|
36
38
|
} from "./context-capsule-validation";
|
|
37
39
|
import { planContextEvidence } from "./context-compiler";
|
|
38
40
|
import { projectContextEvidenceMetadata } from "./context-evidence-metadata";
|
|
41
|
+
import { createEgressLineage, resolveEgressLineage } from "./egress-provenance";
|
|
39
42
|
import { projectRecordEvidenceMetadata } from "./record-metadata";
|
|
40
43
|
import {
|
|
41
44
|
extractInclusiveLines,
|
|
@@ -82,6 +85,7 @@ export class ContextEvidenceError extends Error {
|
|
|
82
85
|
|
|
83
86
|
export interface ContextEvidenceSnapshot {
|
|
84
87
|
collections: string[];
|
|
88
|
+
egressLineage: EgressLineage;
|
|
85
89
|
contexts: ContextRow[];
|
|
86
90
|
documents: ContextEvidenceSnapshotDocument[];
|
|
87
91
|
contextFingerprint: string;
|
|
@@ -105,7 +109,8 @@ export interface ContextEvidenceValue {
|
|
|
105
109
|
observedAt: null;
|
|
106
110
|
contextIds: string[];
|
|
107
111
|
trust: "untrusted";
|
|
108
|
-
egress: "unavailable";
|
|
112
|
+
egress: EgressPolicy | "unavailable";
|
|
113
|
+
egressLineage?: EgressLineage;
|
|
109
114
|
record?: RecordEvidenceMetadata;
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -117,6 +122,7 @@ export type ContextEvidenceCompilerInput = Omit<
|
|
|
117
122
|
export interface ContextEvidenceProjectionContext {
|
|
118
123
|
contextFingerprint: string;
|
|
119
124
|
indexFingerprint: string;
|
|
125
|
+
egressLineage: EgressLineage;
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
export interface ContextEvidenceCompilerDeps<P> {
|
|
@@ -208,18 +214,34 @@ export const captureContextEvidenceSnapshot = async (
|
|
|
208
214
|
"context_load_failed",
|
|
209
215
|
"Failed to load configured contexts"
|
|
210
216
|
).map((row) => ({ ...row }));
|
|
217
|
+
const collectionRows = unwrapStore(
|
|
218
|
+
await store.getCollections(),
|
|
219
|
+
"collection_load_failed",
|
|
220
|
+
"Failed to load indexed collections"
|
|
221
|
+
);
|
|
211
222
|
const collections =
|
|
212
223
|
requestedCollections.length > 0
|
|
213
224
|
? [...new Set(requestedCollections)].sort(compareCodeUnits)
|
|
214
|
-
: [
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
225
|
+
: [...new Set(collectionRows.map((row) => row.name))].sort(
|
|
226
|
+
compareCodeUnits
|
|
227
|
+
);
|
|
228
|
+
let egressLineage: EgressLineage;
|
|
229
|
+
try {
|
|
230
|
+
egressLineage = resolveEgressLineage(
|
|
231
|
+
collectionRows.map((row) => ({
|
|
232
|
+
collection: row.name,
|
|
233
|
+
policy: row.egressPolicy,
|
|
234
|
+
source: row.egressPolicySource,
|
|
235
|
+
})),
|
|
236
|
+
collections
|
|
237
|
+
);
|
|
238
|
+
} catch (error) {
|
|
239
|
+
throw new ContextEvidenceError(
|
|
240
|
+
"collection_load_failed",
|
|
241
|
+
"Failed to resolve complete collection policy lineage",
|
|
242
|
+
error
|
|
243
|
+
);
|
|
244
|
+
}
|
|
223
245
|
const indexName = canonicalizeIndexName(indexNameInput);
|
|
224
246
|
const indexSnapshots: ReturnType<typeof canonicalIndexSnapshot>[] = [];
|
|
225
247
|
const documents: ContextEvidenceSnapshotDocument[] = [];
|
|
@@ -248,6 +270,7 @@ export const captureContextEvidenceSnapshot = async (
|
|
|
248
270
|
}
|
|
249
271
|
return {
|
|
250
272
|
collections,
|
|
273
|
+
egressLineage,
|
|
251
274
|
contexts,
|
|
252
275
|
documents: documents.sort(
|
|
253
276
|
(left, right) =>
|
|
@@ -256,7 +279,10 @@ export const captureContextEvidenceSnapshot = async (
|
|
|
256
279
|
compareCodeUnits(left.mirrorHash ?? "", right.mirrorHash ?? "")
|
|
257
280
|
),
|
|
258
281
|
contextFingerprint: fingerprintContextRows(contexts),
|
|
259
|
-
indexFingerprint: hashJson(
|
|
282
|
+
indexFingerprint: hashJson({
|
|
283
|
+
snapshots: indexSnapshots,
|
|
284
|
+
egressLineage,
|
|
285
|
+
}),
|
|
260
286
|
};
|
|
261
287
|
};
|
|
262
288
|
|
|
@@ -313,6 +339,21 @@ export const materializeContextEvidenceCandidates = async (
|
|
|
313
339
|
"document_load_failed",
|
|
314
340
|
"Failed to batch-load Context evidence documents"
|
|
315
341
|
);
|
|
342
|
+
const collectionRows = unwrapStore(
|
|
343
|
+
await store.getCollections(),
|
|
344
|
+
"collection_load_failed",
|
|
345
|
+
"Failed to load Context evidence policies"
|
|
346
|
+
);
|
|
347
|
+
const policyByCollection = new Map(
|
|
348
|
+
collectionRows.map((row) => [
|
|
349
|
+
row.name,
|
|
350
|
+
{
|
|
351
|
+
collection: row.name,
|
|
352
|
+
policy: row.egressPolicy,
|
|
353
|
+
source: row.egressPolicySource,
|
|
354
|
+
},
|
|
355
|
+
])
|
|
356
|
+
);
|
|
316
357
|
const alignedDocuments = candidates.map((candidate) =>
|
|
317
358
|
referenceDocument(documents, candidate, indexName)
|
|
318
359
|
);
|
|
@@ -343,6 +384,24 @@ export const materializeContextEvidenceCandidates = async (
|
|
|
343
384
|
return candidates.map((candidate, index) => {
|
|
344
385
|
const result = candidate.result;
|
|
345
386
|
const document = alignedDocuments[index];
|
|
387
|
+
if (!document) {
|
|
388
|
+
throw new ContextEvidenceError(
|
|
389
|
+
"document_load_failed",
|
|
390
|
+
`Document identity is unavailable for ${result.uri}`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
const fallbackPolicy = policyByCollection.get(document.collection);
|
|
394
|
+
if (!result.egressLineage && !fallbackPolicy) {
|
|
395
|
+
throw new ContextEvidenceError(
|
|
396
|
+
"collection_load_failed",
|
|
397
|
+
`Policy lineage is unavailable for ${result.uri}`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const egressLineage =
|
|
401
|
+
result.egressLineage ??
|
|
402
|
+
createEgressLineage([
|
|
403
|
+
fallbackPolicy as NonNullable<typeof fallbackPolicy>,
|
|
404
|
+
]);
|
|
346
405
|
const metadata = result[SEARCH_RESULT_PLANNER_METADATA];
|
|
347
406
|
const snippetRange = result.snippetRange;
|
|
348
407
|
if (!document?.mirrorHash || !metadata || !snippetRange) {
|
|
@@ -418,7 +477,8 @@ export const materializeContextEvidenceCandidates = async (
|
|
|
418
477
|
observedAt: null,
|
|
419
478
|
contextIds: [...candidate.contextIds],
|
|
420
479
|
trust: "untrusted",
|
|
421
|
-
egress:
|
|
480
|
+
egress: egressLineage.effectivePolicy,
|
|
481
|
+
egressLineage,
|
|
422
482
|
...(projectRecordEvidenceMetadata(document)
|
|
423
483
|
? { record: projectRecordEvidenceMetadata(document) }
|
|
424
484
|
: {}),
|
|
@@ -441,6 +501,7 @@ export const compileContextEvidence = async <P>(
|
|
|
441
501
|
const fingerprints = {
|
|
442
502
|
contextFingerprint: before.contextFingerprint,
|
|
443
503
|
indexFingerprint: before.indexFingerprint,
|
|
504
|
+
egressLineage: before.egressLineage,
|
|
444
505
|
};
|
|
445
506
|
const plan = await planContextEvidence(
|
|
446
507
|
{ ...input, contextSnapshot: before.contexts, observedAt: null },
|
|
@@ -479,7 +540,16 @@ export const compileContextEvidence = async <P>(
|
|
|
479
540
|
export const toContextCapsuleEvidence = (
|
|
480
541
|
candidate: MaterializedContextCandidate<ContextEvidenceValue>,
|
|
481
542
|
selectionRank: number
|
|
482
|
-
):
|
|
543
|
+
): ContextCapsulePayloadV1_1["evidence"][number] => {
|
|
544
|
+
if (
|
|
545
|
+
candidate.value.egress === "unavailable" ||
|
|
546
|
+
candidate.value.egressLineage === undefined
|
|
547
|
+
) {
|
|
548
|
+
throw new ContextEvidenceError(
|
|
549
|
+
"collection_load_failed",
|
|
550
|
+
`Policy lineage is unavailable for ${candidate.uri}`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
483
553
|
const identity = {
|
|
484
554
|
uri: candidate.uri,
|
|
485
555
|
docid: candidate.docid,
|
|
@@ -493,6 +563,8 @@ export const toContextCapsuleEvidence = (
|
|
|
493
563
|
evidenceId: contextCapsuleEvidenceIdentity(identity),
|
|
494
564
|
...identity,
|
|
495
565
|
...candidate.value,
|
|
566
|
+
egress: candidate.value.egress,
|
|
567
|
+
egressLineage: candidate.value.egressLineage,
|
|
496
568
|
text: candidate.text,
|
|
497
569
|
retrievalRank: candidate.retrievalRank,
|
|
498
570
|
selectionRank,
|