@weftlet/toolkit 0.3.0 → 0.5.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 +26 -1
- package/dist/application/application.js +7 -4
- package/dist/application/cache-adoption.d.ts +43 -0
- package/dist/application/cache-adoption.js +129 -0
- package/dist/application/extraction-identity.d.ts +6 -0
- package/dist/application/extraction-identity.js +15 -0
- package/dist/application/hydration-failure.d.ts +41 -0
- package/dist/application/hydration-failure.js +43 -0
- package/dist/application/hydration-plan.d.ts +4 -7
- package/dist/application/hydration-plan.js +7 -15
- package/dist/application/hydrator.d.ts +5 -5
- package/dist/application/hydrator.js +37 -52
- package/dist/application/overlay.d.ts +3 -1
- package/dist/application/overlay.js +13 -4
- package/dist/application/saved-evidence.d.ts +6 -3
- package/dist/application/saved-evidence.js +7 -1
- package/dist/application/semantic-artifact-store.d.ts +4 -0
- package/dist/application/semantic-artifact-store.js +7 -0
- package/dist/application/semantic-run.d.ts +32 -0
- package/dist/application/semantic-run.js +111 -0
- package/dist/application/semantic-scope.d.ts +13 -0
- package/dist/application/semantic-scope.js +12 -0
- package/dist/application/snapshot-checks.d.ts +2 -1
- package/dist/application/snapshot-checks.js +8 -1
- package/dist/configuration/cache.d.ts +6 -0
- package/dist/configuration/cache.js +18 -0
- package/dist/configuration/config.js +1 -1
- package/dist/extraction/document.js +1 -1
- package/dist/extraction/providers.js +10 -3
- package/dist/extraction/repository-nodes.d.ts +2 -3
- package/dist/extraction/repository-nodes.js +5 -11
- package/dist/extraction/routing.d.ts +1 -1
- package/dist/extraction/routing.js +3 -6
- package/dist/extraction/semantic-cache.d.ts +1 -0
- package/dist/extraction/semantic-cache.js +9 -2
- package/dist/extraction/semantic-diagnostics.d.ts +9 -0
- package/dist/extraction/semantic-diagnostics.js +15 -0
- package/dist/extraction/semantic.d.ts +5 -1
- package/dist/extraction/semantic.js +39 -6
- package/dist/extraction/static.d.ts +13 -5
- package/dist/extraction/static.js +8 -15
- package/dist/governance/governance.js +11 -7
- package/dist/graph/identity-preflight.d.ts +57 -0
- package/dist/graph/identity-preflight.js +71 -0
- package/dist/graph/query.js +2 -0
- package/dist/graph/rdf.d.ts +4 -1
- package/dist/graph/rdf.js +10 -6
- package/dist/graph/validation-progress.d.ts +14 -0
- package/dist/graph/validation-progress.js +18 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/interfaces/cli.js +52 -22
- package/dist/storage/storage.d.ts +7 -1
- package/dist/storage/storage.js +15 -3
- package/dist/visualization/visualization.js +1 -0
- package/docs/ADR-016-hydration-preview.md +1 -1
- package/docs/ADR-017-shacl-validation-union.md +1 -1
- package/docs/ADR-018-operational-semantic-cache.md +100 -0
- package/docs/ADR-019-semantic-failure-diagnostics.md +82 -0
- package/docs/ADR-020-canonical-physical-file-producers.md +97 -0
- package/docs/ADR-021-identity-preflight-and-validation-timing.md +81 -0
- package/docs/PROVIDERS.md +58 -1
- package/docs/RELEASE-1.0-PLAN.md +100 -34
- package/docs/RELEASING.md +4 -2
- package/docs/ROADMAP.md +40 -15
- package/docs/VALIDATION.md +351 -4
- package/docs/extraction-manifest.json +50 -23
- package/package.json +2 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Phase boundaries remain observable even when an operation blocks same-thread timers. */
|
|
2
|
+
export async function measureValidationPhase(phase, counts, onProgress, operation) {
|
|
3
|
+
const started = performance.now();
|
|
4
|
+
const emit = (status) => onProgress?.({
|
|
5
|
+
phase, status, ...counts, elapsedMs: Math.max(0, Math.round(performance.now() - started)),
|
|
6
|
+
});
|
|
7
|
+
emit('started');
|
|
8
|
+
let result;
|
|
9
|
+
try {
|
|
10
|
+
result = await operation();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
emit('failed');
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
emit('completed');
|
|
17
|
+
return result;
|
|
18
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,3 +10,8 @@ export * from "./application/overlay.js";
|
|
|
10
10
|
export * from "./graph/rdf.js";
|
|
11
11
|
export * from "./extraction/providers.js";
|
|
12
12
|
export * from './application/hydration-plan.js';
|
|
13
|
+
export * from './application/cache-adoption.js';
|
|
14
|
+
export * from './application/hydration-failure.js';
|
|
15
|
+
export * from './extraction/semantic-diagnostics.js';
|
|
16
|
+
export * from './graph/identity-preflight.js';
|
|
17
|
+
export * from './graph/validation-progress.js';
|
package/dist/index.js
CHANGED
|
@@ -11,3 +11,8 @@ export * from "./application/overlay.js";
|
|
|
11
11
|
export * from "./graph/rdf.js";
|
|
12
12
|
export * from "./extraction/providers.js";
|
|
13
13
|
export * from './application/hydration-plan.js';
|
|
14
|
+
export * from './application/cache-adoption.js';
|
|
15
|
+
export * from './application/hydration-failure.js';
|
|
16
|
+
export * from './extraction/semantic-diagnostics.js';
|
|
17
|
+
export * from './graph/identity-preflight.js';
|
|
18
|
+
export * from './graph/validation-progress.js';
|
package/dist/interfaces/cli.js
CHANGED
|
@@ -16,6 +16,9 @@ import { diagnoseSetup } from "./doctor.js";
|
|
|
16
16
|
import { runInit } from "./init.js";
|
|
17
17
|
import { loadConfig } from "../configuration/config.js";
|
|
18
18
|
import { planHydration } from '../application/hydration-plan.js';
|
|
19
|
+
import { adoptSemanticCache } from '../application/cache-adoption.js';
|
|
20
|
+
import { SemanticHydrationError } from '../application/hydration-failure.js';
|
|
21
|
+
import { GraphIdentityConflictError } from '../graph/identity-preflight.js';
|
|
19
22
|
function valueAfter(args, name) {
|
|
20
23
|
const index = args.indexOf(name);
|
|
21
24
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -59,7 +62,7 @@ function formatHydrationPlan(plan) {
|
|
|
59
62
|
`Source/cache/budget checks: ${readiness}`,
|
|
60
63
|
];
|
|
61
64
|
for (const document of plan.documents) {
|
|
62
|
-
lines.push(`- ${JSON.stringify(document.path)}: ${document.bytes} bytes, ${document.lines} lines; ${document.role}; source ${document.sourceAuthority}, extraction ${document.extractionReview}; cache ${document.cache.status}; selected by ${document.selectedBy.map((selector) => JSON.stringify(selector)).join(', ')}`);
|
|
65
|
+
lines.push(`- ${JSON.stringify(document.path)} [${document.sourceId}]: ${document.bytes} bytes, ${document.lines} lines; ${document.role}; source ${document.sourceAuthority}, extraction ${document.extractionReview}; cache ${document.cache.status}; selected by ${document.selectedBy.map((selector) => JSON.stringify(selector)).join(', ')}`);
|
|
63
66
|
}
|
|
64
67
|
for (const selection of plan.selections.filter((item) => item.status !== 'matched')) {
|
|
65
68
|
lines.push(`Selection ${JSON.stringify(selection.selector)}: ${selection.status}`);
|
|
@@ -80,7 +83,7 @@ function formatHydrationPlan(plan) {
|
|
|
80
83
|
async function main() {
|
|
81
84
|
const args = process.argv.slice(2);
|
|
82
85
|
if (args.includes('--help') || !args.length) {
|
|
83
|
-
process.stdout.write('weftlet init|config show|config validate|doctor|hydrate|overlay|impact scan|sparql|validate|govern|visualize|diagnostics show|invariant check|clean-compare|ontology compile\nUse --config <file>; queries accept --snapshot <id>. impact scan accepts --changed-file, --capability, --max-facts, --max-depth, --continuation.\nhydrate --plan [--json] [--ref <commit>] [--force-semantic] previews scope, cache and budgets without model calls or graph writes. Preview readiness is advisory and does not add a hydration gate.\ninit [--yes] [--directory <project>] [--config <file>] [--repository-id <id>] [--code-root <path>] [--semantic-source <path>] [--evidence-root <path>] [--model <name>] [--no-gitignore]\nSource flags may be repeated. init never overwrites an existing config. See README.md for examples.\n');
|
|
86
|
+
process.stdout.write('weftlet init|config show|config validate|doctor|hydrate|cache adopt|overlay|impact scan|sparql|validate|govern|visualize|diagnostics show|invariant check|clean-compare|ontology compile\nUse --config <file>; queries accept --snapshot <id>. impact scan accepts --changed-file, --capability, --max-facts, --max-depth, --continuation.\nhydrate --plan [--json] [--ref <commit>] [--force-semantic] previews scope, cache and budgets without model calls or graph writes. Preview readiness is advisory and does not add a hydration gate.\nhydrate --json --quiet emits structured semantic failures on stderr with no progress lines; failure stdout stays empty. hydrate --plan maps opaque source IDs to local document paths.\nhydrate|overlay --validation-details explicitly includes local node/fact identities, extractor names and source citations in identity-conflict errors; default reports use opaque references. This flag writes no diagnostic file. Use --json --quiet for structured identity-conflict stderr and empty failure stdout. Validation timings report phase boundaries, not a live heartbeat or percentage.\ncache adopt --from-config <previous.json> [--config <current.json>] [--ref <commit>] [--dry-run] returns JSON and copies only validated compatible artifacts, without model calls or snapshot writes. --dry-run performs no cache writes. Agent configurations accept the same --owner-doc, --task and --capability selection as hydrate.\ninit [--yes] [--directory <project>] [--config <file>] [--repository-id <id>] [--code-root <path>] [--semantic-source <path>] [--evidence-root <path>] [--model <name>] [--no-gitignore]\nSource flags may be repeated. init never overwrites an existing config. See README.md for examples.\n');
|
|
84
87
|
return;
|
|
85
88
|
}
|
|
86
89
|
if (args[0] === 'init') {
|
|
@@ -113,6 +116,20 @@ async function main() {
|
|
|
113
116
|
return;
|
|
114
117
|
}
|
|
115
118
|
const configPath = valueAfter(args, '--config') ?? defaultConfigPath();
|
|
119
|
+
if (args[0] === 'cache') {
|
|
120
|
+
const fromConfigPath = valueAfter(args, '--from-config');
|
|
121
|
+
if (args[1] !== 'adopt' || !fromConfigPath || fromConfigPath.startsWith('--')) {
|
|
122
|
+
throw new Error('Usage: weftlet cache adopt --from-config <previous.json> [--config <current.json>] [--ref <commit>] [--dry-run]');
|
|
123
|
+
}
|
|
124
|
+
const result = await adoptSemanticCache(configPath, {
|
|
125
|
+
fromConfigPath, ref: valueAfter(args, '--ref') ?? 'HEAD', dryRun: args.includes('--dry-run'),
|
|
126
|
+
request: impactRequestFromArgs(args),
|
|
127
|
+
});
|
|
128
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
129
|
+
if (!result.ready)
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
116
133
|
if (args[0] === 'doctor') {
|
|
117
134
|
process.stdout.write(`${JSON.stringify(await diagnoseSetup(configPath), null, 2)}\n`);
|
|
118
135
|
return;
|
|
@@ -155,7 +172,7 @@ async function main() {
|
|
|
155
172
|
const base = valueAfter(args, '--base-snapshot');
|
|
156
173
|
if (!base)
|
|
157
174
|
throw new Error('overlay requires --base-snapshot <committed snapshot ID>');
|
|
158
|
-
const result = await buildWorkingOverlay(application.repository, application.config, application.snapshotStore, application.storageRoot, base, valueAfter(args, '--agent'));
|
|
175
|
+
const result = await buildWorkingOverlay(application.repository, application.config, application.snapshotStore, application.storageRoot, base, valueAfter(args, '--agent'), { validationDetails: args.includes('--validation-details') });
|
|
159
176
|
process.stdout.write(`${JSON.stringify(result.manifest, null, 2)}\n`);
|
|
160
177
|
return;
|
|
161
178
|
}
|
|
@@ -163,24 +180,32 @@ async function main() {
|
|
|
163
180
|
const controller = new AbortController();
|
|
164
181
|
const cancel = () => controller.abort();
|
|
165
182
|
process.once('SIGINT', cancel);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
try {
|
|
184
|
+
const ref = valueAfter(args, '--ref') ?? 'HEAD';
|
|
185
|
+
const scope = await application.scopeResolver?.resolve(impactRequestFromArgs(args), ref);
|
|
186
|
+
const result = await application.hydrator.hydrate({
|
|
187
|
+
ref: scope?.commitSha ?? ref,
|
|
188
|
+
headName: scope?.headName ?? application.headName,
|
|
189
|
+
semanticSources: scope?.semanticSources,
|
|
190
|
+
forceSemantic: args.includes('--force-semantic'),
|
|
191
|
+
validationDetails: args.includes('--validation-details'),
|
|
192
|
+
signal: controller.signal,
|
|
193
|
+
onProgress: args.includes('--quiet') ? undefined : (event) => process.stderr.write(`[context-graph] ${event.phase}${event.total === undefined ? '' : ` ${event.completed}/${event.total}`}` +
|
|
194
|
+
`${event.status === undefined ? '' : ` ${event.status}`}` +
|
|
195
|
+
`${event.factCount === undefined ? '' : ` facts=${event.factCount}`}${event.nodeCount === undefined ? '' : ` nodes=${event.nodeCount}`}` +
|
|
196
|
+
`${event.sourceId === undefined ? '' : ` ${event.sourceId}`}${event.elapsedMs === undefined ? '' : ` ${event.elapsedMs} ms`}\n`),
|
|
197
|
+
});
|
|
198
|
+
process.stdout.write(`${JSON.stringify({
|
|
199
|
+
snapshotId: result.snapshot.manifest.snapshotId,
|
|
200
|
+
commitSha: result.snapshot.manifest.commitSha,
|
|
201
|
+
contentDigest: result.snapshot.manifest.contentDigest,
|
|
202
|
+
semanticExtracted: result.semanticExtracted,
|
|
203
|
+
semanticReused: result.semanticReused,
|
|
204
|
+
}, null, 2)}\n`);
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
process.removeListener('SIGINT', cancel);
|
|
208
|
+
}
|
|
184
209
|
return;
|
|
185
210
|
}
|
|
186
211
|
if (command === 'clean-compare') {
|
|
@@ -236,6 +261,11 @@ async function main() {
|
|
|
236
261
|
throw new Error('Usage: weftlet hydrate|clean-compare|impact scan|diagnostics show --snapshot <id>|invariant check|ontology compile|visualize --output <file.html|file.dot|file.svg>');
|
|
237
262
|
}
|
|
238
263
|
main().catch((error) => {
|
|
239
|
-
process.stderr.write(`${error instanceof
|
|
264
|
+
process.stderr.write(`${error instanceof GraphIdentityConflictError
|
|
265
|
+
? process.argv.includes('--json') || process.argv.includes('--validation-details')
|
|
266
|
+
? JSON.stringify(error.report, null, 2) : error.message
|
|
267
|
+
: error instanceof SemanticHydrationError
|
|
268
|
+
? process.argv.includes('--json') ? JSON.stringify(error.report, null, 2) : error.message
|
|
269
|
+
: error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`);
|
|
240
270
|
process.exitCode = 1;
|
|
241
271
|
});
|
|
@@ -9,7 +9,13 @@ export declare class FileSnapshotStore implements SnapshotStore {
|
|
|
9
9
|
}
|
|
10
10
|
export declare class SemanticArtifactStore {
|
|
11
11
|
private readonly root;
|
|
12
|
-
|
|
12
|
+
private readonly legacyRoots;
|
|
13
|
+
constructor(root: string, legacyRoots?: readonly string[]);
|
|
13
14
|
read(key: string): Promise<SemanticArtifact | undefined>;
|
|
15
|
+
/** Only explicitly supplied roots are consulted; never enumerate other consumers' profiles. */
|
|
16
|
+
readEntry(key: string): Promise<{
|
|
17
|
+
artifact: SemanticArtifact;
|
|
18
|
+
origin: 'primary' | 'legacy';
|
|
19
|
+
} | undefined>;
|
|
14
20
|
write(artifact: SemanticArtifact): Promise<void>;
|
|
15
21
|
}
|
package/dist/storage/storage.js
CHANGED
|
@@ -87,11 +87,23 @@ export class FileSnapshotStore {
|
|
|
87
87
|
}
|
|
88
88
|
export class SemanticArtifactStore {
|
|
89
89
|
root;
|
|
90
|
-
|
|
90
|
+
legacyRoots;
|
|
91
|
+
constructor(root, legacyRoots = []) {
|
|
91
92
|
this.root = root;
|
|
93
|
+
this.legacyRoots = legacyRoots;
|
|
94
|
+
}
|
|
95
|
+
async read(key) {
|
|
96
|
+
return (await this.readEntry(key))?.artifact;
|
|
92
97
|
}
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
/** Only explicitly supplied roots are consulted; never enumerate other consumers' profiles. */
|
|
99
|
+
async readEntry(key) {
|
|
100
|
+
const filename = `${safeKey(key)}.json`;
|
|
101
|
+
for (const [index, root] of [this.root, ...this.legacyRoots].entries()) {
|
|
102
|
+
const artifact = await readJson(join(root, 'artifacts', 'semantic', filename));
|
|
103
|
+
if (artifact !== undefined)
|
|
104
|
+
return { artifact, origin: index === 0 ? 'primary' : 'legacy' };
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
95
107
|
}
|
|
96
108
|
async write(artifact) {
|
|
97
109
|
const path = join(this.root, 'artifacts', 'semantic', `${safeKey(artifact.key)}.json`);
|
|
@@ -394,6 +394,7 @@ export function renderContextPackHtml(pack, sourceUrlTemplate) {
|
|
|
394
394
|
<strong>${pack.snapshot.overlayDigest ? 'DRAFT overlay' : pack.evidenceState?.stale ? 'HISTORICAL evidence' : pack.evidenceState ? 'Saved evidence at current commit' : 'Saved evidence — current checkout not assessed'}</strong>
|
|
395
395
|
<p>Configuration: ${escapeXml(pack.snapshot.configurationDigest ?? 'unknown')}; ${pack.evidenceState ? (pack.evidenceState.configurationMatches ? 'matches current configuration' : 'configuration mismatch') : 'configuration match unknown'}.
|
|
396
396
|
Scope: ${escapeXml(pack.snapshot.scope?.join(', ') ?? 'unknown')}.
|
|
397
|
+
Extraction compatibility: ${pack.evidenceState?.extractionCompatible === undefined ? 'not assessed' : pack.evidenceState.extractionCompatible ? 'current' : `refresh required (${escapeXml(pack.evidenceState.incompatibleExtractors?.join(', ') ?? 'unknown versions')})`}.
|
|
397
398
|
Excluded working paths: ${pack.evidenceState?.excludedWorkingChanges.length ?? 'unknown'}.
|
|
398
399
|
${pack.snapshot.overlayDigest ? `Overlay freshness: ${escapeXml(pack.evidenceState?.overlayFreshness ?? 'unknown')}.` : ''}
|
|
399
400
|
This view does not validate the current diff.</p>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ADR-016: Read-only hydration planning
|
|
2
2
|
|
|
3
|
-
Status: accepted and implemented
|
|
3
|
+
Status: accepted and implemented in 0.3.0; absent from 0.2.1.
|
|
4
4
|
See [validation](VALIDATION.md) for recorded publication evidence.
|
|
5
5
|
|
|
6
6
|
## Problem
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ADR-017: Validate a temporary RDF union without changing canonical evidence
|
|
2
2
|
|
|
3
|
-
Status: accepted and implemented
|
|
3
|
+
Status: accepted and implemented in the focused 0.3.0 release; absent from 0.2.1.
|
|
4
4
|
See [validation](VALIDATION.md) for checks and recorded publication evidence.
|
|
5
5
|
|
|
6
6
|
## Problem and measured mechanism
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# ADR-018: Preserve Codex artifacts across operational configuration changes
|
|
2
|
+
|
|
3
|
+
Status: accepted and shipped in 0.4.0; release and validation evidence is recorded in
|
|
4
|
+
[validation](VALIDATION.md).
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
With `storageScope: "user"`, the storage profile includes the entire configuration and checkout
|
|
9
|
+
path. Increasing a timeout therefore selected a different directory even though the built-in
|
|
10
|
+
Codex artifact key already excluded that timeout. A partially completed run could lose access
|
|
11
|
+
to reusable work without any source or extraction-contract change.
|
|
12
|
+
|
|
13
|
+
Custom provider modules present a different boundary: they receive the entire semantic
|
|
14
|
+
configuration and may use it to affect their output. Their identities must remain conservative.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
Keep `resolveStorageRoot`, snapshot profiles, snapshot IDs and full configuration digests unchanged.
|
|
19
|
+
For built-in Codex with user storage, use a separate semantic-artifact partition. Its identity
|
|
20
|
+
includes the resolved checkout and full configuration except these five semantic controls:
|
|
21
|
+
|
|
22
|
+
| Setting | Why it can share successful Codex artifacts |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `timeoutMs` | Bounds execution; it does not change the prompt or model arguments |
|
|
25
|
+
| `retries` | Limits retries of supported transient failures |
|
|
26
|
+
| `concurrency` | Schedules independent source extractions |
|
|
27
|
+
| `maxDocuments` | Bounds the selected workload |
|
|
28
|
+
| `maxSourceBytes` | Bounds each source; it never truncates its contents |
|
|
29
|
+
|
|
30
|
+
Document and byte limits still apply before hydration, including when every artifact is cached.
|
|
31
|
+
Changing a limit does not waive it. Model/reasoning settings, prompt/schema/extractor/adapter/
|
|
32
|
+
ontology identities, confidence/unresolved policy, authentication descriptors, source identity
|
|
33
|
+
and bytes continue to invalidate reuse through their existing artifact keys and/or partition.
|
|
34
|
+
Unknown configuration fields remain identity inputs. Credential environment values are not read
|
|
35
|
+
or added to the cache partition.
|
|
36
|
+
|
|
37
|
+
The new user-cache layout is `~/.cache/context-graph/semantic-artifacts-v1/<partition>/artifacts/semantic/`.
|
|
38
|
+
The partition uses a full SHA-256 digest. Different checkouts, repository IDs, namespaces and
|
|
39
|
+
non-operational configurations remain separate. Workspace storage retains its existing paths
|
|
40
|
+
and behavior; it already allowed built-in Codex reuse after these operational changes. Modules
|
|
41
|
+
retain their full semantic-config identity and their existing storage profiles. Sharing a custom
|
|
42
|
+
workspace storage directory remains an explicit operator choice, not a new global cache feature.
|
|
43
|
+
|
|
44
|
+
Artifact keys and output digests retain the 0.2.1/0.3.0 contract, including the repository-document
|
|
45
|
+
identity policy introduced in 0.2.1. No incompatible 0.2.0 artifact is reinterpreted as current.
|
|
46
|
+
Source approval and assertion review remain distinct; this change never approves an assertion.
|
|
47
|
+
|
|
48
|
+
## Legacy recovery without model work
|
|
49
|
+
|
|
50
|
+
The planner and hydrator use the same store factory. It may read the exact legacy user profile
|
|
51
|
+
derived from the current full configuration after checking the new primary store. A corrupt or
|
|
52
|
+
unreadable primary entry stops reuse; a valid legacy entry does not mask it. Planning remains
|
|
53
|
+
read-only. Hydration can atomically retain a validated legacy artifact in the new partition, then
|
|
54
|
+
revalidate the retained entry to handle concurrent winners. Original files, artifact identities,
|
|
55
|
+
source provenance and raw provider output remain intact.
|
|
56
|
+
|
|
57
|
+
Legacy profile directories contain no reliable checkout/configuration ownership manifest, and an
|
|
58
|
+
interrupted run may have no snapshot. Consequently, the toolkit never scans sibling profiles for
|
|
59
|
+
a matching key. If settings were already changed, the old location cannot safely be inferred.
|
|
60
|
+
|
|
61
|
+
The explicit `cache adopt --from-config <previous.json>` command handles that case without
|
|
62
|
+
providers, authentication probes, indexing, ontology compilation, adapters or snapshot writes.
|
|
63
|
+
Both configurations must resolve to the same checkout and have the same non-operational
|
|
64
|
+
partition identity. Keep the exact old configuration in its original configuration directory.
|
|
65
|
+
Relocation is safe only when its original, unchanged `repositoryRoot` still resolves to the same
|
|
66
|
+
checkout (for example, an absolute root). Do not edit that field to compensate for relocation:
|
|
67
|
+
it is part of the old profile identity. Preserve the original field values and omissions.
|
|
68
|
+
|
|
69
|
+
Adoption resolves a committed ref and uses the same configured/agent selection as the hydration
|
|
70
|
+
preview. It looks up only expected keys in the exact old profile, checks the complete artifact
|
|
71
|
+
contract and output digest, and copies valid candidates atomically. `--dry-run` performs no writes.
|
|
72
|
+
Reports identify reused/adopted/planned/missing/corrupt/unavailable/conflicting entries, configured
|
|
73
|
+
budgets and scope omissions. They omit source bodies, raw provider output and configuration values.
|
|
74
|
+
|
|
75
|
+
Recovery is per artifact: valid copies can complete even if another entry is corrupt or conflicts.
|
|
76
|
+
The report records partial progress and exits unsuccessfully for problems or incomplete scope.
|
|
77
|
+
Missing artifacts are ordinary future extraction work. Corrupt complete artifacts are retained
|
|
78
|
+
for diagnosis; they require an explicit forced refresh or operator repair, not automatic overwrite.
|
|
79
|
+
Incomplete temporary files are not published artifacts and do not satisfy a cache lookup.
|
|
80
|
+
|
|
81
|
+
Concurrent writers use immutable publication. Different outputs under one key are reported as
|
|
82
|
+
conflicts; a matching `outputDigest` field alone is insufficient to accept malformed metadata.
|
|
83
|
+
Explicit forced extraction still creates a separate revision and preserves existing artifacts.
|
|
84
|
+
|
|
85
|
+
## Freshness and limits
|
|
86
|
+
|
|
87
|
+
Semantic reuse does not reuse a snapshot's validation result, skip SCIP or SHACL, or let old
|
|
88
|
+
configuration evidence satisfy current validation. A timeout change still changes the snapshot's
|
|
89
|
+
full configuration digest and user storage profile. Saved evidence remains available under its
|
|
90
|
+
original configuration; this increment does not consolidate historical snapshot directories.
|
|
91
|
+
|
|
92
|
+
The current module-provider contract does not promise operational independence. Supporting that
|
|
93
|
+
requires a separate tested contract, not silently dropping fields from a provider's identity.
|
|
94
|
+
Credential rotation under an unchanged environment-variable name is not detected by this cache;
|
|
95
|
+
credentials are neither cache contents nor cache-identity inputs. Existing filesystem access
|
|
96
|
+
controls and the configured storage location remain the security boundary.
|
|
97
|
+
|
|
98
|
+
Validation uses public fixtures, deterministic Codex runners and installed TypeScript indexing.
|
|
99
|
+
Live semantic quality and private consumer acceptance remain separate. See the
|
|
100
|
+
[1.0 plan](RELEASE-1.0-PLAN.md) for timeout diagnostics and document coverage follow-ups.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# ADR-019: Safe semantic failure diagnostics and settled progress
|
|
2
|
+
|
|
3
|
+
Status: shipped in 0.4.0; validation and publication are recorded in [validation](VALIDATION.md).
|
|
4
|
+
This decision does not change extraction identity.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
A generic timeout does not identify which source failed, how much work survived, or how to
|
|
9
|
+
resume. Concurrent workers can also cancel each other: reporting the last error can hide the
|
|
10
|
+
initiating timeout, and reporting before active writes finish can undercount retained artifacts.
|
|
11
|
+
Arbitrary provider exceptions and abort reasons may contain private input.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
Keep semantic-run scheduling and reporting in `application/semantic-run.ts`, separate from graph
|
|
16
|
+
assembly. Record the first source failure before aborting siblings, stop scheduling queued sources,
|
|
17
|
+
and wait for active workers to settle before constructing `SemanticHydrationError.report`.
|
|
18
|
+
The report has a versioned kind, safe code/category, phase, committed SHA, configuration digest,
|
|
19
|
+
elapsed time and scope, effective timeout and its scope, final counts, and recovery guidance.
|
|
20
|
+
|
|
21
|
+
Completion means a validated artifact was retained or successfully reused. A write already in
|
|
22
|
+
progress can finish after cancellation and remains a completion. A provider result returned after
|
|
23
|
+
abort is rejected before validation/publication. Late storage failures remain failures, not sibling
|
|
24
|
+
cancellations. Cancellation between sources has phase `semantic-scheduling`, no failing source ID,
|
|
25
|
+
and run elapsed time; it does not relabel successfully retained artifacts as cancelled.
|
|
26
|
+
|
|
27
|
+
Counts have these meanings:
|
|
28
|
+
|
|
29
|
+
- `completed = extracted + reused`.
|
|
30
|
+
- `total = completed + failed + cancelled + notStarted` after active workers settle.
|
|
31
|
+
- `remaining = total - completed`; this includes failures, cancellations and queued work. It is
|
|
32
|
+
not a promise about the number of model calls required by a future run.
|
|
33
|
+
|
|
34
|
+
Known provider timeouts, cancellations, unavailable infrastructure, process exits and invalid
|
|
35
|
+
output remain distinct. Configured unresolved-mapping and confidence rejections retain separate
|
|
36
|
+
`unresolved` and `low-confidence` codes and remain extraction gaps. Their acceptance criteria are
|
|
37
|
+
unchanged. Unknown extraction exceptions become `provider-failure`, without an
|
|
38
|
+
invented diagnosis. Cache read/write failures have a separate code; invalid extraction validation
|
|
39
|
+
is an extraction gap. Module loading/export/identity problems are unavailable infrastructure.
|
|
40
|
+
No raw exception, cause, provider output, prompt, credential or source path is copied into the
|
|
41
|
+
report. These diagnostics are not approved intent or evidence that a product rule was violated.
|
|
42
|
+
|
|
43
|
+
The CLI prints safe errors and progress on stderr, leaving stdout for successful results.
|
|
44
|
+
`hydrate --json --quiet` produces a JSON semantic failure report on stderr. The JSON contract
|
|
45
|
+
covers the semantic-source run; configuration, repository, indexing and graph validation errors
|
|
46
|
+
retain their existing interfaces. SIGINT listeners are removed on both success and failure.
|
|
47
|
+
The saved-evidence MCP interface still performs no hydration and writes only protocol messages
|
|
48
|
+
to stdout. Trusted module code must itself avoid logging private inputs; this is not a sandbox.
|
|
49
|
+
|
|
50
|
+
## Source correlation and timeout meaning
|
|
51
|
+
|
|
52
|
+
A domain-separated SHA-256 of repository ID and stable semantic ID gives each source an opaque
|
|
53
|
+
`sourceId`. `hydrate --plan` explicitly maps that ID to its local path. The ID is stable across
|
|
54
|
+
retries and source edits when the stable semantic ID stays the same; renames without a declared
|
|
55
|
+
stable ID may change it. It is a correlation aid, not anonymization, encryption or an access
|
|
56
|
+
boundary. Do not publish the local preview without reviewing its paths and other metadata.
|
|
57
|
+
This ID never enters artifact keys, prompts, facts or snapshot configuration digests.
|
|
58
|
+
|
|
59
|
+
For source failures, elapsed time includes cache checks, authentication, provider attempts and
|
|
60
|
+
retries through failure. Codex's configured limit is per attempt; authentication has a separate
|
|
61
|
+
bounded status check. Module execution has one deadline covering import, factory and extraction.
|
|
62
|
+
The report distinguishes these scopes rather than presenting the limit as an end-to-end deadline.
|
|
63
|
+
No timeout default, retry policy, extraction contract or cache version changes here.
|
|
64
|
+
|
|
65
|
+
## Recovery and limits
|
|
66
|
+
|
|
67
|
+
Failures do not reach graph publication. Prior snapshots and completed artifacts remain intact.
|
|
68
|
+
Use the same configuration, committed ref and scope in the no-model preview to inspect current
|
|
69
|
+
reuse before retrying without `--force-semantic`. T03 preserves compatible built-in Codex artifacts
|
|
70
|
+
across supported operational changes; legacy recovery requires the exact previous configuration.
|
|
71
|
+
Custom modules retain conservative full-configuration identity. Completed forced revisions are
|
|
72
|
+
retained but are not automatically adopted by an ordinary rerun or a new forced revision.
|
|
73
|
+
|
|
74
|
+
The toolkit waits for built-in subprocess termination or the module wrapper's bounded promise.
|
|
75
|
+
It cannot forcibly terminate arbitrary trusted in-process module code. Cancellation before source
|
|
76
|
+
selection and outside semantic processing uses the existing safe cancellation error without
|
|
77
|
+
per-source counts. Phase boundaries remain the progress signal; no synchronous SHACL heartbeat,
|
|
78
|
+
incremental validator or invented percentage is introduced by this milestone.
|
|
79
|
+
|
|
80
|
+
Public deterministic tests cover failures, cancellation races, durable-write completion, counts,
|
|
81
|
+
privacy, reuse, unchanged snapshot heads, source mapping and installed CLI behavior. They do not
|
|
82
|
+
claim private consumer acceptance or live-provider semantic quality.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# ADR-020: One physical-file policy for deterministic producers and adapters
|
|
2
|
+
|
|
3
|
+
Status: upstream fix shipped in 0.4.0; release evidence and pending consumer adapter/hydration
|
|
4
|
+
acceptance are recorded separately in [validation](VALIDATION.md).
|
|
5
|
+
|
|
6
|
+
## Reported defect and ownership
|
|
7
|
+
|
|
8
|
+
The consumer's bounded replay of installed 0.3.0 extractors reported 120 conflicting file IDs:
|
|
9
|
+
34 from the neutral contract extractor alone, 57 from its local framework adapter alone, and
|
|
10
|
+
29 from both. Actual file/SCIP extraction classified spec/test files as `Evidence`; contract
|
|
11
|
+
consumers and local framework nodes could classify those same physical IDs as `Component`.
|
|
12
|
+
The consumer isolated a neutral file-plus-contract pair that failed strict SHACL single-kind
|
|
13
|
+
validation. This is an extraction identity defect, not conflicting product intent.
|
|
14
|
+
|
|
15
|
+
Upstream owns the neutral policy and producers. The consumer owns its framework call sites and
|
|
16
|
+
their tests. This work uses public fixtures; it does not reproduce all private IDs, modify the
|
|
17
|
+
consumer repository, patch installed packages or claim successful consumer hydration.
|
|
18
|
+
|
|
19
|
+
## Public contract
|
|
20
|
+
|
|
21
|
+
Move the existing pure `repositoryFileNode(path)` implementation into `@weftlet/core` and export
|
|
22
|
+
it publicly. Its module imports only the `GraphNode` type; core gains no runtime package
|
|
23
|
+
dependencies. Keep the toolkit's internal re-export for compatibility, but adapters should use:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { repositoryFileNode } from '@weftlet/core';
|
|
27
|
+
|
|
28
|
+
const file = {
|
|
29
|
+
...repositoryFileNode(path),
|
|
30
|
+
attributes: { /* adapter-specific evidence metadata */ },
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The caller supplies a repository-relative path in its canonical spelling. Existing mappings stay
|
|
35
|
+
unchanged: `.md`, `.mdx` and `.txt` use `document:<path>`/`Document`; `.spec.<extension>` and
|
|
36
|
+
`.test.<extension>` use `component:file:<path>`/`Evidence`; other physical files use that file
|
|
37
|
+
prefix and `Component`. Matching ignores extension case but preserves path spelling. This is not
|
|
38
|
+
filesystem resolution, universal test detection, proof of existence or approved intent. Do not
|
|
39
|
+
rewrite business concepts, contract identities or architectural modules into physical-file IDs.
|
|
40
|
+
|
|
41
|
+
The producer audit is explicit:
|
|
42
|
+
|
|
43
|
+
| Producer | Change |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Neutral file extractor | Replace duplicated kind logic; preserve source/index attributes |
|
|
46
|
+
| SCIP symbols | Replace duplicated kind logic; preserve symbols, sites and citations |
|
|
47
|
+
| Contract consumers | Replace hard-coded Component; retain conceptual contract and evidence IDs |
|
|
48
|
+
| Document linker | Import the public factory; existing owner/reference behavior stays intact |
|
|
49
|
+
| Routing | Replace duplicated mapping; document endpoints now join document identities |
|
|
50
|
+
| Governance | Use the factory for dependency and membership files and query lookup; retain module/layer concepts |
|
|
51
|
+
| Semantic normalization | Use the shared factory for its existing document-only normalization; see the boundary below |
|
|
52
|
+
|
|
53
|
+
Facts are retained, including test files with mocked client calls, DI and decorators. We do not
|
|
54
|
+
suppress test evidence, rename conflicting IDs, weaken kind cardinality or change source/assertion
|
|
55
|
+
authority. Graphs and all working overlays require strict SHACL before publication; overlay
|
|
56
|
+
validation no longer depends on routing being configured.
|
|
57
|
+
|
|
58
|
+
## Identity, saved evidence and artifacts
|
|
59
|
+
|
|
60
|
+
Contract extraction advances from 1.1.0 to 1.2.0; routing and SCIP fact extraction from 1.0.0 to
|
|
61
|
+
1.1.0; governance analyzer from 2 to 3. The SCIP indexer/tool version is unchanged. Committed
|
|
62
|
+
assembly becomes `standalone-graph-v7`, with `graph-v7`, contract and SCIP fact identity included
|
|
63
|
+
in snapshot IDs. Overlay IDs/metadata also bind assembly, contract and SCIP fact identity,
|
|
64
|
+
so rebuilding identical captured bytes cannot replace an older overlay. Governance records its
|
|
65
|
+
analyzer identity in both snapshot digest inputs and metadata.
|
|
66
|
+
|
|
67
|
+
Current validation requires matching assembly, contract and SCIP fact versions, plus routing version when
|
|
68
|
+
configured. Missing metadata is not a pass. Final checks reject old versions without initiating
|
|
69
|
+
hydration. Historical saved queries still return the original facts, with extraction compatibility
|
|
70
|
+
reported separately from commit/configuration/working-overlay freshness in JSON, Markdown and
|
|
71
|
+
the viewer. Saved queries remain ineligible to validate a current diff.
|
|
72
|
+
|
|
73
|
+
The physical policy itself was already correct. Its semantic cache identity stays at version 1;
|
|
74
|
+
provider/prompt/artifact keys and original artifact bytes remain unchanged. The original snapshot
|
|
75
|
+
and any compatible semantic artifacts remain available. A fresh graph must still be assembled,
|
|
76
|
+
indexed and validated. Reuse does not imply that an old graph passes current validation.
|
|
77
|
+
|
|
78
|
+
## Semantic and consumer boundary
|
|
79
|
+
|
|
80
|
+
The reported 120 conflicts were reproduced entirely by deterministic producers. This fix does
|
|
81
|
+
not rewrite semantic caches or force paid re-extraction to hide that defect. Existing semantic
|
|
82
|
+
normalization continues correcting repository document IDs/kinds only. Non-document model kinds
|
|
83
|
+
remain asserted, inferred and unreviewed; an incompatible model assertion still fails strict
|
|
84
|
+
SHACL. A broader interpretation migration would need separate provenance/OML parity tests and
|
|
85
|
+
an explicit cache/assembly decision. It is not silently bundled into this deterministic fix.
|
|
86
|
+
|
|
87
|
+
After upgrading both packages to the reviewed public release, the consumer must change every
|
|
88
|
+
physical-file node emitted by its framework adapter to the public factory and version that
|
|
89
|
+
adapter's extractor deliberately. Add actual adapter regressions for Prisma/DI/decorator-bearing
|
|
90
|
+
spec/test files composed with neutral file facts. Do not change semantic provider/prompt policy
|
|
91
|
+
versions merely to perform this deterministic adapter migration. Preview compatible artifact reuse,
|
|
92
|
+
then run full hydration and repeat acceptance against the committed adapter update.
|
|
93
|
+
|
|
94
|
+
Public upstream tests compose actual committed-source extractors, real TypeScript indexing,
|
|
95
|
+
document and routing links and a public adapter-shaped fixture. They assert strict SHACL,
|
|
96
|
+
provenance, confidence, authority, stable conceptual identities, saved-byte preservation and
|
|
97
|
+
version guards. They do not establish the private adapter's acceptance or semantic quality.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# ADR-021: Early identity conflicts and honest validation phase timing
|
|
2
|
+
|
|
3
|
+
Status: implemented in development source after 0.4.0. Publication and consumer acceptance
|
|
4
|
+
are separate checkpoints in [validation](VALIDATION.md). This is the bounded T05a increment.
|
|
5
|
+
|
|
6
|
+
## Decision
|
|
7
|
+
|
|
8
|
+
Before ontology compilation, invariant evaluation or RDF construction, scan every assembled
|
|
9
|
+
fact's subject and object identity for multiple kinds. The scan covers semantic, document,
|
|
10
|
+
static, adapter, routing and runtime facts, including conceptual identities. Working overlays
|
|
11
|
+
run the same check over retained and newly extracted facts before RDF construction/publication.
|
|
12
|
+
No fact, kind, ID, citation or authority is changed or discarded by the check.
|
|
13
|
+
This runs after semantic/static extraction; it is separate from no-model `hydrate --plan`.
|
|
14
|
+
|
|
15
|
+
`inspectGraphIdentities(facts, { repositoryId, includeDetails? })` returns a report;
|
|
16
|
+
`assertGraphIdentities` throws `GraphIdentityConflictError` on conflicts. Both are public toolkit
|
|
17
|
+
exports. A passing report has `passed: true` and **`shaclValidated: false`**. Consistent kinds
|
|
18
|
+
alone do not establish canonical classification, correct intent, valid citations or conformance.
|
|
19
|
+
The existing full RDF/SHACL path and shapes remain mandatory for successful publication. Direct
|
|
20
|
+
`RdfEvidenceGraph.validate()` and the saved `validate` command still run all checks and return
|
|
21
|
+
their existing verdict format. There is no validation cache, incremental validator or backend change.
|
|
22
|
+
|
|
23
|
+
The two-pass scan is linear in fact occurrences. The common conflict-free path creates no
|
|
24
|
+
per-evidence diagnostic records. On failure it reports every conflicting identity and occurrence,
|
|
25
|
+
including both ends of a self-reference, repeated fact IDs and late conflicts. Counts are complete;
|
|
26
|
+
there is no hidden document, hop or diagnostic cutoff. Reports retain input indices and side so
|
|
27
|
+
duplicate assertion IDs cannot conceal a producer's occurrence.
|
|
28
|
+
|
|
29
|
+
## Privacy and attribution
|
|
30
|
+
|
|
31
|
+
There was no general configurable diagnostic privacy policy. This increment therefore makes
|
|
32
|
+
local detail an explicit invocation option, without adding an extraction/configuration field.
|
|
33
|
+
Default reports contain repository-scoped opaque node, fact, source and extractor references,
|
|
34
|
+
counts and recognized kind names. Unknown kind strings are hashed as well. References correlate
|
|
35
|
+
records; they are not encryption or proof that a low-entropy identifier cannot be guessed.
|
|
36
|
+
|
|
37
|
+
`hydrate --json --quiet` emits a typed identity-failure report on stderr with empty stdout.
|
|
38
|
+
Use `--validation-details` on `hydrate` or `overlay` only when local identities and citations
|
|
39
|
+
may be displayed. That option includes exact node/fact IDs, extractor identity/version, citation
|
|
40
|
+
path/lines/digest/commit, confidence and the original optional authority/review fields. It does
|
|
41
|
+
not include labels, node attributes, source text, prompts or raw provider output. Absent authority
|
|
42
|
+
fields stay absent; source approval is never promoted into assertion approval.
|
|
43
|
+
|
|
44
|
+
The programmatic equivalent is `HydrationOptions.validationDetails` or the overlay's final
|
|
45
|
+
options argument. Detail changes do not enter snapshot, provider or semantic-cache identities.
|
|
46
|
+
The error message stays safe even when its report includes explicitly requested local details.
|
|
47
|
+
No diagnostic file is written automatically. Existing non-identity SHACL errors retain their
|
|
48
|
+
existing detailed behavior; this is not a claim that every command/error has been redacted.
|
|
49
|
+
|
|
50
|
+
## Timing and failure preservation
|
|
51
|
+
|
|
52
|
+
Hydration reports started/completed/failed boundaries and elapsed wall time for identity
|
|
53
|
+
preflight, RDF construction, union construction and full SHACL. Counts describe graph size,
|
|
54
|
+
not validator completion. A completed SHACL phase means the validator returned, including a
|
|
55
|
+
nonconforming verdict. `RdfEvidenceGraph.validate({ onProgress })` exposes its union/SHACL phases.
|
|
56
|
+
|
|
57
|
+
The synchronous JavaScript work can block same-thread timers. These events are not heartbeats,
|
|
58
|
+
percentages, new timeout controls or interruptible worker execution. Worker isolation remains a
|
|
59
|
+
separate decision. The public profiling harness records preflight and validation phase timings
|
|
60
|
+
alongside its existing construction, resource and runtime measurements.
|
|
61
|
+
|
|
62
|
+
Failure preserves completed semantic artifacts and prior snapshots/heads. Correcting and
|
|
63
|
+
versioning an adapter still requires a fresh assembly and full validation, but compatible
|
|
64
|
+
semantic artifacts can be reused. This preflight does not rewrite cached model assertions or
|
|
65
|
+
choose an authoritative business rule. Evidence disagreements must be resolved at their owner.
|
|
66
|
+
|
|
67
|
+
No extraction/assembly version changes are needed: accepted graph facts, cache identities,
|
|
68
|
+
RDF serialization and conformance constraints are unchanged. The check rejects an existing
|
|
69
|
+
single-kind violation earlier; it does not make old snapshots satisfy current validation.
|
|
70
|
+
|
|
71
|
+
## Evidence and remaining work
|
|
72
|
+
|
|
73
|
+
Tests cover full cross-source attribution, conceptual and physical nodes, exact authority,
|
|
74
|
+
default privacy, late conflicts, duplicates/self-references, immutable artifacts/snapshots,
|
|
75
|
+
corrected retries and non-kind failures that still reach full SHACL. CLI and packed-consumer
|
|
76
|
+
cases use actual TypeScript SCIP and public adapters. Existing positive/negative named-dataset
|
|
77
|
+
SHACL equivalence tests remain unchanged except for an additional timing/parity case.
|
|
78
|
+
|
|
79
|
+
Broader T05 work remains: worker-based progress/cancellation, repeated/changed-input performance
|
|
80
|
+
evaluation, and evidence-driven decisions about conformance-result reuse or incremental/native
|
|
81
|
+
backends. This increment does not infer private consumer performance from public fixtures.
|