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

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 +153 -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 +209 -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 +45 -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 +300 -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 +776 -15
@@ -0,0 +1,261 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import crypto from "node:crypto";
3
+ import path from "node:path";
4
+
5
+ const interfacePath = ".buildchain/kfd-3/collaboration-interface.json";
6
+ const prebuildPath = ".buildchain/kfd-3/collaboration-interface.prebuild.json";
7
+ const artifactPath = ".buildchain/kfd-3/collaboration-interface.artifact.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 hashablePath = (filePath) => filePath.split("#", 1)[0];
12
+ const pointer = (filePath, description = undefined) => ({
13
+ path: filePath,
14
+ sha256: sha256File(hashablePath(filePath)),
15
+ ...(description ? { description } : {}),
16
+ });
17
+
18
+ const writeJson = (filePath, value) => {
19
+ mkdirSync(path.dirname(filePath), { recursive: true });
20
+ writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
21
+ };
22
+
23
+ const packageJson = readJson("package.json");
24
+ const registry = readJson("registry.json");
25
+ const standards = readJson("standards.json");
26
+ const collaborationInterface = readJson(interfacePath);
27
+ const interfaceSha = sha256File(interfacePath);
28
+ const interfaceDigest = `sha256:${interfaceSha}`;
29
+
30
+ const decisionDocs = registry.entries.map((entry) => ({
31
+ id: `decision:${entry.slug}`,
32
+ sourcePath: entry.path,
33
+ sha256: sha256File(entry.path),
34
+ }));
35
+ const schemaSurfaces = [
36
+ "schemas/kfd-standards.schema.json",
37
+ "schemas/kfd-1/contract-world.schema.json",
38
+ "schemas/kfd-1/witness.schema.json",
39
+ "schemas/kfd-2/trust-taxonomy.schema.json",
40
+ "schemas/kfd-2/trust-claims.schema.json",
41
+ "schemas/kfd-2/trust-assessment.schema.json",
42
+ "schemas/kfd-2/release-claims.schema.json",
43
+ "schemas/kfd-2/release-trust-passport.schema.json",
44
+ "schemas/kfd-3/collaboration-interface.schema.json",
45
+ "schemas/kfd-3/witness.schema.json",
46
+ "schemas/kfd-4/observer-perspective.schema.json",
47
+ ].map((filePath) => ({
48
+ id: `schema:${filePath.replace(/^schemas\//, "").replace(/\.schema\.json$/, "").replace(/\//g, ":")}`,
49
+ sourcePath: filePath,
50
+ sha256: sha256File(filePath),
51
+ }));
52
+
53
+ const groupedSurfaces = {
54
+ docs: [
55
+ { id: "doc:readme", sourcePath: "README.md", sha256: sha256File("README.md") },
56
+ { id: "doc:trademarks", sourcePath: "TRADEMARKS.md", sha256: sha256File("TRADEMARKS.md") },
57
+ { id: "doc:docs-map", sourcePath: "docs/MAP.md", sha256: sha256File("docs/MAP.md") },
58
+ { id: "doc:kfd-1-usage", sourcePath: "docs/KFD-1-usage.md", sha256: sha256File("docs/KFD-1-usage.md") },
59
+ { id: "doc:kfd-2-usage", sourcePath: "docs/KFD-2-usage.md", sha256: sha256File("docs/KFD-2-usage.md") },
60
+ { id: "doc:kfd-3-usage", sourcePath: "docs/KFD-3-usage.md", sha256: sha256File("docs/KFD-3-usage.md") },
61
+ { id: "doc:kfd-4-usage", sourcePath: "docs/KFD-4-usage.md", sha256: sha256File("docs/KFD-4-usage.md") },
62
+ ...decisionDocs,
63
+ ],
64
+ schemas: schemaSurfaces,
65
+ standardsMetadata: [
66
+ { id: "metadata:registry", sourcePath: "registry.json", sha256: sha256File("registry.json") },
67
+ { id: "metadata:standards", sourcePath: "standards.json", sha256: sha256File("standards.json") },
68
+ { id: "metadata:release-impact", sourcePath: "release-impact.json", sha256: sha256File("release-impact.json") },
69
+ { id: "metadata:release-anchor", sourcePath: "kfd.release.json", sha256: sha256File("kfd.release.json") },
70
+ { id: "metadata:buildchain-contract-lock", sourcePath: "buildchain.contract-lock.json", sha256: sha256File("buildchain.contract-lock.json") },
71
+ { id: "metadata:kfd-2-public-release-trust-claim", sourcePath: ".buildchain/kfd-2/public-release-trust.claim.json", sha256: sha256File(".buildchain/kfd-2/public-release-trust.claim.json") },
72
+ { id: "metadata:kfd-2-foundation-trust-claims", sourcePath: ".buildchain/kfd-2/kfd-foundation.trust-claims.json", sha256: sha256File(".buildchain/kfd-2/kfd-foundation.trust-claims.json") },
73
+ { id: "metadata:kfd-2-foundation-trust-assessment", sourcePath: ".buildchain/kfd-2/kfd-foundation.trust-assessment.json", sha256: sha256File(".buildchain/kfd-2/kfd-foundation.trust-assessment.json") },
74
+ ],
75
+ packageExports: [
76
+ { id: "export:package-json", sourcePath: "package.json#exports", sha256: sha256File("package.json") },
77
+ { id: "export:npm-files", sourcePath: "package.json#files", sha256: sha256File("package.json") },
78
+ ],
79
+ siteConsumptionContracts: [
80
+ { id: "site:kfd-site-bundle", sourcePath: "site/kfd-site.json", sha256: sha256File("site/kfd-site.json") },
81
+ { id: "site:release-propagation", sourcePath: "buildchain.release-propagation.json", sha256: sha256File("buildchain.release-propagation.json") },
82
+ ],
83
+ };
84
+
85
+ const explicitSurfaces = collaborationInterface.surfaces.map((surface) => ({
86
+ id: surface.id,
87
+ name: surface.id,
88
+ kind: surface.kind,
89
+ participantProfile: Array.isArray(surface.participants) ? surface.participants.join(",") : "",
90
+ availability: surface.maturity || "shipped",
91
+ visibility: "public",
92
+ participantFacing: true,
93
+ public: true,
94
+ sourcePath: surface.discoverability?.path || "",
95
+ }));
96
+
97
+ const declaredSurfaceIds = new Set(explicitSurfaces.map((surface) => surface.id));
98
+ for (const entrypoint of collaborationInterface.minimalEntrypoints) {
99
+ if (declaredSurfaceIds.has(entrypoint.id)) continue;
100
+ explicitSurfaces.push({
101
+ id: entrypoint.id,
102
+ name: entrypoint.id,
103
+ kind: "entrypoint",
104
+ participantProfile: Array.isArray(entrypoint.participants) ? entrypoint.participants.join(",") : "",
105
+ availability: "shipped",
106
+ visibility: "public",
107
+ participantFacing: true,
108
+ public: true,
109
+ sourcePath: entrypoint.surface,
110
+ });
111
+ declaredSurfaceIds.add(entrypoint.id);
112
+ }
113
+
114
+ const valueEvidencePointers = (() => {
115
+ const entriesByPath = new Map();
116
+ for (const valueClaim of collaborationInterface.valueEvidence ?? []) {
117
+ for (const entry of [
118
+ ...(valueClaim.facts ?? []),
119
+ ...(valueClaim.evidence ?? []),
120
+ ...(valueClaim.trustAssessment ? [valueClaim.trustAssessment] : []),
121
+ ]) {
122
+ if (!entry?.path || entriesByPath.has(entry.path)) continue;
123
+ entriesByPath.set(
124
+ entry.path,
125
+ pointer(entry.path, `KFD-3 value evidence for ${valueClaim.id}: ${valueClaim.claim}`)
126
+ );
127
+ }
128
+ }
129
+ return [...entriesByPath.values()];
130
+ })();
131
+
132
+ const participantProfiles = collaborationInterface.participants.map((entry) => entry.id);
133
+ const responsibility = {
134
+ registryFactsOwner: "KFD maintainers",
135
+ artifactVerificationOwner: "KFD package self-verification",
136
+ releasePassportProofOwner: "Buildchain",
137
+ };
138
+ const residualRisk = [
139
+ {
140
+ id: "human-language-interpretation",
141
+ definedBy: "https://kfd.libkungfu.dev/schemas/kfd-2/trust-taxonomy.schema.json#/$defs/residualRisk",
142
+ riskType: "natural-language-semantic-risk",
143
+ trustImpact: "downgrade-warning",
144
+ machineProvability: "not-exhaustively-enumerable",
145
+ agentAction: "semantic-review-required",
146
+ reason: "Natural-language standard interpretation is inspectable and reviewable but not exhaustively enumerable from package bytes.",
147
+ owner: "KFD maintainers",
148
+ },
149
+ ];
150
+
151
+ const prebuild = {
152
+ schemaVersion: 1,
153
+ contract: "kungfu-buildchain-kfd-3-collaboration-interface-prebuild-witness",
154
+ id: "kfd-repository",
155
+ standard: "kfd-3",
156
+ supportLevel: "release",
157
+ source: {
158
+ repo: "kungfu-systems/kfd",
159
+ },
160
+ sourceRegistry: {
161
+ id: "kfd-collaboration-interface",
162
+ path: interfacePath,
163
+ sha256: interfaceSha,
164
+ },
165
+ collaborationInterfaceDigest: interfaceDigest,
166
+ collaborationInterface,
167
+ participantProfiles,
168
+ surfaces: explicitSurfaces,
169
+ ...groupedSurfaces,
170
+ auditBoundary: {
171
+ mode: "closed-world",
172
+ scope: "KFD participant-facing public collaboration/control surfaces shipped in the repository and npm package",
173
+ reachableSurfaceMode: "declared-boundary",
174
+ unclassifiedPolicy: "fail",
175
+ nonExhaustivelyEnumerableSurfaces: residualRisk,
176
+ },
177
+ residualRisk,
178
+ responsibility,
179
+ expectedArtifactVerification: {
180
+ command: "node scripts/check.mjs",
181
+ },
182
+ };
183
+
184
+ const artifact = {
185
+ schemaVersion: 1,
186
+ contract: "kfd-3-witness",
187
+ id: "kfd-repository",
188
+ standard: "kfd-3",
189
+ collaborationInterface: {
190
+ schemaId: standards.standards["kfd-3"].schemaIds.collaborationInterface,
191
+ digest: interfaceDigest,
192
+ },
193
+ sourceRegistry: {
194
+ id: "kfd-collaboration-interface",
195
+ path: interfacePath,
196
+ sha256: interfaceSha,
197
+ },
198
+ artifact: {
199
+ name: packageJson.name,
200
+ path: "npm:@kungfu-tech/kfd",
201
+ digest: interfaceDigest,
202
+ },
203
+ surfaces: explicitSurfaces,
204
+ ...groupedSurfaces,
205
+ evidence: {
206
+ minimalEntrypoints: collaborationInterface.minimalEntrypoints.map((entry) => pointer(entry.surface, entry.purpose)),
207
+ discoverability: [
208
+ pointer("README.md", "Human and agent entrypoint"),
209
+ pointer("TRADEMARKS.md", "Official status, trademark, and authority boundary"),
210
+ pointer("docs/MAP.md", "Documentation routing entrypoint"),
211
+ pointer("registry.json", "Machine-readable decision index"),
212
+ pointer("standards.json", "Machine-readable standards metadata"),
213
+ pointer(".buildchain/kfd-2/public-release-trust.claim.json", "KFD-2 public release trust claim"),
214
+ pointer(".buildchain/kfd-2/kfd-foundation.trust-claims.json", "KFD-2 generic trust claims for KFD self-dogfood"),
215
+ pointer(".buildchain/kfd-2/kfd-foundation.trust-assessment.json", "KFD-2 generic trust assessment for KFD self-dogfood"),
216
+ pointer("package.json", "Package export map"),
217
+ pointer("site/kfd-site.json", "Site content projection"),
218
+ ],
219
+ valueEvidence: valueEvidencePointers,
220
+ transparentConstraints: [
221
+ pointer("CONTRIBUTING.md", "Append-only decision and contribution constraints"),
222
+ pointer("TRADEMARKS.md", "Trademark and official-status constraints"),
223
+ pointer("scripts/check.mjs", "Repository self-verification gate"),
224
+ pointer("site/kfd-site.json", "Site rendering boundary"),
225
+ ],
226
+ choicePaths: [
227
+ pointer("README.md", "Human reading path"),
228
+ pointer("registry.json", "Agent registry path"),
229
+ pointer("standards.json", "Agent standards metadata path"),
230
+ pointer(".buildchain/kfd-2/public-release-trust.claim.json", "Agent release trust claim path"),
231
+ pointer(".buildchain/kfd-2/kfd-foundation.trust-claims.json", "Agent generic trust claims path"),
232
+ pointer(".buildchain/kfd-2/kfd-foundation.trust-assessment.json", "Agent generic trust assessment path"),
233
+ pointer("package.json", "Package consumption path"),
234
+ ],
235
+ manuals: [
236
+ pointer("docs/MAP.md"),
237
+ pointer("TRADEMARKS.md"),
238
+ pointer("docs/KFD-1-usage.md"),
239
+ pointer("docs/KFD-2-usage.md"),
240
+ pointer("docs/KFD-3-usage.md"),
241
+ pointer("docs/KFD-4-usage.md"),
242
+ ],
243
+ },
244
+ closure: {
245
+ classificationMode: "closed-world",
246
+ reachableEntrypoints: collaborationInterface.minimalEntrypoints.map((entry) => entry.id),
247
+ classifiedEntrypoints: collaborationInterface.minimalEntrypoints.map((entry) => entry.id),
248
+ unclassifiedEntrypoints: [],
249
+ },
250
+ verifier: {
251
+ name: "kfd self-verification",
252
+ command: "node scripts/check.mjs",
253
+ },
254
+ residualRisk,
255
+ result: "pass",
256
+ };
257
+
258
+ writeJson(prebuildPath, prebuild);
259
+ writeJson(artifactPath, artifact);
260
+ console.log(`updated ${prebuildPath}`);
261
+ console.log(`updated ${artifactPath}`);
@@ -0,0 +1,353 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { pathToFileURL } from "node:url";
3
+
4
+ const README_PATH = "README.md";
5
+ const REGISTRY_PATH = "registry.json";
6
+ const SITE_BUNDLE_PATH = "site/kfd-site.json";
7
+
8
+ const normalizeLines = (value) => String(value || "").replace(/\r\n/g, "\n").trim();
9
+
10
+ const paragraphBlocks = (markdown) => normalizeLines(markdown)
11
+ .split(/\n{2,}/)
12
+ .map((block) => block.replace(/\n/g, " ").trim())
13
+ .filter(Boolean);
14
+
15
+ const stripInlineCode = (value) => String(value || "").replace(/`([^`]+)`/g, "$1");
16
+
17
+ const parseReadme = (markdown) => {
18
+ const content = normalizeLines(markdown);
19
+ const titleMatch = content.match(/^#\s+(.+)$/m);
20
+ if (!titleMatch) throw new Error("README.md must start with an H1 title");
21
+
22
+ const sections = {};
23
+ const headingPattern = /^##\s+(.+)$/gm;
24
+ const headings = [];
25
+ let match;
26
+ while ((match = headingPattern.exec(content))) {
27
+ headings.push({ title: match[1], index: match.index, bodyStart: headingPattern.lastIndex });
28
+ }
29
+ for (let index = 0; index < headings.length; index += 1) {
30
+ const current = headings[index];
31
+ const next = headings[index + 1];
32
+ sections[current.title] = content.slice(current.bodyStart, next ? next.index : content.length).trim();
33
+ }
34
+
35
+ const intro = content.slice(titleMatch[0].length, headings[0]?.index ?? content.length).trim();
36
+ return {
37
+ title: titleMatch[1].trim(),
38
+ intro,
39
+ sections,
40
+ };
41
+ };
42
+
43
+ const introLead = (intro) => {
44
+ const blocks = paragraphBlocks(intro);
45
+ return {
46
+ lead: blocks[0] || "",
47
+ decisionKinds: blocks.find((block) => block.startsWith("KFDs can be ")) || "",
48
+ };
49
+ };
50
+
51
+ const parseFoundationTriad = (markdown) => {
52
+ const code = markdown.match(/```text\n([\s\S]*?)\n```/);
53
+ if (!code) throw new Error("Foundation triad must include a text code block");
54
+ const before = markdown.slice(0, code.index).trim();
55
+ const after = markdown.slice((code.index ?? 0) + code[0].length).trim();
56
+ const commitments = code[1].split("\n").map((line) => {
57
+ const item = line.match(/^(KFD-[0-9]+):\s+(.+)$/);
58
+ if (!item) throw new Error(`invalid foundation triad line: ${line}`);
59
+ return { id: item[1], text: item[2] };
60
+ });
61
+ return {
62
+ heading: "Foundation triad",
63
+ intro: paragraphBlocks(before)[0] || "",
64
+ commitments,
65
+ summary: paragraphBlocks(after)[0] || "",
66
+ };
67
+ };
68
+
69
+ const parseMarkdownTable = (markdown) => {
70
+ const rows = markdown.split("\n").filter((line) => line.trim().startsWith("|"));
71
+ if (rows.length < 3) return [];
72
+ return rows.slice(2).map((row) => row.trim().replace(/^\||\|$/g, "").split("|").map((cell) => stripInlineCode(cell.trim())))
73
+ .filter((cells) => cells.length >= 4)
74
+ .map(([layer, decision, readerQuestion, commitment]) => ({
75
+ layer,
76
+ decision,
77
+ readerQuestion,
78
+ commitment,
79
+ }));
80
+ };
81
+
82
+ const parseFoundationModel = (markdown) => {
83
+ const chainMatch = markdown.match(/```text\n([\s\S]*?)\n```/);
84
+ if (!chainMatch) throw new Error("Foundation model must include the chain text code block");
85
+ const beforeChain = markdown.slice(0, chainMatch.index).trim();
86
+ const afterChain = markdown.slice((chainMatch.index ?? 0) + chainMatch[0].length).trim();
87
+ return {
88
+ heading: "Foundation model",
89
+ intro: paragraphBlocks(beforeChain)[0] || "",
90
+ layers: parseMarkdownTable(beforeChain),
91
+ chain: chainMatch[1].trim(),
92
+ explanation: paragraphBlocks(afterChain),
93
+ };
94
+ };
95
+
96
+ const parsePracticeGuidelines = (markdown) => ({
97
+ heading: "Practice guidelines",
98
+ intro: paragraphBlocks(markdown)[0] || "",
99
+ guidelines: parseMarkdownTable(markdown),
100
+ explanation: paragraphBlocks(markdown).slice(1),
101
+ });
102
+
103
+ const parseProductProofPath = (markdown) => ({
104
+ heading: "Product proof path",
105
+ body: paragraphBlocks(markdown)[0] || "",
106
+ });
107
+
108
+ const usagePathForEntry = (entry) => `docs/KFD-${entry.number}-usage.md`;
109
+ const usageUrlForEntry = (entry) => `${entry.url}/usage`;
110
+
111
+ const buildUsagePages = (entries) => entries.map((entry) => {
112
+ const usagePath = usagePathForEntry(entry);
113
+ return {
114
+ id: `${entry.id}-usage`,
115
+ decisionId: entry.id,
116
+ decisionNumber: entry.number,
117
+ parentPath: entry.path,
118
+ parentUrl: entry.url,
119
+ path: usagePath,
120
+ url: usageUrlForEntry(entry),
121
+ sourcePath: usagePath,
122
+ sourceExists: existsSync(usagePath),
123
+ relationship: "usage-child-of-decision",
124
+ title: `${entry.id} usage`,
125
+ };
126
+ });
127
+
128
+ const section = ({ id, sourceHeading, title, markdown, role, priority, presentation, firstScreen = false }) => ({
129
+ id,
130
+ sourcePath: README_PATH,
131
+ sourceHeading,
132
+ title,
133
+ renderRole: role,
134
+ homepagePriority: priority,
135
+ defaultPresentation: presentation,
136
+ includeInFirstScreen: firstScreen,
137
+ markdown: normalizeLines(markdown),
138
+ });
139
+
140
+ export const buildSiteBundle = ({ readmeText, registry }) => {
141
+ const readme = parseReadme(readmeText);
142
+ const { lead, decisionKinds } = introLead(readme.intro);
143
+ const foundationTriad = parseFoundationTriad(readme.sections["Foundation triad"] || "");
144
+ const foundationModel = parseFoundationModel(readme.sections["Foundation model"] || "");
145
+ const practiceGuidelines = parsePracticeGuidelines(readme.sections["Practice guidelines"] || "");
146
+ const productProofPath = parseProductProofPath(readme.sections["Product proof path"] || "");
147
+ const entries = registry.entries || [];
148
+
149
+ const homepageSections = [
150
+ section({
151
+ id: "foundation-triad",
152
+ sourceHeading: "Foundation triad",
153
+ title: "Foundation triad",
154
+ markdown: readme.sections["Foundation triad"],
155
+ role: "first-screen",
156
+ priority: 10,
157
+ presentation: "triad-cards",
158
+ firstScreen: true,
159
+ }),
160
+ section({
161
+ id: "foundation-model",
162
+ sourceHeading: "Foundation model",
163
+ title: "Foundation model",
164
+ markdown: readme.sections["Foundation model"],
165
+ role: "primary",
166
+ priority: 20,
167
+ presentation: "layered-model",
168
+ firstScreen: true,
169
+ }),
170
+ section({
171
+ id: "adoption-boundary",
172
+ sourceHeading: "Adoption boundary",
173
+ title: "Adoption boundary",
174
+ markdown: readme.sections["Adoption boundary"],
175
+ role: "primary",
176
+ priority: 25,
177
+ presentation: "boundary-note",
178
+ }),
179
+ section({
180
+ id: "practice-guidelines",
181
+ sourceHeading: "Practice guidelines",
182
+ title: "Practice guidelines",
183
+ markdown: readme.sections["Practice guidelines"],
184
+ role: "primary",
185
+ priority: 27,
186
+ presentation: "practice-table",
187
+ }),
188
+ section({
189
+ id: "product-proof-path",
190
+ sourceHeading: "Product proof path",
191
+ title: "Product proof path",
192
+ markdown: readme.sections["Product proof path"],
193
+ role: "primary",
194
+ priority: 30,
195
+ presentation: "proof-path",
196
+ }),
197
+ section({
198
+ id: "agent-quickstart",
199
+ sourceHeading: "Agent Quickstart",
200
+ title: "Agent Quickstart",
201
+ markdown: readme.sections["Agent Quickstart"],
202
+ role: "support",
203
+ priority: 40,
204
+ presentation: "ordered-steps",
205
+ }),
206
+ section({
207
+ id: "decision-metadata",
208
+ sourceHeading: "Decision metadata",
209
+ title: "Decision metadata",
210
+ markdown: readme.sections["Decision metadata"],
211
+ role: "support",
212
+ priority: 50,
213
+ presentation: "fact-source",
214
+ }),
215
+ ];
216
+
217
+ return {
218
+ schemaVersion: 1,
219
+ contract: "kfd-site-bundle",
220
+ source: {
221
+ package: "@kungfu-tech/kfd",
222
+ homepageTextSource: README_PATH,
223
+ registry: REGISTRY_PATH,
224
+ decisionsDir: "decisions",
225
+ },
226
+ routes: {
227
+ home: "/",
228
+ decisionPattern: "/{number}",
229
+ decisionUsagePattern: "/{number}/usage",
230
+ llms: "/llms.txt",
231
+ manifest: "/manifest.json",
232
+ },
233
+ homepage: {
234
+ title: readme.title,
235
+ lead,
236
+ decisionKinds,
237
+ foundationTriad,
238
+ foundationModel,
239
+ practiceGuidelines,
240
+ productProofPath,
241
+ currentDecisions: {
242
+ heading: "Current decisions",
243
+ source: REGISTRY_PATH,
244
+ },
245
+ sections: homepageSections,
246
+ displayPlan: {
247
+ firstScreen: {
248
+ include: ["title", "lead", "foundation-triad", "foundation-model.chain"],
249
+ maxPrimarySections: 2,
250
+ note: "The first viewport should establish KFD identity and the three-decision worldview without showing renderer or developer contract text.",
251
+ },
252
+ primary: ["foundation-triad", "foundation-model", "adoption-boundary", "practice-guidelines", "product-proof-path"],
253
+ support: ["agent-quickstart", "decision-metadata"],
254
+ currentDecisions: {
255
+ source: REGISTRY_PATH,
256
+ placement: "after-primary",
257
+ ids: entries.map((entry) => entry.id),
258
+ },
259
+ },
260
+ rendererContract: {
261
+ ...section({
262
+ id: "homepage-content-contract",
263
+ sourceHeading: "Homepage content contract",
264
+ title: "Homepage content contract",
265
+ markdown: readme.sections["Homepage content contract"],
266
+ role: "renderer-contract",
267
+ priority: 90,
268
+ presentation: "developer-note",
269
+ }),
270
+ renderAsHomepageContent: false,
271
+ note: "This is a machine/renderer contract for site implementers. It should not be rendered as ordinary homepage content.",
272
+ },
273
+ },
274
+ decisionPages: {
275
+ source: REGISTRY_PATH,
276
+ bodySource: "registry.entries[].path",
277
+ stableUrlField: "url",
278
+ usagePages: {
279
+ source: "registry.entries[] + docs/KFD-N-usage.md",
280
+ bodySource: "docs/KFD-{number}-usage.md",
281
+ stableUrlPattern: "/{number}/usage",
282
+ relationship: "usage-child-of-decision",
283
+ pages: buildUsagePages(entries),
284
+ },
285
+ metadata: {
286
+ licenseBoundary: {
287
+ license: "Apache-2.0",
288
+ licenseFile: "LICENSE",
289
+ officialStatusAndTrademarks: "TRADEMARKS.md",
290
+ summary: "Apache-2.0 covers repository contents; it does not grant KFD/Kungfu trademarks, official status, certification status, or endorsement.",
291
+ },
292
+ publicFactSource: {
293
+ kind: "git-repository",
294
+ host: "github",
295
+ repository: "kungfu-systems/kfd",
296
+ url: "https://github.com/kungfu-systems/kfd",
297
+ loadBearingCoordinate: "commit-addressed repository contents",
298
+ stableRenderedIndex: "https://kfd.libkungfu.dev",
299
+ canonicalPaths: [
300
+ "decisions/KFD-N.md",
301
+ REGISTRY_PATH,
302
+ "standards.json",
303
+ ],
304
+ projectionSurfaces: [
305
+ "https://kfd.libkungfu.dev/N",
306
+ "npm:@kungfu-tech/kfd",
307
+ "Buildchain release passports",
308
+ ],
309
+ extensionRequestNote: "GitHub issues are extension request paths; KFD facts are created only by committed repository contents.",
310
+ },
311
+ },
312
+ },
313
+ renderingBoundary: {
314
+ ownedByKfd: [
315
+ "homepage title and text",
316
+ "homepage section projection from README.md",
317
+ "foundation triad commitments",
318
+ "foundation model layers and chain",
319
+ "product proof path text",
320
+ "agent quickstart text",
321
+ "decision metadata",
322
+ "decision metadata fact source",
323
+ "license and official-status boundary",
324
+ "decision markdown bodies",
325
+ "decision usage page mapping",
326
+ "decision usage markdown bodies",
327
+ ],
328
+ ownedBySite: [
329
+ "HTML structure",
330
+ "CSS",
331
+ "responsive layout",
332
+ "navigation layout",
333
+ "visual assets",
334
+ "decorative images",
335
+ "markdown-to-HTML renderer",
336
+ "section presentation and progressive disclosure within KFD displayPlan constraints",
337
+ ],
338
+ },
339
+ };
340
+ };
341
+
342
+ export const readInputs = () => ({
343
+ readmeText: readFileSync(README_PATH, "utf8"),
344
+ registry: JSON.parse(readFileSync(REGISTRY_PATH, "utf8")),
345
+ });
346
+
347
+ export const generatedSiteBundle = () => buildSiteBundle(readInputs());
348
+
349
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
350
+ const bundle = generatedSiteBundle();
351
+ writeFileSync(SITE_BUNDLE_PATH, `${JSON.stringify(bundle, null, 2)}\n`);
352
+ console.log(`updated ${SITE_BUNDLE_PATH}`);
353
+ }