@kungfu-tech/kfd 1.0.0-alpha.2 → 1.0.0-alpha.20

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.
Files changed (44) hide show
  1. package/.buildchain/kfd-1/contract-world.witness.json +753 -0
  2. package/.buildchain/kfd-2/kfd-foundation.trust-assessment.json +238 -0
  3. package/.buildchain/kfd-2/kfd-foundation.trust-claims.json +225 -0
  4. package/.buildchain/kfd-2/public-release-trust.claim.json +131 -0
  5. package/.buildchain/kfd-3/collaboration-interface.artifact.json +774 -0
  6. package/.buildchain/kfd-3/collaboration-interface.json +421 -0
  7. package/.buildchain/kfd-3/collaboration-interface.prebuild.json +1141 -0
  8. package/README.md +149 -29
  9. package/TRADEMARKS.md +60 -0
  10. package/buildchain.contract-lock.json +86 -0
  11. package/buildchain.release-propagation.json +32 -0
  12. package/decisions/{kfd-1.md → KFD-1.md} +77 -35
  13. package/decisions/{kfd-2.md → KFD-2.md} +63 -11
  14. package/decisions/{kfd-3.md → KFD-3.md} +54 -16
  15. package/decisions/KFD-4.md +182 -0
  16. package/docs/KFD-1-usage.md +37 -0
  17. package/docs/KFD-2-usage.md +123 -0
  18. package/docs/KFD-3-usage.md +98 -0
  19. package/docs/KFD-4-usage.md +31 -0
  20. package/docs/MAP.md +20 -3
  21. package/docs/release-governance.md +28 -0
  22. package/kfd.release.json +13 -0
  23. package/package.json +28 -2
  24. package/registry.json +15 -5
  25. package/release-impact.json +113 -0
  26. package/schemas/kfd-1/contract-world.schema.json +67 -4
  27. package/schemas/kfd-1/witness.schema.json +113 -0
  28. package/schemas/kfd-2/release-claims.schema.json +331 -0
  29. package/schemas/kfd-2/release-trust-passport.schema.json +276 -0
  30. package/schemas/kfd-2/trust-assessment.schema.json +313 -0
  31. package/schemas/kfd-2/trust-claims.schema.json +334 -0
  32. package/schemas/kfd-2/trust-taxonomy.schema.json +219 -0
  33. package/schemas/kfd-3/collaboration-interface.schema.json +542 -0
  34. package/schemas/kfd-3/witness.schema.json +167 -0
  35. package/schemas/kfd-4/observer-perspective.schema.json +272 -0
  36. package/schemas/kfd-standards.schema.json +163 -0
  37. package/scripts/check.mjs +930 -0
  38. package/scripts/npm-publish-transaction.mjs +220 -0
  39. package/scripts/update-kfd-1-witness.mjs +35 -0
  40. package/scripts/update-kfd-2-claim.mjs +304 -0
  41. package/scripts/update-kfd-3-witness.mjs +261 -0
  42. package/scripts/update-site-bundle.mjs +353 -0
  43. package/site/kfd-site.json +251 -12
  44. package/standards.json +775 -15
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ const EXACT_TAG_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
8
+
9
+ function readArg(argv, name, fallback = "") {
10
+ const index = argv.indexOf(`--${name}`);
11
+ return index === -1 ? fallback : argv[index + 1] || "";
12
+ }
13
+
14
+ function hasFlag(argv, name) {
15
+ return argv.includes(`--${name}`);
16
+ }
17
+
18
+ function readEnv(name, fallback = "") {
19
+ return process.env[name] || fallback;
20
+ }
21
+
22
+ function runNpm({ cwd, args, allowFailure = false }) {
23
+ const result = spawnSync("npm", args, { cwd, env: process.env, encoding: "utf8" });
24
+ if (result.error) throw result.error;
25
+ if (!allowFailure && result.status !== 0) {
26
+ throw new Error(`npm ${args.join(" ")} failed\n${result.stdout || ""}${result.stderr || ""}`.trim());
27
+ }
28
+ return result;
29
+ }
30
+
31
+ function readPackageJson(cwd) {
32
+ const filePath = path.join(cwd, "package.json");
33
+ if (!fs.existsSync(filePath)) throw new Error(`package.json not found: ${filePath}`);
34
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
35
+ }
36
+
37
+ function parsePackResult(stdout) {
38
+ const parsed = JSON.parse(stdout);
39
+ const pack = Array.isArray(parsed) ? parsed[0] : parsed;
40
+ if (!pack?.name || !pack?.version) throw new Error("npm pack did not return package name and version");
41
+ return {
42
+ name: pack.name,
43
+ version: pack.version,
44
+ filename: pack.filename || "",
45
+ integrity: pack.integrity || "",
46
+ shasum: pack.shasum || "",
47
+ entryCount: pack.entryCount || pack.files?.length || 0,
48
+ };
49
+ }
50
+
51
+ function artifactDigest(pack) {
52
+ if (pack.integrity) return pack.integrity;
53
+ if (pack.shasum) return `sha1:${pack.shasum}`;
54
+ throw new Error("npm pack did not return integrity or shasum");
55
+ }
56
+
57
+ function parseNpmView(stdout) {
58
+ const raw = String(stdout || "").trim();
59
+ if (!raw) return undefined;
60
+ const parsed = JSON.parse(raw);
61
+ const dist = parsed?.dist || parsed;
62
+ return {
63
+ integrity: dist?.integrity || parsed?.["dist.integrity"] || "",
64
+ shasum: dist?.shasum || parsed?.["dist.shasum"] || "",
65
+ };
66
+ }
67
+
68
+ function publishedDigest({ cwd, name, version, registry }) {
69
+ const result = runNpm({
70
+ cwd,
71
+ args: ["view", `${name}@${version}`, "dist.integrity", "dist.shasum", "--json", `--registry=${registry}`],
72
+ allowFailure: true,
73
+ });
74
+ if (result.status !== 0) {
75
+ const output = `${result.stdout || ""}\n${result.stderr || ""}`;
76
+ if (/\bE404\b|404 Not Found|is not in this registry/i.test(output)) return undefined;
77
+ throw new Error(`npm view ${name}@${version} failed\n${output}`.trim());
78
+ }
79
+ const view = parseNpmView(result.stdout);
80
+ return view?.integrity || (view?.shasum ? `sha1:${view.shasum}` : "");
81
+ }
82
+
83
+ function assertPackageVersion({ pkg, expectedVersion }) {
84
+ if (pkg.private === true) throw new Error("package.json private must be false before npm publish");
85
+ if (!pkg.name || typeof pkg.name !== "string") throw new Error("package.json name must be a non-empty string");
86
+ if (!pkg.version || typeof pkg.version !== "string") throw new Error("package.json version must be a non-empty string");
87
+ if (expectedVersion && pkg.version !== expectedVersion) {
88
+ throw new Error(`package.json version must match Buildchain version: package=${pkg.version} buildchain=${expectedVersion}`);
89
+ }
90
+ const exactTag = `v${pkg.version}`;
91
+ if (!EXACT_TAG_PATTERN.test(exactTag)) throw new Error(`unsupported release tag for npm publish: ${exactTag}`);
92
+ return exactTag;
93
+ }
94
+
95
+ function writeEvidence({ cwd, evidencePath, evidence }) {
96
+ const resolved = path.resolve(cwd, evidencePath);
97
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
98
+ fs.writeFileSync(resolved, `${JSON.stringify(evidence, null, 2)}\n`);
99
+ return resolved;
100
+ }
101
+
102
+ function writeGitHubOutputs(outputs) {
103
+ const outputPath = process.env.GITHUB_OUTPUT;
104
+ if (!outputPath) return;
105
+ fs.appendFileSync(outputPath, `${Object.entries(outputs)
106
+ .map(([key, value]) => `${key}=${String(value).replace(/\r?\n/g, " ")}`)
107
+ .join("\n")}\n`);
108
+ }
109
+
110
+ export function npmPublishTransaction({
111
+ cwd = process.cwd(),
112
+ registry = "https://registry.npmjs.org/",
113
+ dryRunPublish = false,
114
+ access = "public",
115
+ skipRegistryLookup = false,
116
+ } = {}) {
117
+ const resolvedCwd = path.resolve(cwd);
118
+ const pkg = readPackageJson(resolvedCwd);
119
+ const expectedVersion = readEnv("BUILDCHAIN_VERSION");
120
+ const exactTag = assertPackageVersion({ pkg, expectedVersion });
121
+ const distTag = readEnv("BUILDCHAIN_NPM_DIST_TAG", pkg.version.includes("-") ? "alpha" : "latest");
122
+ const pack = parsePackResult(runNpm({
123
+ cwd: resolvedCwd,
124
+ args: ["pack", "--dry-run", "--json", `--registry=${registry}`],
125
+ }).stdout);
126
+ const digest = artifactDigest(pack);
127
+ const existingDigest = skipRegistryLookup ? undefined : publishedDigest({
128
+ cwd: resolvedCwd,
129
+ name: pkg.name,
130
+ version: pkg.version,
131
+ registry,
132
+ });
133
+ let publishAction = "already-published";
134
+ if (existingDigest) {
135
+ if (existingDigest !== digest) throw new Error(`artifact digest mismatch: npm:${pkg.name}@${pkg.version}`);
136
+ } else if (dryRunPublish) {
137
+ publishAction = "dry-run";
138
+ } else {
139
+ runNpm({
140
+ cwd: resolvedCwd,
141
+ args: ["publish", "--access", access, "--tag", distTag, `--registry=${registry}`],
142
+ });
143
+ publishAction = "published";
144
+ const registryDigest = skipRegistryLookup ? undefined : publishedDigest({
145
+ cwd: resolvedCwd,
146
+ name: pkg.name,
147
+ version: pkg.version,
148
+ registry,
149
+ });
150
+ if (registryDigest && registryDigest !== digest) {
151
+ throw new Error(`artifact digest mismatch: npm:${pkg.name}@${pkg.version}`);
152
+ }
153
+ }
154
+ const evidencePath = readEnv("BUILDCHAIN_PUBLISH_EVIDENCE");
155
+ if (!evidencePath) throw new Error("BUILDCHAIN_PUBLISH_EVIDENCE is required");
156
+ const evidence = {
157
+ schema: 1,
158
+ version: expectedVersion || pkg.version,
159
+ channel: readEnv("BUILDCHAIN_CHANNEL"),
160
+ source_sha: readEnv("BUILDCHAIN_SOURCE_SHA"),
161
+ release_sha: readEnv("BUILDCHAIN_RELEASE_SHA"),
162
+ target_ref: readEnv("BUILDCHAIN_TARGET_REF"),
163
+ release_material_sha: readEnv("BUILDCHAIN_RELEASE_MATERIAL_SHA", readEnv("BUILDCHAIN_RELEASE_SHA")),
164
+ publish_tooling_sha: readEnv("BUILDCHAIN_PUBLISH_TOOLING_SHA", readEnv("BUILDCHAIN_RELEASE_SHA")),
165
+ artifacts: [{
166
+ group: "node",
167
+ kind: "npm",
168
+ name: pkg.name,
169
+ ref: pkg.version,
170
+ digest,
171
+ }],
172
+ };
173
+ const resolvedEvidencePath = writeEvidence({ cwd: resolvedCwd, evidencePath, evidence });
174
+ writeGitHubOutputs({
175
+ version: pkg.version,
176
+ "exact-tag": exactTag,
177
+ "dist-tag": distTag,
178
+ "artifact-digest": digest,
179
+ "publish-action": publishAction,
180
+ "publish-evidence": resolvedEvidencePath,
181
+ });
182
+ return {
183
+ schemaVersion: 1,
184
+ package: { name: pkg.name, version: pkg.version },
185
+ exactTag,
186
+ distTag,
187
+ registry,
188
+ publishAction,
189
+ pack,
190
+ evidencePath: resolvedEvidencePath,
191
+ evidence,
192
+ };
193
+ }
194
+
195
+ function usage() {
196
+ return `Usage:
197
+ node scripts/npm-publish-transaction.mjs [--cwd <dir>] [--registry <url>]
198
+ [--dry-run-publish] [--skip-registry-lookup]
199
+ `;
200
+ }
201
+
202
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
203
+ try {
204
+ const argv = process.argv.slice(2);
205
+ if (hasFlag(argv, "help") || argv.includes("-h")) {
206
+ process.stdout.write(usage());
207
+ process.exit(0);
208
+ }
209
+ const result = npmPublishTransaction({
210
+ cwd: readArg(argv, "cwd", process.cwd()),
211
+ registry: readArg(argv, "registry", "https://registry.npmjs.org/"),
212
+ dryRunPublish: hasFlag(argv, "dry-run-publish"),
213
+ skipRegistryLookup: hasFlag(argv, "skip-registry-lookup"),
214
+ });
215
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
216
+ } catch (error) {
217
+ console.error(`npm-publish-transaction: ${error.message}`);
218
+ process.exitCode = 1;
219
+ }
220
+ }
@@ -0,0 +1,35 @@
1
+ import { readFileSync, writeFileSync } from "node:fs";
2
+ import crypto from "node:crypto";
3
+
4
+ const outputPath = ".buildchain/kfd-1/contract-world.witness.json";
5
+
6
+ const readJson = (filePath) => JSON.parse(readFileSync(filePath, "utf8"));
7
+ const sha256File = (filePath) => crypto.createHash("sha256").update(readFileSync(filePath)).digest("hex");
8
+
9
+ const witness = readJson(outputPath);
10
+ const standards = readJson("standards.json");
11
+ const standardsSha = sha256File("standards.json");
12
+ const registrySha = sha256File("registry.json");
13
+ const surfaceRegister = standards.standards?.["kfd-1"]?.surfaceRegister;
14
+ const registeredSurfaces = new Map((surfaceRegister?.surfaces ?? []).map((surface) => [surface.id, surface]));
15
+
16
+ witness.contractWorld.digest = `sha256:${standardsSha}`;
17
+ witness.canonicalPolicy.sha256 = standardsSha;
18
+ witness.registry.sha256 = registrySha;
19
+ witness.compatibilityImpactClasses = surfaceRegister?.compatibilityImpactClasses ?? [];
20
+ witness.surfaces = [...registeredSurfaces.values()].map((registered) => ({
21
+ name: registered.id,
22
+ sourcePath: registered.sourcePath,
23
+ sourceSha256: sha256File(registered.sourcePath),
24
+ artifactPath: registered.sourcePath,
25
+ expectedSha256: sha256File(registered.sourcePath),
26
+ byteForByte: true,
27
+ class: registered.class,
28
+ classes: registered.classes ?? [registered.class],
29
+ description: registered.description,
30
+ weldRationale: registered.weldRationale,
31
+ impactProjection: registered.impactProjection,
32
+ }));
33
+
34
+ writeFileSync(outputPath, `${JSON.stringify(witness, null, 2)}\n`);
35
+ console.log(`updated ${outputPath}`);
@@ -0,0 +1,304 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import crypto from "node:crypto";
3
+ import path from "node:path";
4
+
5
+ const releaseClaimPath = ".buildchain/kfd-2/public-release-trust.claim.json";
6
+ const trustClaimsPath = ".buildchain/kfd-2/kfd-foundation.trust-claims.json";
7
+ const trustAssessmentPath = ".buildchain/kfd-2/kfd-foundation.trust-assessment.json";
8
+
9
+ const readJson = (filePath) => JSON.parse(readFileSync(filePath, "utf8"));
10
+ const sha256File = (filePath) => crypto.createHash("sha256").update(readFileSync(filePath)).digest("hex");
11
+ const digestFile = (filePath) => `sha256:${sha256File(filePath)}`;
12
+ const pointer = (filePath, extra = {}) => ({
13
+ path: filePath,
14
+ sha256: sha256File(filePath),
15
+ ...extra,
16
+ });
17
+ const artifactPointer = (kind, filePath, extra = {}) => ({
18
+ kind,
19
+ path: filePath,
20
+ sha256: sha256File(filePath),
21
+ ...extra,
22
+ });
23
+ const evidence = (type, filePath, description, extra = {}) => ({
24
+ type,
25
+ pointer: artifactPointer(type === "schema" ? "schema" : type === "witness" ? "witness" : "file", filePath),
26
+ machineProvability: "machine-verifiable",
27
+ description,
28
+ ...extra,
29
+ });
30
+ const evidenceResult = (type, filePath, description, extra = {}) => ({
31
+ type,
32
+ result: "pass",
33
+ machineProvability: "machine-verifiable",
34
+ path: filePath,
35
+ digest: digestFile(filePath),
36
+ description,
37
+ ...extra,
38
+ });
39
+ const responsibility = {
40
+ owner: "KFD maintainers",
41
+ sourceOwner: "KFD maintainers",
42
+ verificationOwner: "KFD package self-verification",
43
+ decisionOwner: "KFD maintainers",
44
+ };
45
+ const naturalLanguageResidualRisk = {
46
+ id: "human-language-interpretation",
47
+ definedBy: "https://kfd.libkungfu.dev/schemas/kfd-2/trust-taxonomy.schema.json#/$defs/residualRisk",
48
+ riskType: "natural-language-semantic-risk",
49
+ trustImpact: "downgrade-warning",
50
+ machineProvability: "not-exhaustively-enumerable",
51
+ agentAction: "semantic-review-required",
52
+ reason: "Natural-language standard interpretation is inspectable and reviewable but cannot be exhaustively proved from package bytes.",
53
+ owner: "KFD maintainers",
54
+ };
55
+ const writeJson = (filePath, value) => {
56
+ mkdirSync(path.dirname(filePath), { recursive: true });
57
+ writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
58
+ console.log(`updated ${filePath}`);
59
+ };
60
+
61
+ const packageJson = readJson("package.json");
62
+ const releaseAnchor = readJson("kfd.release.json");
63
+
64
+ const sourceBindings = [
65
+ pointer("package.json", { id: "package-version-and-exports" }),
66
+ pointer("kfd.release.json", { id: "anchored-release-version" }),
67
+ pointer("registry.json", { id: "decision-registry" }),
68
+ pointer("standards.json", { id: "standards-metadata" }),
69
+ pointer("release-impact.json", { id: "release-impact-ledger" }),
70
+ pointer("buildchain.toml", { id: "buildchain-release-contract" }),
71
+ pointer("buildchain.contract-lock.json", { id: "buildchain-runtime-contract-lock" }),
72
+ ];
73
+
74
+ const machineEvidence = [
75
+ pointer("scripts/check.mjs", { id: "self-verification-command" }),
76
+ pointer(".github/workflows/build.yml", { id: "buildchain-build-workflow" }),
77
+ pointer(".github/workflows/buildchain-ref-promotion.yml", { id: "buildchain-promotion-workflow" }),
78
+ pointer("schemas/kfd-2/trust-taxonomy.schema.json", { id: "kfd-2-trust-taxonomy-schema" }),
79
+ pointer("schemas/kfd-2/trust-claims.schema.json", { id: "kfd-2-trust-claims-schema" }),
80
+ pointer("schemas/kfd-2/trust-assessment.schema.json", { id: "kfd-2-trust-assessment-schema" }),
81
+ pointer("schemas/kfd-2/release-claims.schema.json", { id: "kfd-2-release-claims-schema" }),
82
+ pointer("schemas/kfd-2/release-trust-passport.schema.json", { id: "kfd-2-release-trust-passport-schema" }),
83
+ ];
84
+
85
+ const hashes = Object.fromEntries(
86
+ [...sourceBindings, ...machineEvidence].map((entry) => [entry.id, entry.sha256]),
87
+ );
88
+
89
+ const releaseClaim = {
90
+ id: "kfd-public-release-trust",
91
+ public: true,
92
+ claim:
93
+ "The KFD npm release is backed by declared source facts, machine-readable evidence, artifact coordinates, verification, audit boundary, responsibility, and explicit residual-risk state.",
94
+ sourceBindings,
95
+ machineEvidence,
96
+ hashes,
97
+ artifacts: [
98
+ {
99
+ name: packageJson.name,
100
+ version: packageJson.version,
101
+ path: "package.json",
102
+ sha256: sha256File("package.json"),
103
+ },
104
+ {
105
+ name: "kfd-release-anchor",
106
+ version: releaseAnchor.npmVersion,
107
+ path: "kfd.release.json",
108
+ sha256: sha256File("kfd.release.json"),
109
+ },
110
+ ],
111
+ verification: {
112
+ result: "passed",
113
+ command: "node scripts/check.mjs",
114
+ },
115
+ auditBoundary: {
116
+ scope: "KFD public npm package release facts, package exports, release governance files, and Buildchain release-passport inputs",
117
+ enumerability: "closed-world",
118
+ },
119
+ responsibility: {
120
+ owner: "KFD maintainers",
121
+ sourceOwner: "KFD maintainers",
122
+ verificationOwner: "KFD package self-verification",
123
+ releaseDecisionOwner: "KFD maintainers",
124
+ releasePassportProofOwner: "Buildchain",
125
+ },
126
+ residualRisk: [],
127
+ };
128
+
129
+ writeJson(releaseClaimPath, releaseClaim);
130
+
131
+ const trustClaims = {
132
+ schemaVersion: 1,
133
+ contract: "kfd-2-trust-claims",
134
+ standard: "kfd-2",
135
+ projection: {
136
+ kind: "generic",
137
+ description: "KFD self-dogfood claims for assessing KFD-1, KFD-3, and KFD-4 from the generic KFD-2 trust model.",
138
+ },
139
+ claims: [
140
+ {
141
+ id: "kfd-1-contract-world-trust",
142
+ statement:
143
+ "KFD-1 is trustable as the KFD package contract-world rule because its surface register, schema, witness, and verification command are inspectable from committed package facts.",
144
+ subject: {
145
+ kind: "contract-world",
146
+ id: "kfd-1-surface-register",
147
+ standard: "kfd-1",
148
+ description: "KFD-1 non-drifting fact-source and compatibility-impact surface register.",
149
+ },
150
+ facts: [
151
+ artifactPointer("file", "standards.json"),
152
+ artifactPointer("schema", "schemas/kfd-1/contract-world.schema.json"),
153
+ ],
154
+ evidence: [
155
+ evidence("schema", "schemas/kfd-1/contract-world.schema.json", "KFD-1 contract-world schema is published as a package surface."),
156
+ evidence("file", "scripts/check.mjs", "The package check gate validates the KFD-1 schema, surface register, witness, and hashes."),
157
+ ],
158
+ verification: {
159
+ command: "node scripts/check.mjs",
160
+ expectedResult: "pass",
161
+ },
162
+ auditBoundary: {
163
+ scope: "KFD package KFD-1 surface-register, schema, witness, and self-verification gate",
164
+ enumerability: "closed-world",
165
+ },
166
+ residualRisk: [],
167
+ responsibility,
168
+ status: "enforced",
169
+ },
170
+ {
171
+ id: "kfd-3-collaboration-interface-trust",
172
+ statement:
173
+ "KFD-3 is trustable as a participant-facing collaboration interface because KFD publishes the declared interface, explicit value evidence, prebuild witness, artifact witness, extension path, and closure check.",
174
+ subject: {
175
+ kind: "collaboration-interface",
176
+ id: "kfd-3-collaboration-interface",
177
+ standard: "kfd-3",
178
+ description: "KFD package collaboration interface for humans, agents, maintainers, package consumers, site consumers, and release systems.",
179
+ },
180
+ facts: [
181
+ artifactPointer("file", ".buildchain/kfd-3/collaboration-interface.json"),
182
+ ],
183
+ evidence: [
184
+ evidence("schema", "schemas/kfd-3/collaboration-interface.schema.json", "KFD-3 collaboration interface schema is published."),
185
+ evidence("file", ".buildchain/kfd-3/collaboration-interface.json", "KFD-3 source collaboration interface declares reachable participant-facing surfaces and value evidence."),
186
+ evidence("file", "scripts/check.mjs", "The package check gate validates KFD-3 interface closure and witness parity."),
187
+ ],
188
+ verification: {
189
+ command: "node scripts/check.mjs",
190
+ expectedResult: "warning",
191
+ },
192
+ auditBoundary: {
193
+ scope: "KFD participant-facing collaboration surfaces, extension paths, and shipped witness files",
194
+ enumerability: "closed-world",
195
+ },
196
+ residualRisk: [naturalLanguageResidualRisk],
197
+ responsibility,
198
+ status: "enforced",
199
+ },
200
+ {
201
+ id: "kfd-4-observer-perspective-trust",
202
+ statement:
203
+ "KFD-4 is trustable as an observer-perspective interface because KFD publishes the schema, standards metadata, decision text, and verification gate for observer-relative timeline views.",
204
+ subject: {
205
+ kind: "observer-perspective",
206
+ id: "kfd-4-observer-perspective",
207
+ standard: "kfd-4",
208
+ description: "KFD-4 observer-perspective schema for perspective-bearing timeline views.",
209
+ },
210
+ facts: [
211
+ artifactPointer("file", "decisions/KFD-4.md"),
212
+ artifactPointer("file", "standards.json"),
213
+ artifactPointer("schema", "schemas/kfd-4/observer-perspective.schema.json"),
214
+ ],
215
+ evidence: [
216
+ evidence("schema", "schemas/kfd-4/observer-perspective.schema.json", "KFD-4 observer-perspective schema is published."),
217
+ evidence("file", "standards.json", "Standards metadata exposes the KFD-4 schema ID, path, interface version, and concept names."),
218
+ evidence("file", "scripts/check.mjs", "The package check gate validates the KFD-4 schema and standards metadata."),
219
+ ],
220
+ verification: {
221
+ command: "node scripts/check.mjs",
222
+ expectedResult: "pass",
223
+ },
224
+ auditBoundary: {
225
+ scope: "KFD-4 decision text, observer-perspective schema, standards metadata, and self-verification gate",
226
+ enumerability: "closed-world",
227
+ },
228
+ residualRisk: [],
229
+ responsibility,
230
+ status: "enforced",
231
+ },
232
+ ],
233
+ schemaEvolution: {
234
+ compatibilityRule:
235
+ "Compatible additions may keep schemaVersion 1; semantic, required-field, verification-meaning, or responsibility-boundary changes require a new interface version or contract.",
236
+ },
237
+ };
238
+ writeJson(trustClaimsPath, trustClaims);
239
+
240
+ const trustClaimsDigest = digestFile(trustClaimsPath);
241
+ const assessment = {
242
+ schemaVersion: 1,
243
+ contract: "kfd-2-trust-assessment",
244
+ standard: "kfd-2",
245
+ assessedClaims: {
246
+ schemaId: "https://kfd.libkungfu.dev/schemas/kfd-2/trust-claims.schema.json",
247
+ path: trustClaimsPath,
248
+ digest: trustClaimsDigest,
249
+ },
250
+ result: "warning",
251
+ projection: {
252
+ kind: "generic",
253
+ description: "Generic KFD-2 assessment of KFD-owned foundation and practice guideline claims.",
254
+ },
255
+ assessments: [
256
+ {
257
+ id: "assess-kfd-1-contract-world-trust",
258
+ claimId: "kfd-1-contract-world-trust",
259
+ subject: trustClaims.claims[0].subject,
260
+ result: "pass",
261
+ facts: trustClaims.claims[0].facts.map((entry) => evidenceResult(entry.kind, entry.path, `Fact ${entry.path} is present and hashable.`)),
262
+ evidence: trustClaims.claims[0].evidence.map((entry) => evidenceResult(entry.type, entry.pointer.path, entry.description)),
263
+ auditBoundary: trustClaims.claims[0].auditBoundary,
264
+ responsibility,
265
+ residualRisk: [],
266
+ },
267
+ {
268
+ id: "assess-kfd-3-collaboration-interface-trust",
269
+ claimId: "kfd-3-collaboration-interface-trust",
270
+ subject: trustClaims.claims[1].subject,
271
+ result: "warning",
272
+ facts: trustClaims.claims[1].facts.map((entry) => evidenceResult(entry.kind, entry.path, `Fact ${entry.path} is present and hashable.`)),
273
+ evidence: trustClaims.claims[1].evidence.map((entry) => evidenceResult(entry.type, entry.pointer.path, entry.description)),
274
+ auditBoundary: trustClaims.claims[1].auditBoundary,
275
+ responsibility,
276
+ residualRisk: [naturalLanguageResidualRisk],
277
+ },
278
+ {
279
+ id: "assess-kfd-4-observer-perspective-trust",
280
+ claimId: "kfd-4-observer-perspective-trust",
281
+ subject: trustClaims.claims[2].subject,
282
+ result: "pass",
283
+ facts: trustClaims.claims[2].facts.map((entry) => evidenceResult(entry.kind, entry.path, `Fact ${entry.path} is present and hashable.`)),
284
+ evidence: trustClaims.claims[2].evidence.map((entry) => evidenceResult(entry.type, entry.pointer.path, entry.description)),
285
+ auditBoundary: trustClaims.claims[2].auditBoundary,
286
+ responsibility,
287
+ residualRisk: [],
288
+ },
289
+ ],
290
+ unboundClaims: [],
291
+ downgradeReasons: [
292
+ {
293
+ id: "kfd-3-natural-language-semantics",
294
+ riskType: "natural-language-semantic-risk",
295
+ trustImpact: "downgrade-warning",
296
+ reason: "KFD-3 exposes machine-checkable collaboration surfaces and value evidence, but the human-language meaning of trusted value and non-coercive cooperation remains a reviewable semantic responsibility.",
297
+ agentAction: "semantic-review-required",
298
+ source: "kfd-3-collaboration-interface-trust",
299
+ },
300
+ ],
301
+ responsibility,
302
+ schemaEvolution: trustClaims.schemaEvolution,
303
+ };
304
+ writeJson(trustAssessmentPath, assessment);