@weftlet/toolkit 0.4.0 → 0.6.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/README.md +149 -14
- package/dist/application/cache-adoption.d.ts +2 -1
- package/dist/application/cache-adoption.js +12 -5
- package/dist/application/document-coverage.d.ts +28 -0
- package/dist/application/document-coverage.js +58 -0
- package/dist/application/document-overlay.d.ts +14 -0
- package/dist/application/document-overlay.js +31 -0
- package/dist/application/extraction-identity.d.ts +2 -1
- package/dist/application/extraction-identity.js +7 -0
- package/dist/application/hydration-inputs.d.ts +15 -0
- package/dist/application/hydration-inputs.js +55 -0
- package/dist/application/hydration-plan.d.ts +7 -0
- package/dist/application/hydration-plan.js +18 -5
- package/dist/application/hydrator.d.ts +2 -0
- package/dist/application/hydrator.js +40 -18
- package/dist/application/overlay.d.ts +3 -1
- package/dist/application/overlay.js +29 -9
- package/dist/application/saved-evidence.d.ts +2 -2
- package/dist/application/semantic-run.d.ts +3 -0
- package/dist/application/semantic-scope.d.ts +1 -1
- package/dist/application/semantic-scope.js +2 -2
- package/dist/configuration/cache.js +13 -1
- package/dist/configuration/config.d.ts +2 -0
- package/dist/configuration/config.js +6 -1
- package/dist/configuration/document-traversal.d.ts +7 -0
- package/dist/configuration/document-traversal.js +13 -0
- package/dist/extraction/canonical-document-links.d.ts +28 -0
- package/dist/extraction/canonical-document-links.js +95 -0
- package/dist/extraction/document-classification.d.ts +44 -0
- package/dist/extraction/document-classification.js +161 -0
- package/dist/extraction/document-evidence.d.ts +21 -0
- package/dist/extraction/document-evidence.js +83 -0
- package/dist/extraction/document-traversal.d.ts +76 -0
- package/dist/extraction/document-traversal.js +210 -0
- package/dist/extraction/document.d.ts +3 -1
- package/dist/extraction/document.js +3 -1
- package/dist/graph/authority.js +3 -0
- package/dist/graph/coverage.d.ts +8 -0
- package/dist/graph/coverage.js +96 -0
- package/dist/graph/document-role-description.d.ts +5 -0
- package/dist/graph/document-role-description.js +18 -0
- package/dist/graph/identity-preflight.d.ts +57 -0
- package/dist/graph/identity-preflight.js +71 -0
- package/dist/graph/query.d.ts +2 -2
- package/dist/graph/query.js +22 -62
- package/dist/graph/rdf.d.ts +4 -1
- package/dist/graph/rdf.js +21 -6
- package/dist/graph/shacl-shapes.js +26 -0
- package/dist/graph/validation-progress.d.ts +14 -0
- package/dist/graph/validation-progress.js +18 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/interfaces/cli.js +29 -5
- package/dist/interfaces/document-coverage.d.ts +9 -0
- package/dist/interfaces/document-coverage.js +117 -0
- package/dist/repository/git.d.ts +11 -0
- package/dist/repository/git.js +38 -0
- package/dist/visualization/visualization.js +21 -6
- package/docs/ADR-017-shacl-validation-union.md +4 -0
- package/docs/ADR-018-operational-semantic-cache.md +2 -2
- package/docs/ADR-019-semantic-failure-diagnostics.md +2 -2
- package/docs/ADR-020-canonical-physical-file-producers.md +2 -2
- package/docs/ADR-021-identity-preflight-and-validation-timing.md +84 -0
- package/docs/ADR-022-release-documentation.md +44 -0
- package/docs/ADR-023-document-coverage-preview.md +64 -0
- package/docs/ADR-024-implementation-coverage.md +51 -0
- package/docs/ADR-025-document-classification.md +78 -0
- package/docs/ADR-026-traversal-hydration.md +94 -0
- package/docs/ADR-027-validation-closeout.md +155 -0
- package/docs/CONSUMER-TRIAL.md +1 -1
- package/docs/MIGRATING-TO-WEFTLET.md +1 -1
- package/docs/PROVIDERS.md +17 -1
- package/docs/RELEASE-1.0-PLAN.md +177 -48
- package/docs/RELEASING.md +46 -8
- package/docs/ROADMAP.md +59 -28
- package/docs/VALIDATION.md +451 -0
- package/docs/benchmarks/validation-2026-10-28/README.md +25 -0
- package/docs/benchmarks/validation-2026-10-28/large.json +1 -0
- package/docs/benchmarks/validation-2026-10-28/lifecycle.json +1 -0
- package/docs/benchmarks/validation-2026-10-28/native.json +1 -0
- package/docs/benchmarks/validation-2026-10-28/rich.json +1 -0
- package/docs/extraction-manifest.json +73 -17
- package/examples/generic-typescript/document-policy.json +9 -0
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -13,6 +13,10 @@ Proposed future capabilities are recorded in the [Weftlet 2.0 product plan](docs
|
|
|
13
13
|
|
|
14
14
|
## Set up a project
|
|
15
15
|
|
|
16
|
+
<!-- weftlet:release:start -->
|
|
17
|
+
Package versions in this checkout/archive: `@weftlet/toolkit@0.6.0` and `@weftlet/core@0.6.0`.
|
|
18
|
+
<!-- weftlet:release:end -->
|
|
19
|
+
|
|
16
20
|
Weftlet uses `@weftlet/toolkit`; its neutral `@weftlet/core` dependency is installed
|
|
17
21
|
automatically. Both packages are available on npm.
|
|
18
22
|
See [release status](docs/RELEASING.md). Existing Tently users should follow
|
|
@@ -80,7 +84,7 @@ pnpm exec weftlet hydrate --plan --json --config /path/to/project/context-graph.
|
|
|
80
84
|
The human summary and JSON identify the resolved commit, current local configuration, selected
|
|
81
85
|
documents and inclusion reasons, UTF-8 byte sizes, source approval, expected cache reuse and
|
|
82
86
|
extraction counts, budget violations, and working changes excluded from the committed input.
|
|
83
|
-
|
|
87
|
+
Direct-mode selection uses configured repository file/directory paths; `approvedIntentSources` uses its
|
|
84
88
|
separate glob matcher. An explicit empty semantic source list selects no documents, fixing the
|
|
85
89
|
earlier accidental expansion to the whole repository.
|
|
86
90
|
|
|
@@ -96,9 +100,9 @@ and existing agent-selection limits are warnings; they do not add a new hydratio
|
|
|
96
100
|
would prevent removing the last document and invalidating its relationships. All selected
|
|
97
101
|
documents remain visible when budgets are exceeded.
|
|
98
102
|
|
|
99
|
-
Source approval does not approve model assertions.
|
|
100
|
-
evidence roots
|
|
101
|
-
|
|
103
|
+
Source approval does not approve model assertions. In direct mode, validation-document labels
|
|
104
|
+
reflect configured evidence roots and selected validation documents still undergo semantic
|
|
105
|
+
extraction. The opt-in traversal mode below excludes them by default. See
|
|
102
106
|
[ADR 016](docs/ADR-016-hydration-preview.md) and the [1.0 task list](docs/RELEASE-1.0-PLAN.md).
|
|
103
107
|
|
|
104
108
|
Starting with **0.4.0**, preview also maps opaque diagnostic source IDs to local paths. Semantic
|
|
@@ -107,8 +111,131 @@ their structured report on stderr. Built-in Codex can reuse completed artifacts
|
|
|
107
111
|
operational changes such as increasing a timeout. See [provider recovery](docs/PROVIDERS.md#limits-and-reuse)
|
|
108
112
|
for preview, retry and explicit legacy-cache adoption instructions.
|
|
109
113
|
|
|
114
|
+
## Preview linked document coverage
|
|
115
|
+
|
|
116
|
+
This checkout/archive includes a separate prospective preview. npm 0.5.0 does not include this command:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
pnpm exec weftlet documents plan --entry docs/sot.md --entry docs/roadmap.md --root docs --ref HEAD
|
|
120
|
+
pnpm exec weftlet documents plan --entry docs/sot.md --root docs --ref HEAD --json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use your repository's exact committed entry paths. `--root` may repeat and defaults to the
|
|
124
|
+
repository root. The operation follows supported Markdown links with cycle protection and
|
|
125
|
+
deduplication, records citations and exclusions, and reports missing/ambiguous targets. Paths,
|
|
126
|
+
approval matches and validation-evidence labels remain explicit; following a link never approves
|
|
127
|
+
its contents. Git objects supply the input even while the checkout is dirty.
|
|
128
|
+
|
|
129
|
+
This reports prospective coverage and **does not change hydration inputs or estimate cache/model
|
|
130
|
+
work**. Continue using `hydrate --plan` for the current execution plan. This command does not modify configuration.
|
|
131
|
+
Existing semantic document/byte budgets are compared after traversal, including validation
|
|
132
|
+
documents. Independent read limits (`--max-read-documents`, `--max-read-bytes`,
|
|
133
|
+
`--max-document-bytes`) leave an explicit unread frontier if reached. Incomplete coverage or
|
|
134
|
+
exceeded extraction budgets return a report with exit status 1, without model calls or graph writes.
|
|
135
|
+
The preview follows only supported local links; complete coverage is not a claim of complete
|
|
136
|
+
product knowledge. See [ADR 023](docs/ADR-023-document-coverage-preview.md) for limits and the
|
|
137
|
+
prospective-operation boundaries.
|
|
138
|
+
|
|
139
|
+
The preview also accepts an optional JSON source policy:
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
pnpm exec weftlet documents plan --entry docs/sot.md --root docs --document-policy document-policy.json --json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"schemaVersion": 1,
|
|
148
|
+
"roles": [
|
|
149
|
+
{ "id": "intent", "pattern": "docs/sot.md", "role": "intent" },
|
|
150
|
+
{ "id": "plans", "pattern": "docs/plans/**", "role": "plan" },
|
|
151
|
+
{ "id": "checks", "pattern": "docs/validation/**", "role": "validation" }
|
|
152
|
+
],
|
|
153
|
+
"owners": [
|
|
154
|
+
{ "id": "sot-owner", "pattern": "docs/**", "ownerDocument": "docs/sot.md" }
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Roles are `intent`, `plan`, `validation` or `reference`; unmatched sources are `unclassified`
|
|
160
|
+
unless configured evidence roots or approved intent sources provide a default. The owner must
|
|
161
|
+
be read within the selected coverage, match `approvedIntentSources`, and have an unambiguous
|
|
162
|
+
intent role. Owner mappings and links never transfer approval to another source or approve an
|
|
163
|
+
assertion. Conflicting mappings remain explicit gaps.
|
|
164
|
+
|
|
165
|
+
This file is an operation input, separate from `context-graph.config.json`. `ready` and the
|
|
166
|
+
exit status still describe traversal and budget checks; inspect `classification.complete` and
|
|
167
|
+
its issues for role/ownership gaps. The policy does not change current hydration or cache inputs.
|
|
168
|
+
The public `extractDocumentEvidence` API separately emits cited document-presence and reference
|
|
169
|
+
facts, including empty validation documents, without interpreting prose or treating a written
|
|
170
|
+
“PASS” as proof that a test ran. Queries, RDF/SHACL and the viewer preserve its source metadata.
|
|
171
|
+
See [ADR 025](docs/ADR-025-document-classification.md) for the contract and limits.
|
|
172
|
+
|
|
173
|
+
## Hydrate linked SOT and roadmap documents
|
|
174
|
+
|
|
175
|
+
This checkout/archive adds opt-in traversal hydration; npm 0.5.0 does not support it. Merge this
|
|
176
|
+
fragment into your normal configuration, using real committed entry paths and reviewed owner
|
|
177
|
+
mappings. Keep the existing `semanticSources` array for direct-mode compatibility; traversal
|
|
178
|
+
replaces its selection when enabled.
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"documentTraversal": {
|
|
183
|
+
"entryPoints": ["docs/sot.md", "docs/roadmap.md"],
|
|
184
|
+
"roots": ["docs"],
|
|
185
|
+
"maxReadDocuments": 1000,
|
|
186
|
+
"maxReadBytes": 16777216,
|
|
187
|
+
"maxDocumentBytes": 1048576,
|
|
188
|
+
"policy": {
|
|
189
|
+
"schemaVersion": 1,
|
|
190
|
+
"roles": [
|
|
191
|
+
{ "id": "intent", "pattern": "docs/sot.md", "role": "intent" },
|
|
192
|
+
{ "id": "plans", "pattern": "docs/roadmap.md", "role": "plan" },
|
|
193
|
+
{ "id": "checks", "pattern": "docs/validation/**", "role": "validation" }
|
|
194
|
+
],
|
|
195
|
+
"owners": [
|
|
196
|
+
{ "id": "product-owner", "pattern": "docs/**", "ownerDocument": "docs/sot.md" }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Review `approvedIntentSources` separately: an owner must already be explicitly approved. Preview
|
|
204
|
+
with `weftlet hydrate --plan --json`, then run `weftlet hydrate --ref HEAD` after reviewing scope
|
|
205
|
+
and cost. The plan reports all discovered documents, roles, ownership, exclusions, read limits,
|
|
206
|
+
semantic budgets and expected artifact reuse. Validation documents receive presence/reference
|
|
207
|
+
facts without model calls. `semantic.maxDocuments` and `maxSourceBytes` apply to semantic candidates;
|
|
208
|
+
traversal read limits apply to every read document. Broken/ambiguous links, incomplete reads, role
|
|
209
|
+
ambiguity or exceeded budgets stop new model work rather than silently trimming coverage.
|
|
210
|
+
|
|
211
|
+
Ownership gaps remain diagnostics. Reaching an owner, choosing an intent role or reading an
|
|
212
|
+
approved source never approves a model assertion. Plans/unclassified sources remain explicitly
|
|
213
|
+
labeled, and model facts remain inferred/unreviewed. Complete coverage means the configured
|
|
214
|
+
canonical links were followed, not that every product rule was found.
|
|
215
|
+
|
|
216
|
+
Built-in Codex can reuse unchanged artifacts when enabling traversal or editing its policy/read
|
|
217
|
+
limits. Role/owner metadata is assembled without rewriting those artifacts. Custom module
|
|
218
|
+
providers use a separate full-config cache. Snapshots bind the configuration and selection, while
|
|
219
|
+
old snapshots remain queryable. Draft overlays recompute reachability, invalidate changed sources
|
|
220
|
+
and owners, and label incomplete coverage without making model calls.
|
|
221
|
+
|
|
222
|
+
Traversal cannot be combined with `agentContext` or a direct programmatic source override; saved
|
|
223
|
+
impact queries still accept owner/task filters. `documents plan` remains a prospective operation;
|
|
224
|
+
its sidecar policy is not automatically adopted by hydration. See
|
|
225
|
+
[ADR 026](docs/ADR-026-traversal-hydration.md) for identity, compatibility and limits.
|
|
226
|
+
|
|
110
227
|
## SHACL validation and performance
|
|
111
228
|
|
|
229
|
+
Starting with **0.5.0**, identity preflight runs before ontology/RDF work.
|
|
230
|
+
`hydrate --json --quiet` reports conflicts using opaque references; `--validation-details` explicitly
|
|
231
|
+
includes local identities, producer versions and citations. Validation emits phase-boundary times
|
|
232
|
+
and graph counts, without a percentage or live heartbeat. Full SHACL remains required after a
|
|
233
|
+
passing preflight. See [ADR 021](docs/ADR-021-identity-preflight-and-validation-timing.md).
|
|
234
|
+
|
|
235
|
+
Version 0.5.0 also accepts `semantic.timeoutMs: 600000` for an approved ten-minute extraction
|
|
236
|
+
attempt; the default remains two minutes. See [provider limits and reuse](docs/PROVIDERS.md#limits-and-reuse)
|
|
237
|
+
before retrying with compatible cached artifacts.
|
|
238
|
+
|
|
112
239
|
Starting with 0.3.0, the toolkit indexes a temporary union to accelerate cold validation.
|
|
113
240
|
The toolkit uses JavaScript `rdf-validate-shacl` and an in-memory
|
|
114
241
|
N3 store. Each hydration validates the complete graph; semantic artifact reuse does not make
|
|
@@ -133,10 +260,14 @@ pnpm build
|
|
|
133
260
|
pnpm benchmark:shacl
|
|
134
261
|
```
|
|
135
262
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
263
|
+
The [T05 closeout](docs/ADR-027-validation-closeout.md) measures cold, repeated and changed inputs,
|
|
264
|
+
plus worker, exact-result-key and Rust prototypes. Direct full validation remains the 1.0 choice:
|
|
265
|
+
the 10,000-fact public cases measured about 2.9–5.7 seconds, with material memory use. These are
|
|
266
|
+
fixture measurements, not a private consumer capacity guarantee. The prototypes are development
|
|
267
|
+
tools, not runtime options; every hydration still performs full validation. Current progress reports
|
|
268
|
+
phase boundaries because synchronous work blocks same-thread timers. Reproduce the lifecycle study
|
|
269
|
+
from a development checkout with `pnpm benchmark:validation`; raw results and commands are linked
|
|
270
|
+
from the ADR.
|
|
140
271
|
|
|
141
272
|
## Development
|
|
142
273
|
|
|
@@ -204,12 +335,9 @@ Each committed JSON record names a scoped binding and exact producer/consumer fi
|
|
|
204
335
|
are cited candidate dependencies; they do not assert an approved policy or observed delivery.
|
|
205
336
|
|
|
206
337
|
Install the locally packed core and toolkit tarballs together. The installed commands are
|
|
207
|
-
`weftlet`, `weftlet-mcp`, and the compatible `context-graph` / `context-graph-mcp` aliases.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
npm install --save-dev "/path/to/weftlet/.release/weftlet-core-<version>.tgz" "/path/to/weftlet/.release/weftlet-toolkit-<version>.tgz"
|
|
211
|
-
npx weftlet init
|
|
212
|
-
```
|
|
338
|
+
`weftlet`, `weftlet-mcp`, and the compatible `context-graph` / `context-graph-mcp` aliases.
|
|
339
|
+
Use the [versioned installation examples](docs/RELEASING.md#inspecting-and-consuming-releases)
|
|
340
|
+
generated for this checkout/archive; then run `npx weftlet init`.
|
|
213
341
|
|
|
214
342
|
Pass `--config /absolute/path/context-graph.config.json`
|
|
215
343
|
to the CLI or set `CONTEXT_GRAPH_CONFIG` for MCP. No launcher rebuild is required for installed
|
|
@@ -238,6 +366,13 @@ ahead of repeated detail and shared-import context. Ranking changes ordering, no
|
|
|
238
366
|
the reachable scope. Responses identify the ranking version; after a ranking upgrade, restart
|
|
239
367
|
scans whose old continuation tokens are rejected. No snapshot refresh is needed for new ordering.
|
|
240
368
|
|
|
369
|
+
This source includes a [coverage reporting correction](docs/ADR-024-implementation-coverage.md)
|
|
370
|
+
for the next release: code relationships displayed under contracts also count as implementation
|
|
371
|
+
evidence. New reports identify `coverage.scope: "returned-page"` and `countsAreNonExclusive: true`.
|
|
372
|
+
Counts can overlap and describe returned evidence; they are not completeness percentages or proof
|
|
373
|
+
that behavior is correct. Document/model claims and test-only evidence do not establish production
|
|
374
|
+
implementation. The reporting fix works with saved snapshots without another hydration.
|
|
375
|
+
|
|
241
376
|
[Relative import evidence](docs/ADR-013-relative-module-requests.md) now scopes module requests
|
|
242
377
|
to the importing directory. An explicit refresh applies this extraction fix; saved snapshots
|
|
243
378
|
keep their original facts. These requests remain unresolved evidence, while SCIP supplies
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImpactScanRequest } from '@weftlet/core';
|
|
1
|
+
import type { DocumentSelectionRecord, ImpactScanRequest } from '@weftlet/core';
|
|
2
2
|
import { type SemanticInputIssue, type SemanticSelection } from '../extraction/semantic-sources.js';
|
|
3
3
|
import { type SemanticScope } from './semantic-scope.js';
|
|
4
4
|
export interface SemanticCacheAdoptionOptions {
|
|
@@ -28,6 +28,7 @@ export interface SemanticCacheAdoption {
|
|
|
28
28
|
readonly complete: boolean;
|
|
29
29
|
};
|
|
30
30
|
readonly records: readonly SemanticCacheAdoptionRecord[];
|
|
31
|
+
readonly documentSelection?: DocumentSelectionRecord;
|
|
31
32
|
readonly counts: Readonly<Record<SemanticCacheAdoptionStatus, number>>;
|
|
32
33
|
readonly selections: readonly SemanticSelection[];
|
|
33
34
|
readonly budgets: {
|
|
@@ -2,10 +2,10 @@ import { loadConfig } from '../configuration/config.js';
|
|
|
2
2
|
import { resolveSemanticStorageRoots, resolveStorageRoot, semanticCachePartition } from '../configuration/cache.js';
|
|
3
3
|
import { inspectSemanticCache } from '../extraction/semantic-cache.js';
|
|
4
4
|
import { semanticProviderIdentity } from '../extraction/semantic-identity.js';
|
|
5
|
-
import { selectSemanticInputs } from '../extraction/semantic-sources.js';
|
|
6
5
|
import { sha256, stableJson } from '../infrastructure/util.js';
|
|
7
6
|
import { GitRepository } from '../repository/git.js';
|
|
8
7
|
import { SemanticArtifactStore } from '../storage/storage.js';
|
|
8
|
+
import { selectHydrationInputs } from './hydration-inputs.js';
|
|
9
9
|
import { resolveSemanticScope } from './semantic-scope.js';
|
|
10
10
|
const problemStatuses = new Set(['corrupt', 'unavailable', 'conflict']);
|
|
11
11
|
function problem(inspection, source, location) {
|
|
@@ -67,6 +67,11 @@ async function publishCandidate(candidate, config, identity, current) {
|
|
|
67
67
|
return { ...candidate.record, status: 'adopted',
|
|
68
68
|
reason: 'Validated artifact is available in the current cache; the previous artifact is unchanged.' };
|
|
69
69
|
}
|
|
70
|
+
function previousArtifactRoot(repositoryRoot, config) {
|
|
71
|
+
// Traverse only the explicitly named module namespace; direct/Codex recovery retains legacy conflict checks.
|
|
72
|
+
return config.documentTraversal && config.semantic.provider === 'module'
|
|
73
|
+
? resolveSemanticStorageRoots(repositoryRoot, config).primary : resolveStorageRoot(repositoryRoot, config);
|
|
74
|
+
}
|
|
70
75
|
/** Explicitly adopts only committed-source artifacts from a compatible, named legacy profile. */
|
|
71
76
|
export async function adoptSemanticCache(configPath, options) {
|
|
72
77
|
const [loaded, previous] = await Promise.all([loadConfig(configPath), loadConfig(options.fromConfigPath)]);
|
|
@@ -81,10 +86,11 @@ export async function adoptSemanticCache(configPath, options) {
|
|
|
81
86
|
const ref = options.ref ?? 'HEAD';
|
|
82
87
|
const commitSha = await repository.resolveRef(ref);
|
|
83
88
|
const scope = await resolveSemanticScope(config, repository, commitSha, options.request);
|
|
84
|
-
const selection = await
|
|
89
|
+
const selection = await selectHydrationInputs(repository, commitSha, config, scope.selectors);
|
|
85
90
|
const issues = [...selection.issues];
|
|
86
91
|
const limited = scope.omittedDocuments.length > 0 || scope.ignoredSearchTerms > 0;
|
|
87
|
-
const complete = !limited && selection.selections.every((item) => item.status === 'matched')
|
|
92
|
+
const complete = !limited && selection.selections.every((item) => item.status === 'matched') &&
|
|
93
|
+
(selection.documentSelection?.complete ?? true);
|
|
88
94
|
if (limited)
|
|
89
95
|
issues.push({ code: 'selection-limited', severity: 'warning',
|
|
90
96
|
message: `Existing agent selection limits omitted ${scope.omittedDocuments.length} documents and ${scope.ignoredSearchTerms} search terms; adoption describes only the selected scope.`,
|
|
@@ -95,7 +101,7 @@ export async function adoptSemanticCache(configPath, options) {
|
|
|
95
101
|
const current = new SemanticArtifactStore(resolveSemanticStorageRoots(repositoryRoot, config).primary);
|
|
96
102
|
// Do not scan sibling profiles or infer ownership from an artifact key. The
|
|
97
103
|
// supplied old configuration proves the exact legacy location to inspect.
|
|
98
|
-
const old = new SemanticArtifactStore(
|
|
104
|
+
const old = new SemanticArtifactStore(previousArtifactRoot(repositoryRoot, previous.config));
|
|
99
105
|
const identity = semanticProviderIdentity(config.semantic);
|
|
100
106
|
for (const source of selection.sources) {
|
|
101
107
|
const candidate = await inspectCandidate(source, config.semantic, identity, old, current);
|
|
@@ -117,9 +123,10 @@ export async function adoptSemanticCache(configPath, options) {
|
|
|
117
123
|
ref, commitSha, configurationDigest: sha256(stableJson(config)),
|
|
118
124
|
previousConfigurationDigest: sha256(stableJson(previous.config)), dryRun,
|
|
119
125
|
ready: complete && !issues.some((issue) => issue.severity === 'error'), scope: { ...scope, complete },
|
|
126
|
+
...(selection.documentSelection ? { documentSelection: selection.documentSelection } : {}),
|
|
120
127
|
records, counts, selections: selection.selections, budgets: selection.budgets, issues,
|
|
121
128
|
assumptions: [
|
|
122
|
-
'Selection uses the same configured or bounded agent scope as hydration planning at the resolved commit; only expected keys in the explicitly named previous profile are inspected.',
|
|
129
|
+
'Selection uses the same configured, traversal or bounded agent scope as hydration planning at the resolved commit; only expected keys in the explicitly named previous profile are inspected.',
|
|
123
130
|
'Missing or incomplete previous artifacts need later extraction. Corrupt or conflicting complete artifacts are retained for diagnosis.',
|
|
124
131
|
'Adoption preserves original artifact identity and provenance; it does not validate or publish a current snapshot.',
|
|
125
132
|
'Artifacts are adopted independently; earlier valid copies remain available if a later artifact or storage operation fails.',
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type DocumentTraversalOptions, type DocumentTraversalReport } from '../extraction/document-traversal.js';
|
|
2
|
+
import { type DocumentClassification, type DocumentClassificationPolicy, type DocumentClassificationReport } from '../extraction/document-classification.js';
|
|
3
|
+
export interface DocumentCoverageOptions extends Omit<DocumentTraversalOptions, 'maxDocuments' | 'maxSourceBytes'> {
|
|
4
|
+
readonly ref?: string;
|
|
5
|
+
readonly documentPolicy?: DocumentClassificationPolicy;
|
|
6
|
+
}
|
|
7
|
+
export interface DocumentCoveragePlan extends Omit<DocumentTraversalReport, 'documents'> {
|
|
8
|
+
readonly schemaVersion: 1;
|
|
9
|
+
readonly kind: 'document-coverage-plan';
|
|
10
|
+
readonly mode: 'prospective';
|
|
11
|
+
readonly changesHydrationSelection: false;
|
|
12
|
+
readonly repositoryId: string;
|
|
13
|
+
readonly ref: string;
|
|
14
|
+
readonly commitSha: string;
|
|
15
|
+
readonly configurationDigest: string;
|
|
16
|
+
readonly coverageDigest: string;
|
|
17
|
+
/** Traversal and budget readiness only; classification is reported independently. */
|
|
18
|
+
readonly ready: boolean;
|
|
19
|
+
readonly classification: DocumentClassificationReport;
|
|
20
|
+
readonly documents: readonly (DocumentTraversalReport['documents'][number] & DocumentClassification & {
|
|
21
|
+
readonly role: 'semantic-document' | 'validation-evidence';
|
|
22
|
+
readonly extractionReview: 'unreviewed';
|
|
23
|
+
})[];
|
|
24
|
+
readonly excludedWorkingChanges: readonly string[];
|
|
25
|
+
readonly assumptions: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
/** Read committed links only. This does not initialize execution, inspect caches or change selection. */
|
|
28
|
+
export declare function planDocumentCoverage(configPath: string, options: DocumentCoverageOptions): Promise<DocumentCoveragePlan>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { loadConfig } from '../configuration/config.js';
|
|
2
|
+
import { GitRepository } from '../repository/git.js';
|
|
3
|
+
import { sha256, stableJson } from '../infrastructure/util.js';
|
|
4
|
+
import { traverseDocuments } from '../extraction/document-traversal.js';
|
|
5
|
+
import { classifyDocumentSources, parseDocumentClassificationPolicy } from '../extraction/document-classification.js';
|
|
6
|
+
function classifyKnownDocuments(paths, context, policy) {
|
|
7
|
+
// Traversal bounds reads, not its discovered frontier. Preserve every known path while each
|
|
8
|
+
// classifier call stays bounded; all batches see the same complete set of read owners.
|
|
9
|
+
const ordered = [...paths].sort();
|
|
10
|
+
const batchSize = 1000;
|
|
11
|
+
const first = classifyDocumentSources(ordered.slice(0, batchSize), context, policy);
|
|
12
|
+
const documents = [...first.documents];
|
|
13
|
+
const issues = [...first.issues];
|
|
14
|
+
for (let offset = batchSize; offset < ordered.length; offset += batchSize) {
|
|
15
|
+
const batch = classifyDocumentSources(ordered.slice(offset, offset + batchSize), context, policy);
|
|
16
|
+
documents.push(...batch.documents);
|
|
17
|
+
issues.push(...batch.issues);
|
|
18
|
+
}
|
|
19
|
+
return { policyDigest: first.policyDigest, documents, issues, complete: !issues.length };
|
|
20
|
+
}
|
|
21
|
+
/** Read committed links only. This does not initialize execution, inspect caches or change selection. */
|
|
22
|
+
export async function planDocumentCoverage(configPath, options) {
|
|
23
|
+
const { config, repositoryRoot } = await loadConfig(configPath);
|
|
24
|
+
const documentPolicy = parseDocumentClassificationPolicy(options.documentPolicy ?? { schemaVersion: 1 });
|
|
25
|
+
const repository = new GitRepository(repositoryRoot);
|
|
26
|
+
const ref = options.ref ?? 'HEAD';
|
|
27
|
+
const commitSha = await repository.resolveRef(ref);
|
|
28
|
+
const traversal = await traverseDocuments(repository, commitSha, {
|
|
29
|
+
entryPoints: options.entryPoints, roots: options.roots,
|
|
30
|
+
maxReadDocuments: options.maxReadDocuments, maxReadBytes: options.maxReadBytes,
|
|
31
|
+
maxDocumentBytes: options.maxDocumentBytes,
|
|
32
|
+
maxDocuments: config.semantic.maxDocuments ?? 8, maxSourceBytes: config.semantic.maxSourceBytes ?? 65_536,
|
|
33
|
+
});
|
|
34
|
+
const classification = classifyKnownDocuments(traversal.documents.map(document => document.path), {
|
|
35
|
+
approvedIntentSources: config.approvedIntentSources ?? [], evidenceRoots: config.evidenceRoots,
|
|
36
|
+
availableDocuments: traversal.documents.filter(document => document.status === 'read').map(document => document.path),
|
|
37
|
+
}, documentPolicy);
|
|
38
|
+
const classified = new Map(classification.documents.map(document => [document.path, document]));
|
|
39
|
+
const documents = traversal.documents.map(document => ({ ...document, ...classified.get(document.path),
|
|
40
|
+
role: classified.get(document.path).sourceRole === 'validation' ? 'validation-evidence' : 'semantic-document',
|
|
41
|
+
extractionReview: 'unreviewed' }));
|
|
42
|
+
return { ...traversal, documents, schemaVersion: 1, kind: 'document-coverage-plan', mode: 'prospective',
|
|
43
|
+
changesHydrationSelection: false, repositoryId: config.repositoryId, ref, commitSha,
|
|
44
|
+
configurationDigest: sha256(stableJson(config)), classification,
|
|
45
|
+
coverageDigest: sha256(stableJson({ commitSha, traversal, documents, classification })),
|
|
46
|
+
ready: traversal.coverage.complete && traversal.budgets.withinLimits,
|
|
47
|
+
excludedWorkingChanges: await repository.workingChanges(),
|
|
48
|
+
assumptions: [
|
|
49
|
+
'This is prospective document coverage, not the hydration execution plan. It changes no configuration or hydration inputs and estimates no cache reuse, model calls, tokens or cost.',
|
|
50
|
+
'Documents and link citations come from the resolved commit; configuration, document policy and excluded working changes describe current operation inputs.',
|
|
51
|
+
'Complete covers supported local document links inside the requested scope. External links, fragments and resolved non-document files are reported but not traversed; this does not prove complete product coverage.',
|
|
52
|
+
'Extraction budgets compare all discovered documents, including validation evidence. Safety limits can leave an explicit unread frontier; undiscovered descendants then remain unknown.',
|
|
53
|
+
'Ready describes traversal and budget checks only. Classification completeness is separate; unresolved roles or ownership are evidence gaps, not proven business-rule violations or approved intent.',
|
|
54
|
+
'Roles use explicit document policy and configured defaults. Ownership maps require a read, approved intent owner. Neither approval nor ownership transfers through links or approves individual assertions.',
|
|
55
|
+
'No provider, adapter, indexer, runtime source or graph validator was initialized. No cache, snapshot or source document was written.',
|
|
56
|
+
'Use hydrate --plan for current extraction inputs and cache estimates. The standalone document-evidence API is available; connecting classification and validation separation to hydration remains T07c.',
|
|
57
|
+
] };
|
|
58
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContextGraphConfig } from '../configuration/config.js';
|
|
2
|
+
import type { DocumentSelectionRecord, GraphFact } from '@weftlet/core';
|
|
3
|
+
import type { HydrationInputs } from './hydration-inputs.js';
|
|
4
|
+
/** Retain only unchanged, still-reachable assertions with unchanged source ownership. */
|
|
5
|
+
export declare function retainOverlayDocumentFact(fact: GraphFact, inputs: HydrationInputs | undefined, affected: ReadonlySet<string>): boolean;
|
|
6
|
+
export declare function overlayDocumentRoots(config: Pick<ContextGraphConfig, 'documentTraversal'>): readonly string[];
|
|
7
|
+
export declare function overlayDocumentManifest(selection?: DocumentSelectionRecord): {
|
|
8
|
+
documentSelection: DocumentSelectionRecord;
|
|
9
|
+
scope: readonly string[];
|
|
10
|
+
} | {
|
|
11
|
+
documentSelection?: undefined;
|
|
12
|
+
scope?: undefined;
|
|
13
|
+
};
|
|
14
|
+
export declare function overlayDocumentNotes(config: Pick<ContextGraphConfig, 'documentTraversal'>): readonly string[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { documentEvidenceExtractorIdentity } from '../extraction/document-evidence.js';
|
|
2
|
+
import { stableJson } from '../infrastructure/util.js';
|
|
3
|
+
/** Retain only unchanged, still-reachable assertions with unchanged source ownership. */
|
|
4
|
+
export function retainOverlayDocumentFact(fact, inputs, affected) {
|
|
5
|
+
if (!inputs?.documentSelection)
|
|
6
|
+
return true;
|
|
7
|
+
if (fact.extractor.id === documentEvidenceExtractorIdentity.id)
|
|
8
|
+
return false;
|
|
9
|
+
if (!/\.(?:md|mdx|txt)$/i.test(fact.provenance.path))
|
|
10
|
+
return true;
|
|
11
|
+
if (!inputs.documentSelection.complete)
|
|
12
|
+
return false;
|
|
13
|
+
const source = inputs.sources.find(source => source.path === fact.provenance.path);
|
|
14
|
+
const classification = inputs.documentEvidence?.classification.documents.find(document => document.path === fact.provenance.path);
|
|
15
|
+
return Boolean(source && classification && source.digest === fact.provenance.digest &&
|
|
16
|
+
fact.sourceRole === classification.sourceRole &&
|
|
17
|
+
fact.sourcePolicyDigest === inputs.documentSelection.policyDigest &&
|
|
18
|
+
stableJson(fact.sourceOwnership) === stableJson(classification.ownership) &&
|
|
19
|
+
!classification.ownership.ownerDocuments.some(path => affected.has(path)));
|
|
20
|
+
}
|
|
21
|
+
export function overlayDocumentRoots(config) {
|
|
22
|
+
return config.documentTraversal ? config.documentTraversal.roots ?? ['.'] : [];
|
|
23
|
+
}
|
|
24
|
+
export function overlayDocumentManifest(selection) {
|
|
25
|
+
return selection ? { documentSelection: selection, scope: selection.documentPaths } : {};
|
|
26
|
+
}
|
|
27
|
+
export function overlayDocumentNotes(config) {
|
|
28
|
+
return config.documentTraversal ? [
|
|
29
|
+
'Document traversal was recomputed from captured drafts. Changed/unreachable sources and changed owners invalidate prior semantic assertions; incomplete coverage invalidates all retained document assertions.',
|
|
30
|
+
] : [];
|
|
31
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ContextGraphConfig } from '../configuration/config.js';
|
|
2
2
|
export declare const graphAssemblyVersion = 7;
|
|
3
3
|
export declare const graphAssemblyIdentity = "standalone-graph-v7";
|
|
4
|
+
export declare function documentExtractionVersions(config?: Pick<ContextGraphConfig, 'documentTraversal'>): Readonly<Record<string, string>>;
|
|
4
5
|
/** Runtime expectations are separate from source/configuration identity and artifact reuse. */
|
|
5
|
-
export declare function requiredSnapshotExtractorVersions(config?: Pick<ContextGraphConfig, 'routingSources'>): Readonly<Record<string, string>>;
|
|
6
|
+
export declare function requiredSnapshotExtractorVersions(config?: Pick<ContextGraphConfig, 'routingSources' | 'documentTraversal'>): Readonly<Record<string, string>>;
|
|
6
7
|
export declare function incompatibleSnapshotExtractors(actual: Readonly<Record<string, string>> | undefined, expected: Readonly<Record<string, string>>): readonly string[];
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { repositoryContractExtractorIdentity, scipSymbolExtractorIdentity } from '../extraction/static.js';
|
|
2
2
|
import { routingExtractorIdentity } from '../extraction/routing.js';
|
|
3
|
+
import { documentEvidenceExtractorIdentity } from '../extraction/document-evidence.js';
|
|
4
|
+
import { documentSelectionIdentity } from './hydration-inputs.js';
|
|
3
5
|
export const graphAssemblyVersion = 7;
|
|
4
6
|
export const graphAssemblyIdentity = `standalone-graph-v${graphAssemblyVersion}`;
|
|
7
|
+
export function documentExtractionVersions(config) {
|
|
8
|
+
return config?.documentTraversal ? { 'document-selection': documentSelectionIdentity,
|
|
9
|
+
[documentEvidenceExtractorIdentity.id]: documentEvidenceExtractorIdentity.version } : {};
|
|
10
|
+
}
|
|
5
11
|
/** Runtime expectations are separate from source/configuration identity and artifact reuse. */
|
|
6
12
|
export function requiredSnapshotExtractorVersions(config) {
|
|
7
13
|
return { assembly: graphAssemblyIdentity,
|
|
14
|
+
...documentExtractionVersions(config),
|
|
8
15
|
[repositoryContractExtractorIdentity.id]: repositoryContractExtractorIdentity.version,
|
|
9
16
|
[scipSymbolExtractorIdentity.id]: scipSymbolExtractorIdentity.version,
|
|
10
17
|
...(config?.routingSources?.length ? { [routingExtractorIdentity.id]: routingExtractorIdentity.version } : {}),
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DocumentSelectionRecord, GraphFact } from '@weftlet/core';
|
|
2
|
+
import type { ContextGraphConfig } from '../configuration/config.js';
|
|
3
|
+
import type { GitRepository } from '../repository/git.js';
|
|
4
|
+
import { selectSemanticInputs } from '../extraction/semantic-sources.js';
|
|
5
|
+
import { extractDocumentEvidence } from '../extraction/document-evidence.js';
|
|
6
|
+
export declare const documentSelectionIdentity = "document-selection-v1";
|
|
7
|
+
export type DocumentEvidence = Awaited<ReturnType<typeof extractDocumentEvidence>>;
|
|
8
|
+
export type HydrationInputs = Awaited<ReturnType<typeof selectSemanticInputs>> & {
|
|
9
|
+
readonly documentEvidence?: DocumentEvidence;
|
|
10
|
+
readonly documentSelection?: DocumentSelectionRecord;
|
|
11
|
+
};
|
|
12
|
+
/** One committed selection for preview, hydration and explicit cache adoption. No execution dependencies. */
|
|
13
|
+
export declare function selectHydrationInputs(repository: GitRepository, commitSha: string, config: ContextGraphConfig, selectors?: readonly string[]): Promise<HydrationInputs>;
|
|
14
|
+
/** Assembly metadata is deliberately outside immutable provider artifacts. */
|
|
15
|
+
export declare function classifyHydratedFacts(facts: readonly GraphFact[], evidence?: DocumentEvidence): readonly GraphFact[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { selectSemanticInputs } from '../extraction/semantic-sources.js';
|
|
2
|
+
import { extractDocumentEvidence } from '../extraction/document-evidence.js';
|
|
3
|
+
import { sha256, stableJson } from '../infrastructure/util.js';
|
|
4
|
+
export const documentSelectionIdentity = 'document-selection-v1';
|
|
5
|
+
/** One committed selection for preview, hydration and explicit cache adoption. No execution dependencies. */
|
|
6
|
+
export async function selectHydrationInputs(repository, commitSha, config, selectors = config.semanticSources) {
|
|
7
|
+
if (!config.documentTraversal)
|
|
8
|
+
return selectSemanticInputs(repository, commitSha, selectors, config.semantic);
|
|
9
|
+
const context = { repositoryRoot: repository.root, repositoryId: config.repositoryId,
|
|
10
|
+
ref: commitSha, commitSha, snapshotId: commitSha, changedPaths: [], deletedPaths: [], renamedPaths: {} };
|
|
11
|
+
const evidence = await extractDocumentEvidence(repository, context, {
|
|
12
|
+
...config.documentTraversal, documentPolicy: config.documentTraversal.policy,
|
|
13
|
+
// Traversal reads have their own limits; semantic budgets are applied after role exclusion below.
|
|
14
|
+
maxDocuments: 10_000, maxSourceBytes: 4 * 1024 * 1024,
|
|
15
|
+
approvedIntentSources: config.approvedIntentSources, evidenceRoots: config.evidenceRoots,
|
|
16
|
+
});
|
|
17
|
+
const classified = new Map(evidence.classification.documents.map(document => [document.path, document]));
|
|
18
|
+
const excluded = [];
|
|
19
|
+
const semanticPaths = [];
|
|
20
|
+
for (const document of evidence.traversal.documents) {
|
|
21
|
+
const classification = classified.get(document.path);
|
|
22
|
+
if (document.status !== 'read')
|
|
23
|
+
excluded.push({ path: document.path, reason: 'unread' });
|
|
24
|
+
else if (classification?.roleStatus === 'ambiguous')
|
|
25
|
+
excluded.push({ path: document.path, reason: 'ambiguous-role' });
|
|
26
|
+
else if (classification?.sourceRole === 'validation')
|
|
27
|
+
excluded.push({ path: document.path, reason: 'validation' });
|
|
28
|
+
else
|
|
29
|
+
semanticPaths.push(document.path);
|
|
30
|
+
}
|
|
31
|
+
const selection = await selectSemanticInputs(repository, commitSha, semanticPaths, config.semantic);
|
|
32
|
+
// Prospective traversal budgets count every document. Execution budgets count only semantic inputs.
|
|
33
|
+
const issues = [...selection.issues, ...evidence.traversal.issues.filter(issue => !['document-budget', 'source-byte-budget'].includes(issue.code)), ...evidence.classification.issues.map(issue => ({ ...issue, severity: issue.code === 'role-ambiguous' ? 'error' : issue.severity }))];
|
|
34
|
+
const record = { version: 1, policyDigest: evidence.classification.policyDigest,
|
|
35
|
+
complete: evidence.traversal.coverage.complete && !issues.some(issue => issue.severity === 'error'),
|
|
36
|
+
entryPoints: evidence.traversal.entryPoints, roots: evidence.traversal.roots,
|
|
37
|
+
documentPaths: evidence.traversal.documents.map(document => document.path), semanticPaths, excluded };
|
|
38
|
+
const digest = sha256(stableJson({ identity: documentSelectionIdentity, commitSha, record,
|
|
39
|
+
traversal: evidence.traversal, classification: evidence.classification }));
|
|
40
|
+
return { ...selection, issues, documentEvidence: evidence, documentSelection: { ...record, digest } };
|
|
41
|
+
}
|
|
42
|
+
/** Assembly metadata is deliberately outside immutable provider artifacts. */
|
|
43
|
+
export function classifyHydratedFacts(facts, evidence) {
|
|
44
|
+
if (!evidence)
|
|
45
|
+
return facts;
|
|
46
|
+
const classified = new Map(evidence.classification.documents.map(document => [document.path, document]));
|
|
47
|
+
return facts.map(fact => {
|
|
48
|
+
const document = classified.get(fact.provenance.path);
|
|
49
|
+
if (!document)
|
|
50
|
+
throw new Error('Document assembly fact has no classified source');
|
|
51
|
+
const metadata = { sourceRole: document.sourceRole, sourceOwnership: document.ownership,
|
|
52
|
+
sourcePolicyDigest: evidence.classification.policyDigest, sourceAuthority: document.sourceAuthority };
|
|
53
|
+
return { ...fact, ...metadata, id: sha256(stableJson({ fact: fact.id, metadata, identity: documentSelectionIdentity })) };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -2,6 +2,8 @@ import type { ImpactScanRequest } from '@weftlet/core';
|
|
|
2
2
|
import { type SemanticCacheInspection } from '../extraction/semantic-cache.js';
|
|
3
3
|
import { type SemanticInputIssue, type SemanticSelection } from '../extraction/semantic-sources.js';
|
|
4
4
|
import { type SemanticScope } from './semantic-scope.js';
|
|
5
|
+
import { type DocumentEvidence } from './hydration-inputs.js';
|
|
6
|
+
import type { DocumentSelectionRecord, SourceDocumentRole, SourceOwnership } from '@weftlet/core';
|
|
5
7
|
export interface HydrationPlanOptions {
|
|
6
8
|
readonly ref?: string;
|
|
7
9
|
readonly forceSemantic?: boolean;
|
|
@@ -21,6 +23,9 @@ export interface HydrationPlanDocument {
|
|
|
21
23
|
readonly approvedBy: readonly string[];
|
|
22
24
|
readonly extractionReview: 'unreviewed';
|
|
23
25
|
readonly cache: Omit<SemanticCacheInspection, 'artifact'>;
|
|
26
|
+
readonly sourceRole?: SourceDocumentRole;
|
|
27
|
+
readonly sourceOwnership?: SourceOwnership;
|
|
28
|
+
readonly sourcePolicyDigest?: string;
|
|
24
29
|
}
|
|
25
30
|
export interface HydrationPlan {
|
|
26
31
|
readonly schemaVersion: 1;
|
|
@@ -34,6 +39,8 @@ export interface HydrationPlan {
|
|
|
34
39
|
readonly complete: boolean;
|
|
35
40
|
};
|
|
36
41
|
readonly documents: readonly HydrationPlanDocument[];
|
|
42
|
+
readonly documentSelection?: DocumentSelectionRecord;
|
|
43
|
+
readonly documentCoverage?: Pick<DocumentEvidence, 'traversal' | 'classification'>;
|
|
37
44
|
readonly selections: readonly SemanticSelection[];
|
|
38
45
|
readonly budgets: {
|
|
39
46
|
readonly maxDocuments: number;
|
|
@@ -4,9 +4,9 @@ import { matchesRepositoryGlob } from '../repository/glob.js';
|
|
|
4
4
|
import { createSemanticArtifactStore } from './semantic-artifact-store.js';
|
|
5
5
|
import { inspectSemanticCache } from '../extraction/semantic-cache.js';
|
|
6
6
|
import { semanticProviderIdentity } from '../extraction/semantic-identity.js';
|
|
7
|
-
import { selectSemanticInputs } from '../extraction/semantic-sources.js';
|
|
8
7
|
import { sha256, stableJson } from '../infrastructure/util.js';
|
|
9
8
|
import { resolveSemanticScope } from './semantic-scope.js';
|
|
9
|
+
import { selectHydrationInputs } from './hydration-inputs.js';
|
|
10
10
|
import { semanticSourceId } from '../extraction/semantic-diagnostics.js';
|
|
11
11
|
async function describeDocument(source, selections, config, evidencePaths, store, forceSemantic = false) {
|
|
12
12
|
const inspection = forceSemantic
|
|
@@ -29,11 +29,12 @@ export async function planHydration(configPath, options = {}) {
|
|
|
29
29
|
const ref = options.ref ?? 'HEAD';
|
|
30
30
|
const commitSha = await repository.resolveRef(ref);
|
|
31
31
|
const scope = await resolveSemanticScope(config, repository, commitSha, options.request);
|
|
32
|
-
const selection = await
|
|
32
|
+
const selection = await selectHydrationInputs(repository, commitSha, config, scope.selectors);
|
|
33
33
|
const issues = [...selection.issues];
|
|
34
34
|
const { omittedDocuments, ignoredSearchTerms } = scope;
|
|
35
35
|
const limited = omittedDocuments.length > 0 || ignoredSearchTerms > 0;
|
|
36
|
-
const complete = !limited && selection.selections.every((item) => item.status === 'matched')
|
|
36
|
+
const complete = !limited && selection.selections.every((item) => item.status === 'matched') &&
|
|
37
|
+
(selection.documentSelection?.complete ?? true);
|
|
37
38
|
if (limited)
|
|
38
39
|
issues.push({ code: 'selection-limited', severity: 'warning',
|
|
39
40
|
message: `Existing agent selection limits omitted ${omittedDocuments.length} documents and ${ignoredSearchTerms} search terms; this plan describes only the selected scope.`,
|
|
@@ -42,7 +43,11 @@ export async function planHydration(configPath, options = {}) {
|
|
|
42
43
|
const evidencePaths = new Set(await repository.listFilesAt(commitSha, config.evidenceRoots));
|
|
43
44
|
const documents = [];
|
|
44
45
|
for (const source of selection.sources) {
|
|
45
|
-
const
|
|
46
|
+
const described = await describeDocument(source, selection.selections, config, evidencePaths, store, options.forceSemantic);
|
|
47
|
+
const classification = selection.documentEvidence?.classification.documents.find(item => item.path === source.path);
|
|
48
|
+
const document = classification ? { ...described, role: 'semantic-document',
|
|
49
|
+
sourceAuthority: classification.sourceAuthority, sourceRole: classification.sourceRole,
|
|
50
|
+
sourceOwnership: classification.ownership, sourcePolicyDigest: selection.documentEvidence.classification.policyDigest } : described;
|
|
46
51
|
const { cache } = document;
|
|
47
52
|
if (cache.status === 'corrupt' || cache.status === 'unavailable')
|
|
48
53
|
issues.push({
|
|
@@ -56,9 +61,17 @@ export async function planHydration(configPath, options = {}) {
|
|
|
56
61
|
configurationDigest: sha256(stableJson(config)), ready: complete && !issues.some((item) => item.severity === 'error'),
|
|
57
62
|
scope: { ...scope, complete },
|
|
58
63
|
documents, selections: selection.selections, budgets: selection.budgets,
|
|
64
|
+
...(selection.documentSelection ? { documentSelection: selection.documentSelection,
|
|
65
|
+
documentCoverage: { traversal: selection.documentEvidence.traversal, classification: selection.documentEvidence.classification } } : {}),
|
|
59
66
|
estimates: { reusableArtifacts: count('hit'), extractions: count('miss', 'forced'), unknownArtifacts: count('corrupt', 'unavailable') },
|
|
60
67
|
issues, excludedWorkingChanges: await repository.workingChanges(),
|
|
61
|
-
assumptions: [
|
|
68
|
+
assumptions: selection.documentSelection ? [
|
|
69
|
+
'Traversal uses committed entry points and canonical local links. All discovered documents and exclusions are reported; only semantic candidates count against extraction budgets.',
|
|
70
|
+
'Validation documents retain deterministic presence/references without model extraction. Role ambiguity and incomplete coverage block model work; ownership gaps remain explicit diagnostics.',
|
|
71
|
+
'Classification and owner mappings never approve assertions. Model facts remain inferred/unreviewed, including from approved sources.',
|
|
72
|
+
'Readiness checks selection, budgets and readable caches. It does not initialize providers, adapters, credentials, indexing, runtime sources or graph validation.',
|
|
73
|
+
'Built-in Codex artifacts retain their extraction identity. Traversal module providers use a separate conservative cache; no cache or snapshot was written.',
|
|
74
|
+
] : [
|
|
62
75
|
'Sources come from the resolved commit; configuration and cache are read from the current local environment.',
|
|
63
76
|
'Estimates require unchanged source, configuration, provider contract and readable artifacts; concurrent changes can invalidate them.',
|
|
64
77
|
'Document and per-document UTF-8 byte limits apply to all selected documents, including cache hits; no token or monetary estimate is made.',
|
|
@@ -14,6 +14,8 @@ export interface HydrationOptions {
|
|
|
14
14
|
readonly forceSemantic?: boolean;
|
|
15
15
|
readonly snapshotSuffix?: string;
|
|
16
16
|
readonly requireClean?: boolean;
|
|
17
|
+
/** Explicit local diagnostics may disclose repository identities, producers and citations. */
|
|
18
|
+
readonly validationDetails?: boolean;
|
|
17
19
|
readonly semanticSources?: readonly string[];
|
|
18
20
|
readonly runtimeEvidenceRevision?: RuntimeEvidenceRevision;
|
|
19
21
|
}
|