@weftlet/toolkit 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/application/agent-context.d.ts +3 -1
- package/dist/application/agent-context.js +15 -6
- package/dist/application/hydration-plan.d.ts +57 -0
- package/dist/application/hydration-plan.js +79 -0
- package/dist/application/hydrator.js +9 -15
- package/dist/extraction/providers.js +2 -2
- package/dist/extraction/semantic-cache.d.ts +12 -0
- package/dist/extraction/semantic-cache.js +59 -0
- package/dist/extraction/semantic-identity.d.ts +7 -0
- package/dist/extraction/semantic-identity.js +29 -0
- package/dist/extraction/semantic-sources.d.ts +27 -0
- package/dist/extraction/semantic-sources.js +35 -0
- package/dist/extraction/semantic.js +11 -21
- package/dist/graph/rdf.d.ts +1 -1
- package/dist/graph/rdf.js +13 -28
- package/dist/graph/shacl-shapes.d.ts +5 -0
- package/dist/graph/shacl-shapes.js +27 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interfaces/cli.js +47 -3
- package/dist/repository/git.d.ts +1 -1
- package/dist/repository/git.js +5 -1
- package/docs/ADR-016-hydration-preview.md +91 -0
- package/docs/ADR-017-shacl-validation-union.md +102 -0
- package/docs/RELEASE-1.0-PLAN.md +96 -29
- package/docs/RELEASING.md +17 -6
- package/docs/ROADMAP.md +27 -5
- package/docs/VALIDATION.md +133 -3
- package/docs/WEFTLET-2.0-PLAN.md +9 -8
- package/docs/extraction-manifest.json +21 -10
- package/package.json +3 -2
package/dist/graph/rdf.js
CHANGED
|
@@ -1,39 +1,16 @@
|
|
|
1
1
|
import { QueryEngine } from '@comunica/query-sparql';
|
|
2
|
-
import { DataFactory,
|
|
2
|
+
import { DataFactory, Store, Writer } from 'n3';
|
|
3
3
|
import SHACLValidator from 'rdf-validate-shacl';
|
|
4
4
|
import { contextPackEvidenceAuthority } from "./authority.js";
|
|
5
5
|
import { stableJson } from "../infrastructure/util.js";
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
7
|
+
import { CG, RDF, XSD, evidenceShapes } from './shacl-shapes.js';
|
|
8
|
+
const { namedNode: iri, literal } = DataFactory;
|
|
9
|
+
export { CG } from './shacl-shapes.js';
|
|
11
10
|
export const nodeIri = (id) => `urn:context-graph:node:${encodeURIComponent(id)}`;
|
|
12
11
|
export const factIri = (id) => `urn:context-graph:fact:${encodeURIComponent(id)}`;
|
|
13
12
|
const engine = new QueryEngine();
|
|
14
13
|
const SparqlParser = createRequire(import.meta.url)('sparqljs').Parser;
|
|
15
|
-
const shapes = new Parser().parse(`
|
|
16
|
-
@prefix cg: <${CG}>.
|
|
17
|
-
@prefix rdf: <${RDF}>.
|
|
18
|
-
@prefix sh: <http://www.w3.org/ns/shacl#>.
|
|
19
|
-
@prefix xsd: <${XSD}>.
|
|
20
|
-
cg:FactShape a sh:NodeShape; sh:targetClass rdf:Statement;
|
|
21
|
-
sh:property [ sh:path cg:record; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string ];
|
|
22
|
-
sh:property [ sh:path rdf:subject; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
23
|
-
sh:property [ sh:path rdf:predicate; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
24
|
-
sh:property [ sh:path rdf:object; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
25
|
-
sh:property [ sh:path cg:authority; sh:minCount 1; sh:maxCount 1;
|
|
26
|
-
sh:in ("declared" "implemented" "validated" "observed" "inferred" "draft") ];
|
|
27
|
-
sh:property [ sh:path cg:path; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
28
|
-
sh:property [ sh:path cg:commit; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
29
|
-
sh:property [ sh:path cg:sourceDigest; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
30
|
-
sh:property [ sh:path cg:startLine; sh:minCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
31
|
-
sh:property [ sh:path cg:endLine; sh:minCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
32
|
-
sh:property [ sh:path cg:confidence; sh:minCount 1; sh:datatype xsd:decimal; sh:minInclusive 0; sh:maxInclusive 1 ];
|
|
33
|
-
sh:property [ sh:path cg:extractor; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ].
|
|
34
|
-
cg:NodeShape a sh:NodeShape; sh:targetClass cg:Node;
|
|
35
|
-
sh:property [ sh:path cg:kind; sh:minCount 1; sh:maxCount 1 ].
|
|
36
|
-
`);
|
|
37
14
|
/** Lossless RDF dataset: one named graph per cited assertion, with provenance in the default graph. */
|
|
38
15
|
export class RdfEvidenceGraph {
|
|
39
16
|
snapshot;
|
|
@@ -85,7 +62,15 @@ export class RdfEvidenceGraph {
|
|
|
85
62
|
}
|
|
86
63
|
}
|
|
87
64
|
async validate() {
|
|
88
|
-
|
|
65
|
+
// These graph-independent shapes already read the dataset as a union. Index
|
|
66
|
+
// that union once so every property lookup avoids scanning one graph per fact.
|
|
67
|
+
// Keep every triple; the original named dataset retains assertion provenance
|
|
68
|
+
// and remains the source for queries and serialization.
|
|
69
|
+
const validationGraph = new Store();
|
|
70
|
+
for (const { subject, predicate, object } of this.dataset) {
|
|
71
|
+
validationGraph.addQuad(subject, predicate, object);
|
|
72
|
+
}
|
|
73
|
+
const report = await new SHACLValidator(new Store(evidenceShapes)).validate(validationGraph);
|
|
89
74
|
const issues = report.results.map((result) => ({
|
|
90
75
|
category: 'extraction-gap',
|
|
91
76
|
focus: result.focusNode?.value,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CG = "https://context-graph.dev/record#";
|
|
2
|
+
export declare const RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
|
|
3
|
+
export declare const XSD = "http://www.w3.org/2001/XMLSchema#";
|
|
4
|
+
/** Graph-independent evidence constraints, evaluated over the union of all assertion graphs. */
|
|
5
|
+
export declare const evidenceShapes: import("n3").Quad[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Parser } from 'n3';
|
|
2
|
+
export const CG = 'https://context-graph.dev/record#';
|
|
3
|
+
export const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
4
|
+
export const XSD = 'http://www.w3.org/2001/XMLSchema#';
|
|
5
|
+
/** Graph-independent evidence constraints, evaluated over the union of all assertion graphs. */
|
|
6
|
+
export const evidenceShapes = new Parser().parse(`
|
|
7
|
+
@prefix cg: <${CG}>.
|
|
8
|
+
@prefix rdf: <${RDF}>.
|
|
9
|
+
@prefix sh: <http://www.w3.org/ns/shacl#>.
|
|
10
|
+
@prefix xsd: <${XSD}>.
|
|
11
|
+
cg:FactShape a sh:NodeShape; sh:targetClass rdf:Statement;
|
|
12
|
+
sh:property [ sh:path cg:record; sh:minCount 1; sh:maxCount 1; sh:datatype xsd:string ];
|
|
13
|
+
sh:property [ sh:path rdf:subject; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
14
|
+
sh:property [ sh:path rdf:predicate; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
15
|
+
sh:property [ sh:path rdf:object; sh:minCount 1; sh:maxCount 1; sh:nodeKind sh:IRI ];
|
|
16
|
+
sh:property [ sh:path cg:authority; sh:minCount 1; sh:maxCount 1;
|
|
17
|
+
sh:in ("declared" "implemented" "validated" "observed" "inferred" "draft") ];
|
|
18
|
+
sh:property [ sh:path cg:path; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
19
|
+
sh:property [ sh:path cg:commit; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
20
|
+
sh:property [ sh:path cg:sourceDigest; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ];
|
|
21
|
+
sh:property [ sh:path cg:startLine; sh:minCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
22
|
+
sh:property [ sh:path cg:endLine; sh:minCount 1; sh:datatype xsd:integer; sh:minInclusive 1 ];
|
|
23
|
+
sh:property [ sh:path cg:confidence; sh:minCount 1; sh:datatype xsd:decimal; sh:minInclusive 0; sh:maxInclusive 1 ];
|
|
24
|
+
sh:property [ sh:path cg:extractor; sh:minCount 1; sh:datatype xsd:string; sh:minLength 1 ].
|
|
25
|
+
cg:NodeShape a sh:NodeShape; sh:targetClass cg:Node;
|
|
26
|
+
sh:property [ sh:path cg:kind; sh:minCount 1; sh:maxCount 1 ].
|
|
27
|
+
`);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/interfaces/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import { FileSnapshotStore } from "../storage/storage.js";
|
|
|
15
15
|
import { diagnoseSetup } from "./doctor.js";
|
|
16
16
|
import { runInit } from "./init.js";
|
|
17
17
|
import { loadConfig } from "../configuration/config.js";
|
|
18
|
+
import { planHydration } from '../application/hydration-plan.js';
|
|
18
19
|
function valueAfter(args, name) {
|
|
19
20
|
const index = args.indexOf(name);
|
|
20
21
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -45,10 +46,41 @@ export function impactRequestFromArgs(args) {
|
|
|
45
46
|
continuation: valueAfter(args, '--continuation'),
|
|
46
47
|
};
|
|
47
48
|
}
|
|
49
|
+
function formatHydrationPlan(plan) {
|
|
50
|
+
const readiness = plan.issues.some((issue) => issue.severity === 'error')
|
|
51
|
+
? 'blocked' : plan.ready ? 'ready' : 'needs review';
|
|
52
|
+
const lines = [
|
|
53
|
+
`Hydration plan: ${plan.repositoryId}`,
|
|
54
|
+
`Commit: ${plan.commitSha} (ref ${plan.ref})`,
|
|
55
|
+
`Configuration: ${plan.configurationDigest}`,
|
|
56
|
+
`Scope: ${plan.scope.mode}, ${plan.scope.complete ? 'complete' : 'incomplete'}; head ${plan.scope.headName}`,
|
|
57
|
+
`Documents: ${plan.budgets.selectedDocuments}/${plan.budgets.maxDocuments}; ${plan.budgets.totalSourceBytes} bytes total; ${plan.budgets.maxSourceBytes} bytes maximum per document`,
|
|
58
|
+
`Expected cache reuse: ${plan.estimates.reusableArtifacts}; extractions: ${plan.estimates.extractions}; unknown cache entries: ${plan.estimates.unknownArtifacts}`,
|
|
59
|
+
`Source/cache/budget checks: ${readiness}`,
|
|
60
|
+
];
|
|
61
|
+
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(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
for (const selection of plan.selections.filter((item) => item.status !== 'matched')) {
|
|
65
|
+
lines.push(`Selection ${JSON.stringify(selection.selector)}: ${selection.status}`);
|
|
66
|
+
}
|
|
67
|
+
for (const issue of plan.issues)
|
|
68
|
+
lines.push(`${issue.severity.toUpperCase()} [${issue.code}]: ${issue.message}`);
|
|
69
|
+
if (plan.scope.omittedDocuments.length) {
|
|
70
|
+
lines.push(`Documents omitted by scope limits: ${plan.scope.omittedDocuments.map((path) => JSON.stringify(path)).join(', ')}`);
|
|
71
|
+
}
|
|
72
|
+
if (plan.scope.ignoredSearchTerms)
|
|
73
|
+
lines.push(`Search terms omitted by scope limits: ${plan.scope.ignoredSearchTerms}`);
|
|
74
|
+
if (plan.excludedWorkingChanges.length) {
|
|
75
|
+
lines.push(`Working changes excluded: ${plan.excludedWorkingChanges.map((path) => JSON.stringify(path)).join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
lines.push(...plan.assumptions.map((assumption) => `Note: ${assumption}`));
|
|
78
|
+
return `${lines.join('\n')}\n`;
|
|
79
|
+
}
|
|
48
80
|
async function main() {
|
|
49
81
|
const args = process.argv.slice(2);
|
|
50
82
|
if (args.includes('--help') || !args.length) {
|
|
51
|
-
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.\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');
|
|
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');
|
|
52
84
|
return;
|
|
53
85
|
}
|
|
54
86
|
if (args[0] === 'init') {
|
|
@@ -85,6 +117,17 @@ async function main() {
|
|
|
85
117
|
process.stdout.write(`${JSON.stringify(await diagnoseSetup(configPath), null, 2)}\n`);
|
|
86
118
|
return;
|
|
87
119
|
}
|
|
120
|
+
if (args[0] === 'hydrate' && args.includes('--plan')) {
|
|
121
|
+
const plan = await planHydration(configPath, {
|
|
122
|
+
ref: valueAfter(args, '--ref') ?? 'HEAD',
|
|
123
|
+
forceSemantic: args.includes('--force-semantic'),
|
|
124
|
+
request: impactRequestFromArgs(args),
|
|
125
|
+
});
|
|
126
|
+
process.stdout.write(args.includes('--json') ? `${JSON.stringify(plan, null, 2)}\n` : formatHydrationPlan(plan));
|
|
127
|
+
if (!plan.ready)
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
88
131
|
const application = await createContextGraphApplication(configPath);
|
|
89
132
|
const [command, subcommand] = args;
|
|
90
133
|
if (command === 'sparql' || command === 'validate') {
|
|
@@ -120,9 +163,10 @@ async function main() {
|
|
|
120
163
|
const controller = new AbortController();
|
|
121
164
|
const cancel = () => controller.abort();
|
|
122
165
|
process.once('SIGINT', cancel);
|
|
123
|
-
const
|
|
166
|
+
const ref = valueAfter(args, '--ref') ?? 'HEAD';
|
|
167
|
+
const scope = await application.scopeResolver?.resolve(impactRequestFromArgs(args), ref);
|
|
124
168
|
const result = await application.hydrator.hydrate({
|
|
125
|
-
ref:
|
|
169
|
+
ref: scope?.commitSha ?? ref,
|
|
126
170
|
headName: scope?.headName ?? application.headName,
|
|
127
171
|
semanticSources: scope?.semanticSources,
|
|
128
172
|
forceSemantic: args.includes('--force-semantic'),
|
package/dist/repository/git.d.ts
CHANGED
|
@@ -22,5 +22,5 @@ export declare class GitRepository {
|
|
|
22
22
|
readFileAt(commitSha: string, path: string): Promise<string>;
|
|
23
23
|
findTextAt(commitSha: string, needles: readonly string[], roots: readonly string[]): Promise<readonly GitTextMatch[]>;
|
|
24
24
|
delta(baseSha: string | undefined, headSha: string, roots: readonly string[]): Promise<GitDelta>;
|
|
25
|
-
semanticSources(context: ExtractionContext, roots: readonly string[]): Promise<readonly SemanticSource[]>;
|
|
25
|
+
semanticSources(context: Pick<ExtractionContext, 'commitSha'>, roots: readonly string[]): Promise<readonly SemanticSource[]>;
|
|
26
26
|
}
|
package/dist/repository/git.js
CHANGED
|
@@ -26,7 +26,7 @@ export class GitRepository {
|
|
|
26
26
|
}
|
|
27
27
|
async workingChanges() {
|
|
28
28
|
const prefix = await this.run(['rev-parse', '--show-prefix']);
|
|
29
|
-
const output = await this.execute(['status', '--porcelain=v1', '-z', '--untracked-files=all'], false);
|
|
29
|
+
const output = await this.execute(['--no-optional-locks', 'status', '--porcelain=v1', '-z', '--untracked-files=all'], false);
|
|
30
30
|
const records = output.split('\0');
|
|
31
31
|
const paths = new Set();
|
|
32
32
|
for (let index = 0; index < records.length; index++) {
|
|
@@ -65,6 +65,8 @@ export class GitRepository {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
async listFilesAt(commitSha, roots) {
|
|
68
|
+
if (roots.length === 0)
|
|
69
|
+
return [];
|
|
68
70
|
const output = await this.run(['ls-tree', '-r', '--name-only', commitSha, '--', ...roots]);
|
|
69
71
|
return output.split('\n').filter(Boolean).sort();
|
|
70
72
|
}
|
|
@@ -107,6 +109,8 @@ export class GitRepository {
|
|
|
107
109
|
return [...matches.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
108
110
|
}
|
|
109
111
|
async delta(baseSha, headSha, roots) {
|
|
112
|
+
if (roots.length === 0)
|
|
113
|
+
return { changedPaths: [], deletedPaths: [], renamedPaths: {} };
|
|
110
114
|
if (!baseSha) {
|
|
111
115
|
return {
|
|
112
116
|
changedPaths: await this.listFilesAt(headSha, roots),
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ADR-016: Read-only hydration planning
|
|
2
|
+
|
|
3
|
+
Status: accepted and implemented for the 0.3.0 release plan; absent from 0.2.1.
|
|
4
|
+
See [validation](VALIDATION.md) for recorded publication evidence.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
Consumers need to inspect document selection, extraction work and configured limits before
|
|
9
|
+
invoking a model. Constructing the execution application is unsuitable for that preview because
|
|
10
|
+
it loads configured repository adapters. Independently calculating source selection or cache keys
|
|
11
|
+
would also allow the preview to disagree with hydration.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
Provide `hydrate --plan` with a human summary and `hydrate --plan --json` with a structured
|
|
16
|
+
`hydration-plan` record. The public `planHydration(configPath, options)` function uses the same
|
|
17
|
+
planner. `--ref` resolves once to a commit SHA, including for agent scope. Configuration and
|
|
18
|
+
artifact storage are read from the current local environment, and the plan reports excluded
|
|
19
|
+
working changes rather than using their bytes as committed evidence.
|
|
20
|
+
|
|
21
|
+
The planner reads configuration, committed Git objects and existing semantic artifacts. It never
|
|
22
|
+
constructs an execution application or loads a configured provider/adapter. It does not probe
|
|
23
|
+
credentials, index TypeScript, collect runtime evidence, compile ontology artifacts, validate RDF,
|
|
24
|
+
publish snapshots or create cache directories. Git status disables optional locks so the preview
|
|
25
|
+
does not refresh the index. Source bodies and raw model output are not included in the result.
|
|
26
|
+
|
|
27
|
+
Committed source selection, duplicate semantic-ID checks and budget assessment are shared with
|
|
28
|
+
hydration. Provider identity and semantic artifact keys are pure functions shared with execution.
|
|
29
|
+
Per-source entries identify exact path/content digest, stable semantic identity, inclusion selectors,
|
|
30
|
+
line and UTF-8 byte counts, configured evidence role and matched source-approval patterns.
|
|
31
|
+
|
|
32
|
+
Classification follows configuration, not an inference about prose meaning. `sourceAuthority`
|
|
33
|
+
can be declared by an approved path while `extractionReview` remains unreviewed. A source matching
|
|
34
|
+
`evidenceRoots` is labeled validation evidence, but selecting it still schedules semantic extraction.
|
|
35
|
+
Recursive SOT traversal and default separation of validation documents belong to T07.
|
|
36
|
+
|
|
37
|
+
## Cache and readiness semantics
|
|
38
|
+
|
|
39
|
+
Cache inspection distinguishes these states without modifying evidence:
|
|
40
|
+
|
|
41
|
+
| State | Planned meaning |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `hit` | Readable artifact matches source identity/content, extraction contract, structure and output digest |
|
|
44
|
+
| `miss` | No artifact exists for the current key; extraction is expected |
|
|
45
|
+
| `forced` | Explicit force requests fresh extraction; no forced key or artifact is created by planning |
|
|
46
|
+
| `corrupt` | Stored JSON, identity, structure or content digest is invalid; reuse is not claimed |
|
|
47
|
+
| `unavailable` | The artifact could not be read; its reuse state is unknown |
|
|
48
|
+
|
|
49
|
+
Corrupt/unavailable entries are not ordinary misses and are never silently repaired or overwritten.
|
|
50
|
+
An artifact can remain reusable after a source rename or a different commit with unchanged content;
|
|
51
|
+
its original path/commit need not equal the current path/commit. Hydration rebinds current provenance.
|
|
52
|
+
The preview's estimate is conditional on unchanged inputs and storage state, not a guarantee against
|
|
53
|
+
concurrent changes or a successful provider run.
|
|
54
|
+
|
|
55
|
+
Limits apply to every selected document, including cache hits: `maxDocuments` bounds the document
|
|
56
|
+
count and `maxSourceBytes` bounds each document's UTF-8 bytes. Total source bytes are reported but
|
|
57
|
+
are not a token or monetary budget. Selection is never trimmed to make these limits pass.
|
|
58
|
+
|
|
59
|
+
Budget, duplicate-ID and cache errors produce a blocked plan. Missing/no-document selectors and
|
|
60
|
+
omissions from existing bounded agent selection produce warnings and an incomplete scope that
|
|
61
|
+
needs review. Both yield `ready: false` and CLI exit 1, while retaining the full plan. `ready: true`
|
|
62
|
+
and exit 0 mean only that these planning checks passed; execution prerequisites and product-intent
|
|
63
|
+
completeness have not been established.
|
|
64
|
+
|
|
65
|
+
Warnings do not create new hard hydration gates. Existing hydration behavior can still publish a
|
|
66
|
+
new graph after deleting the last selected document, removing its old relationships. The preview
|
|
67
|
+
exposes that empty match for review. An explicitly empty source list is complete and selects none.
|
|
68
|
+
|
|
69
|
+
## Compatibility
|
|
70
|
+
|
|
71
|
+
The shared key/output-digest implementation preserves the released 0.2.1 semantic artifact contract,
|
|
72
|
+
including document identity-policy invalidation. Valid existing artifacts remain reusable; no
|
|
73
|
+
semantic re-extraction is required merely by this refactor. Operational configuration changes can
|
|
74
|
+
still affect cache identity/storage profiles; that is separate T03 work.
|
|
75
|
+
|
|
76
|
+
The empty-source fix changes graph assembly behavior: empty roots previously could enumerate all
|
|
77
|
+
repository documents. Assembly advances to `graph-v6` so corrected snapshots cannot collide with
|
|
78
|
+
immutable older snapshots at the same commit/configuration. Old snapshots remain readable and
|
|
79
|
+
unchanged. The requested ref also controls agent source selection instead of always using HEAD.
|
|
80
|
+
|
|
81
|
+
## Validation and next work
|
|
82
|
+
|
|
83
|
+
Public regressions cover committed and dirty inputs, unchanged index/files, absent or side-effecting
|
|
84
|
+
provider/adapter modules, empty scope, warm/cold/forced cache, malformed and unreadable artifacts,
|
|
85
|
+
released-key compatibility, budgets, duplicate IDs, missing selectors and historical agent scope
|
|
86
|
+
with explicit omissions. Existing rename/delete lifecycle checks remain applicable. Full validation
|
|
87
|
+
and release evidence are recorded separately in [VALIDATION.md](VALIDATION.md).
|
|
88
|
+
|
|
89
|
+
This increment makes no SHACL performance change. T05 will measure graph construction and full
|
|
90
|
+
validation before selecting caching, incremental validation or backend changes. See the
|
|
91
|
+
[1.0 plan](RELEASE-1.0-PLAN.md) for bounded follow-ups and the separate 2.0 platform direction.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# ADR-017: Validate a temporary RDF union without changing canonical evidence
|
|
2
|
+
|
|
3
|
+
Status: accepted and implemented for the focused 0.3.0 release plan; absent from 0.2.1.
|
|
4
|
+
See [validation](VALIDATION.md) for checks and recorded publication evidence.
|
|
5
|
+
|
|
6
|
+
## Problem and measured mechanism
|
|
7
|
+
|
|
8
|
+
The canonical RDF dataset has one named relationship graph per assertion, with assertion records,
|
|
9
|
+
node metadata and provenance in the default graph. The JavaScript `rdf-validate-shacl` validator
|
|
10
|
+
uses graph-wildcard dataset lookups through clownface. N3 indexes graphs first, so a lookup with
|
|
11
|
+
no graph restriction visits each graph before consulting its subject/predicate/object indexes.
|
|
12
|
+
Repeating those lookups for each focus node and shape property becomes expensive as assertion
|
|
13
|
+
graphs grow.
|
|
14
|
+
|
|
15
|
+
Bounded public experiments measured this cost in the current layout and compared an indexed union
|
|
16
|
+
using the same validator and shapes. They establish a synthetic scaling problem and a useful
|
|
17
|
+
optimization; they do not reproduce the private consumer's complete generation or diagnose its
|
|
18
|
+
reported 30-minute timeout. The consumer's total graph size and other phase costs remain unknown.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
For each `RdfEvidenceGraph.validate()` call, build a temporary single-default-graph N3 store from
|
|
23
|
+
every subject/predicate/object triple in the canonical dataset. Run the unchanged SHACL shapes
|
|
24
|
+
and validator on that store, and retain the existing explicit citation-order check. The canonical
|
|
25
|
+
named dataset remains unchanged and continues to serve SPARQL, fact projection and serialization.
|
|
26
|
+
|
|
27
|
+
This is still full-graph validation on every refresh. It introduces no GraphDB service, native/Rust
|
|
28
|
+
validator, incremental validation or validation-result cache. The short-lived union is not retained
|
|
29
|
+
as another persistent graph or used to replace canonical evidence.
|
|
30
|
+
|
|
31
|
+
RDF graphs are sets: identical SPO triples from multiple named graphs collapse in the validation
|
|
32
|
+
projection. The present shapes already use union lookups and node/value sets, and do not inspect
|
|
33
|
+
graph identity. Separate assertion records and their cited provenance remain intact in the original
|
|
34
|
+
dataset; no assertion, shape or constraint is removed. A future graph-sensitive shape requires an
|
|
35
|
+
explicit compatibility decision and new equivalence tests before using this projection.
|
|
36
|
+
|
|
37
|
+
## Bounded public measurements
|
|
38
|
+
|
|
39
|
+
Environment: Linux cloud workspace, Node 24.19.0, N3 2.7.2 and rdf-validate-shacl 0.6.5.
|
|
40
|
+
Each case ran once in a fresh child process with a 45-second hard deadline. The prototype copied
|
|
41
|
+
the same original dataset into a single graph only for validation; production-patch verification
|
|
42
|
+
is recorded separately in [VALIDATION.md](VALIDATION.md).
|
|
43
|
+
|
|
44
|
+
Fixtures contain public synthetic Workflow-to-Component assertions, cited metadata and one named
|
|
45
|
+
relationship graph per fact. Shared topology repeats 50 nodes; unique topology uses two distinct
|
|
46
|
+
nodes per fact. Timings below are seconds, with union construction separated from SHACL. RSS is
|
|
47
|
+
the process sample after validation, including Node, libraries and both datasets, not a measurement
|
|
48
|
+
of projection memory alone.
|
|
49
|
+
|
|
50
|
+
| Facts / topology | Original quads | Original SHACL | Union construction | Union SHACL | Union RSS MiB |
|
|
51
|
+
| --- | ---: | ---: | ---: | ---: | ---: |
|
|
52
|
+
| 1,000 shared | 20,203 | 3.889 | 0.061 | 0.239 | 352.3 |
|
|
53
|
+
| 2,000 shared | 40,203 | 19.550 | 0.102 | 0.410 | 440.0 |
|
|
54
|
+
| 1,000 unique | 28,003 | 5.731 | 0.104 | 0.308 | 352.6 |
|
|
55
|
+
| 2,000 unique | 56,003 | 31.502 | 0.153 | 0.467 | 457.9 |
|
|
56
|
+
| 5,000 shared | 100,203 | No verdict before process deadline | 0.251 | 1.131 | 825.5 |
|
|
57
|
+
| 10,000 unique | 280,003 | Not measured | 0.779 | 2.119 | 1,287.3 |
|
|
58
|
+
|
|
59
|
+
The 5,000-fact original-mode process was terminated after 45.051 seconds total elapsed time,
|
|
60
|
+
including startup and construction. It produced no SHACL verdict; this is not an inferred
|
|
61
|
+
completed validation duration. For the 10,000-fact unique union case, initial canonical graph
|
|
62
|
+
construction took 1.058 seconds in addition to the times shown. Its roughly 1.3 GiB RSS is a
|
|
63
|
+
material memory cost and should be measured on larger or different workloads.
|
|
64
|
+
|
|
65
|
+
These single runs are not statistical latency estimates or production guarantees. The experiment
|
|
66
|
+
does not measure semantic extraction, SCIP, SPARQL, serialization, snapshot publication or disk
|
|
67
|
+
storage. No private consumer data or live provider calls were used. The repository benchmark
|
|
68
|
+
`pnpm benchmark:shacl` reproduces bounded public comparisons using the current build; retain its
|
|
69
|
+
configuration, versions and raw output when comparing results.
|
|
70
|
+
|
|
71
|
+
## Correctness and compatibility
|
|
72
|
+
|
|
73
|
+
The prototype compared sorted conformance issues between the original and union paths across
|
|
74
|
+
valid repeated relationships/attributes, conflicting node kinds, out-of-range confidence, invalid
|
|
75
|
+
citations, empty citation paths, colliding assertion IDs and combined violations. All seven paired
|
|
76
|
+
cases agreed, and before/after serialization hashes preserved the canonical named dataset.
|
|
77
|
+
|
|
78
|
+
Production regressions must compare both paths for all supported constraints, including negative
|
|
79
|
+
cases, and preserve named-graph SPARQL results, fact projection, serialization and repeated calls.
|
|
80
|
+
Those checks establish parity for the current shapes, not arbitrary future SHACL rules. Failed
|
|
81
|
+
validation must continue to prevent publication and preserve the previous valid snapshot.
|
|
82
|
+
|
|
83
|
+
The optimization changes neither facts nor evidence authority and does not require a new semantic
|
|
84
|
+
cache identity. It does not make old evidence eligible for current-diff gates. Normal snapshot
|
|
85
|
+
commit, configuration, scope and provenance checks continue to apply.
|
|
86
|
+
|
|
87
|
+
## Release boundary and remaining T05 work
|
|
88
|
+
|
|
89
|
+
Ship the demonstrated cold-validation improvement after its independent review and required
|
|
90
|
+
validation, ahead of unrelated 1.0 work. A first graph cannot benefit from reusing a successful
|
|
91
|
+
validation result that does not yet exist. Private consumer acceptance remains pending after release.
|
|
92
|
+
|
|
93
|
+
Early identity checks, detailed progress/elapsed reporting, validation-result caching and safe
|
|
94
|
+
incremental validation remain open. The validator's main validation loop is synchronous; timers
|
|
95
|
+
on the same JavaScript thread cannot show a live heartbeat while it is blocked. Keep phase
|
|
96
|
+
boundaries honest and evaluate bounded worker execution before promising in-phase progress or
|
|
97
|
+
cancellation. Any later cached or incremental result must account for graph content, shapes,
|
|
98
|
+
validator/policy versions, deletions, affected relationships and global constraints, with full
|
|
99
|
+
validation when safe scope cannot be established.
|
|
100
|
+
|
|
101
|
+
Native engines and optional persistent database backends remain measurement-driven alternatives,
|
|
102
|
+
not prerequisites of this release. See the [1.0 task list](RELEASE-1.0-PLAN.md).
|
package/docs/RELEASE-1.0-PLAN.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# Consumer hardening and the 1.0 release plan
|
|
2
2
|
|
|
3
|
-
Status: maintainer-directed work
|
|
4
|
-
The
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Status: maintainer-directed work; source checkpoint on 2026-10-26 before the planned 0.3.0 release.
|
|
4
|
+
The report concerned `@weftlet/toolkit@0.2.0`. **T01's upstream patch shipped in 0.2.1**;
|
|
5
|
+
genuine consumer acceptance remains pending. T02 is merged and awaits release. T05's focused
|
|
6
|
+
cold-validation optimization is implemented in development source, with validation/release pending;
|
|
7
|
+
its broader follow-ups and T03, T04, T06 and T07 remain open. These tasks improve setup, reuse, diagnostics and document coverage
|
|
8
|
+
without expanding the consumer's migration. An official 1.0
|
|
9
|
+
follows this work and genuine consumer acceptance, with its exact release scope reviewed when
|
|
10
|
+
the evidence is available.
|
|
8
11
|
|
|
9
12
|
This is the near-term release task list. The [Weftlet 2.0 product plan](WEFTLET-2.0-PLAN.md)
|
|
10
13
|
remains a separate future direction for generation, approvals, a companion website and hosted
|
|
@@ -31,17 +34,20 @@ integration. Consumer acceptance is reported separately from upstream determinis
|
|
|
31
34
|
|
|
32
35
|
| ID | Task | Priority/status | Dependencies and release boundary |
|
|
33
36
|
| --- | --- | --- | --- |
|
|
34
|
-
| **T01** | Coherent repository-document identity and kind | **
|
|
35
|
-
| **T02** | No-model hydration/setup preview |
|
|
37
|
+
| **T01** | Coherent repository-document identity and kind | **Upstream patch shipped in 0.2.1; consumer acceptance pending** | SHACL and assertions preserved; genuine consumer re-run is still required |
|
|
38
|
+
| **T02** | No-model hydration/setup preview | Merged in PR #18; not published in 0.2.1 | Shared selection/cache inspection, human/JSON plans; extend with T07 traversal coverage |
|
|
36
39
|
| **T03** | Artifact reuse across operational configuration changes | Planned efficiency work | Preserve T01's semantic identity separation; keep snapshot/config identity distinct from reusable artifact identity |
|
|
37
40
|
| **T04** | Actionable, privacy-safe timeout diagnostics | Planned diagnostics work | Use stable source identifiers and run progress; document recovery with T02/T03 |
|
|
38
|
-
| **T05** | Early identity checks and validation progress/profiling |
|
|
39
|
-
| **T06** | Packaged release-documentation consistency |
|
|
41
|
+
| **T05** | Early identity checks and validation progress/profiling | **Adoption blocker; cold-validation fix in source** | Validate and release union-projection optimization now; early checks, detailed progress and validation reuse remain open |
|
|
42
|
+
| **T06** | Packaged release-documentation consistency | Open; README version pins removed in 0.2.1 | Automated archive/version consistency check remains to be implemented |
|
|
40
43
|
| **T07** | Coverage-aware traversal from SOT/roadmap entry points | Planned bounded feature work | Use canonical identity from T01, preview from T02 and incremental reuse from T03; split selection/classification/extraction changes |
|
|
41
44
|
|
|
42
|
-
T02
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
T02 passed the local publication checks and hosted Ubuntu/Windows checks before
|
|
46
|
+
[PR #18](https://github.com/jchewitt/weftlet/pull/18) merged. Prioritize the focused T05 performance
|
|
47
|
+
release following the maintainer's reported timeout; do not wait for the remaining 1.0 features.
|
|
48
|
+
T03, T04, T06 and T07 remain independently useful increments. Keep them
|
|
49
|
+
separate from the optional platform work. Publication follows the normal release process; no new
|
|
50
|
+
npm release is claimed for T02. Normal release checks apply to every shipped increment.
|
|
45
51
|
|
|
46
52
|
## T01 — Resolve repository-document identity conflicts
|
|
47
53
|
|
|
@@ -66,16 +72,40 @@ Acceptance:
|
|
|
66
72
|
the patch, then request a genuine consumer re-run against the recorded inputs; do not infer
|
|
67
73
|
consumer acceptance from the upstream fixture.
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
Upstream completion evidence:
|
|
76
|
+
|
|
77
|
+
- [Fix PR #15](https://github.com/jchewitt/weftlet/pull/15) implements the policy in
|
|
78
|
+
[ADR 015](ADR-015-repository-document-identity.md), with public cross-document regressions and
|
|
79
|
+
fresh/cache-reuse coverage. [Release PR #16](https://github.com/jchewitt/weftlet/pull/16)
|
|
80
|
+
advances the fixed core/toolkit group to 0.2.1.
|
|
81
|
+
- [Release run 40382864083](https://github.com/jchewitt/weftlet/actions/runs/40382864083)
|
|
82
|
+
completed preparation, publication and release records on its first attempt at commit
|
|
83
|
+
`5d1db91bf19ed493a20849b2d0f92d3aeac35dfe`. Required checks included 227 deterministic tests,
|
|
84
|
+
12 advisory architecture findings, fresh packed-consumer checks and hosted Ubuntu/Windows CI.
|
|
85
|
+
- Registry archives, provenance and tags match the reviewed release. A fresh public-registry
|
|
86
|
+
consumer passes the two-document regression, real SCIP, RDF/SHACL, queries and unchanged
|
|
87
|
+
snapshot identity/content on artifact reuse, without live model calls. See the detailed
|
|
88
|
+
[validation record](VALIDATION.md) for commits, checks and result boundaries.
|
|
89
|
+
|
|
90
|
+
The private consumer has not yet supplied a successful full hydration/repeat against 0.2.1.
|
|
91
|
+
Upstream publication and regression success do not close that acceptance gate or diagnose the
|
|
92
|
+
separate full-graph validation latency observation.
|
|
72
93
|
|
|
73
94
|
## T02 — Preview scope and work without calling a model
|
|
74
95
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
artifact
|
|
96
|
+
Implemented in development source: `hydrate --plan` renders a human summary and `--json` returns
|
|
97
|
+
the structured plan. This feature is not in published 0.2.1. Shared source selection and identity
|
|
98
|
+
logic report selected documents and sizes, inclusion reasons, configured role/source approval,
|
|
99
|
+
unreviewed assertion status, artifact reuse/extraction estimates and document/per-source byte limits.
|
|
100
|
+
See [ADR 016](ADR-016-hydration-preview.md) and [validation](VALIDATION.md).
|
|
101
|
+
|
|
102
|
+
Missing or unsupported-only selectors and bounded agent omissions remain visible as warnings;
|
|
103
|
+
incomplete plans need review and exit 1. They do not introduce new hydration gates that would
|
|
104
|
+
break deletion of the last document. Budget, duplicate-ID and corrupt/unavailable cache errors
|
|
105
|
+
block planning checks without truncating selected sources. An explicit empty source list selects
|
|
106
|
+
none. Requested refs now govern agent scope; corrected snapshots use graph-v6 while valid 0.2.1
|
|
107
|
+
semantic artifacts remain reusable. T03's operational cache changes and T07's traversal/default
|
|
108
|
+
validation-document separation remain separate work.
|
|
79
109
|
|
|
80
110
|
Acceptance:
|
|
81
111
|
|
|
@@ -126,19 +156,56 @@ Acceptance:
|
|
|
126
156
|
|
|
127
157
|
## T05 — Detect inexpensive conflicts early and explain validation work
|
|
128
158
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
The implementation uses JavaScript on Node:
|
|
160
|
+
`rdf-validate-shacl` validates an in-memory N3 dataset. Hydration constructs and validates the
|
|
161
|
+
entire assembled graph, including when semantic artifacts were reused. There is no persistent
|
|
162
|
+
GraphDB backend or incremental validation. Querying a saved snapshot does not rerun SHACL.
|
|
163
|
+
|
|
164
|
+
The maintainer reports that validation pushes the consumer's overall generation beyond its
|
|
165
|
+
30-minute timeout, preventing snapshot publication and making adoption unusable. This is now
|
|
166
|
+
a release blocker, not an optional observability improvement. Upstream has measured a specific
|
|
167
|
+
named-graph lookup cost in public synthetic fixtures, but has not measured that consumer graph or
|
|
168
|
+
diagnosed its complete timeout. Ship the focused performance release once its correctness and
|
|
169
|
+
improvement are demonstrated, ahead of the remaining 1.0 tasks.
|
|
170
|
+
|
|
171
|
+
[ADR 017](ADR-017-shacl-validation-union.md) records the implemented cold-validation optimization:
|
|
172
|
+
build a temporary union of every SPO triple for the same validator/shapes, while keeping original
|
|
173
|
+
named assertion graphs canonical for queries and serialization. It removes repeated wildcard
|
|
174
|
+
lookups across one graph per fact. In a bounded single-run public 2,000-fact unique-node case,
|
|
175
|
+
the original SHACL path took 31.502 seconds; union construction took 0.153 seconds and SHACL
|
|
176
|
+
took 0.467 seconds. A 10,000-fact unique-node union case used about 1.3 GiB process RSS. These
|
|
177
|
+
are synthetic phase measurements, not a private consumer reproduction or end-to-end guarantee.
|
|
178
|
+
|
|
179
|
+
The focused change still validates the whole graph each time. It does not add Rust, GraphDB,
|
|
180
|
+
incremental validation or a validation-result cache. Early checks and broader observability/reuse
|
|
181
|
+
remain follow-ups rather than reasons to delay the cold-path fix. Native code or a database does
|
|
182
|
+
not by itself establish faster or correct incremental SHACL.
|
|
132
183
|
|
|
133
184
|
Acceptance:
|
|
134
185
|
|
|
135
186
|
- Early errors identify the conflicting identity/kinds and relevant evidence using the configured
|
|
136
187
|
privacy policy. Preserve all underlying assertions for diagnosis; early checks are not a
|
|
137
188
|
substitute for RDF/SHACL validation.
|
|
138
|
-
- Report elapsed time and honest
|
|
139
|
-
|
|
189
|
+
- Report elapsed time and honest progress for long validation. Current phase boundaries remain
|
|
190
|
+
the supported progress signal: the synchronous validator blocks same-thread timers. Evaluate
|
|
191
|
+
bounded worker execution before promising an in-phase heartbeat or cancellation; never display
|
|
192
|
+
a fabricated completion percentage when the validator exposes no meaningful denominator.
|
|
140
193
|
- Record reproducible public-fixture sizes, fact/node counts, runtime versions, wall time and
|
|
141
|
-
resource observations. Separate measured bottlenecks
|
|
194
|
+
resource observations for construction and validation separately. Separate measured bottlenecks
|
|
195
|
+
from hypotheses; include repeated identical input and small changed-input cases.
|
|
196
|
+
- Demonstrate improved cold full-graph validation, because reusing a previous validation result
|
|
197
|
+
cannot unblock a first graph that has never completed. Keep private consumer acceptance and
|
|
198
|
+
the overall generation timeout separate from synthetic validator-only benchmarks.
|
|
199
|
+
- Evaluate reuse of a successful conformance result only when validated graph content, shapes,
|
|
200
|
+
validator version and applicable policy/semantics match. This reuse must not make historical
|
|
201
|
+
evidence satisfy current-diff freshness, scope or provenance requirements.
|
|
202
|
+
- Evaluate dependency-aware incremental validation with insertions, updates, deletions, renames,
|
|
203
|
+
affected relationships and global constraints. Revalidate the complete affected scope or fall
|
|
204
|
+
back to full validation when it cannot be bounded safely; changed nodes alone are insufficient.
|
|
205
|
+
- Benchmark a suitable native/Rust-backed validator or optional persistent graph database if
|
|
206
|
+
measurements justify a candidate. Compare supported SHACL behavior, positive/negative parity,
|
|
207
|
+
installation, licensing, portability and maintenance cost. T02 adds no backend migration, and
|
|
208
|
+
this evaluation does not commit the standalone toolkit to a mandatory service.
|
|
142
209
|
- Any optimized validation/projection path has equivalence tests, including negative cases;
|
|
143
210
|
failure must preserve the prior snapshot. Keep model-independent profiling separate from live
|
|
144
211
|
extraction performance and from the reported two-fact correctness defect.
|
|
@@ -146,9 +213,9 @@ Acceptance:
|
|
|
146
213
|
## T06 — Keep packaged documentation consistent with the release
|
|
147
214
|
|
|
148
215
|
The consumer installed 0.2.0 while its packaged README still named 0.1.2 and some archive examples
|
|
149
|
-
used 0.1.1.
|
|
150
|
-
|
|
151
|
-
|
|
216
|
+
used 0.1.1. Release 0.2.1 removes the README version pins; immutable 0.2.0 archives retain their
|
|
217
|
+
original text. The automated release-documentation consistency check remains open. Add that
|
|
218
|
+
repeatable check rather than relying on manual edits alone.
|
|
152
219
|
|
|
153
220
|
Acceptance:
|
|
154
221
|
|
|
@@ -194,7 +261,7 @@ Acceptance:
|
|
|
194
261
|
|
|
195
262
|
## Official 1.0 acceptance
|
|
196
263
|
|
|
197
|
-
|
|
264
|
+
With T01's upstream patch published, work through T02–T07 in bounded increments and record implementation
|
|
198
265
|
PRs and validation evidence here or in the linked validation record. Review the exact 1.0 scope
|
|
199
266
|
against completed evidence; any deferral needs an explicit maintainer decision and must remain
|
|
200
267
|
visible rather than being treated as done. The companion website, hosted AI and broader 2.0
|