@kungfu-tech/buildchain 3.0.6 → 3.0.7-alpha.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.
Files changed (64) hide show
  1. package/README.md +4 -2
  2. package/actions/release-tail/README.md +17 -0
  3. package/bin/buildchain.mjs +11 -0
  4. package/bin/internal/command-registry.mjs +2 -0
  5. package/contracts/fixtures/release-tail-capabilities-v1/kungfu-alpha.json +273 -0
  6. package/contracts/publication-rehearsal-capsule-v1.schema.json +173 -0
  7. package/contracts/release-tail-capabilities-v1.schema.json +199 -0
  8. package/contracts/release-tail-provider-bindings-v1.schema.json +56 -0
  9. package/dist/site/agent-index.json +3 -0
  10. package/dist/site/artifact-schemas.json +6 -0
  11. package/dist/site/buildchain-contract.json +35 -20
  12. package/dist/site/buildchain-site.json +307 -17
  13. package/dist/site/capability-registry.json +12 -9
  14. package/dist/site/cli-registry.json +102 -0
  15. package/dist/site/controller-registry.json +14 -2
  16. package/dist/site/kfd-claims.json +247 -16
  17. package/dist/site/kfd-upstream-aggregate.json +1 -1
  18. package/dist/site/manual-registry.json +48 -3
  19. package/dist/site/node-api-registry.json +3108 -1409
  20. package/dist/site/page-registry.json +275 -9
  21. package/dist/site/public-surface-audit.json +304 -15
  22. package/dist/site/publication-authority-registry.json +26 -1
  23. package/dist/site/publication-registry.json +4 -4
  24. package/dist/site/release-provenance.json +5 -0
  25. package/dist/site/schemas/publication-rehearsal-capsule-v1.schema.json +269 -0
  26. package/dist/site/schemas/release-tail-capabilities-v1.schema.json +353 -0
  27. package/dist/site/schemas/release-tail-provider-bindings-v1.schema.json +94 -0
  28. package/dist/site/site-manifest.json +31 -7
  29. package/dist/site/workflow-registry.json +86 -9
  30. package/docs/MAP.md +5 -2
  31. package/docs/cli-reference.md +136 -0
  32. package/docs/node-api-reference.md +233 -84
  33. package/docs/publication-rehearsal.md +94 -0
  34. package/docs/release-tail-contract.md +160 -0
  35. package/docs/release-tail-provider-plane.md +120 -0
  36. package/package.json +8 -3
  37. package/packages/core/buildchain-agent-manuals.js +3 -0
  38. package/packages/core/buildchain-kfd-claims.js +1 -1
  39. package/packages/core/buildchain-publication-authority.js +1 -0
  40. package/packages/core/index.js +39 -0
  41. package/packages/core/paper-agent-entry.js +11 -5
  42. package/packages/core/paper-repository.js +1 -0
  43. package/packages/core/paper-scaffold-content.js +21 -0
  44. package/packages/core/paper.js +28 -2
  45. package/packages/core/publication-rehearsal-projection.js +173 -0
  46. package/packages/core/publication-rehearsal-runtime.js +909 -0
  47. package/packages/core/release-tail-compatibility.js +60 -0
  48. package/packages/core/release-tail-provider-adapters.js +461 -0
  49. package/packages/core/release-tail-provider-plane.js +1228 -0
  50. package/scripts/assemble-publication-artifact-admission.mjs +1 -1
  51. package/scripts/assemble-self-publication-admission.mjs +1 -1
  52. package/scripts/buildchain-cli-help.mjs +13 -0
  53. package/scripts/check-core-mechanism-inventory.mjs +347 -0
  54. package/scripts/check-inventory.mjs +8 -8
  55. package/scripts/check-maintainability.mjs +9 -2
  56. package/scripts/check-release-tail-contract.mjs +435 -0
  57. package/scripts/generate-channel-promotion-workflow.mjs +10 -8
  58. package/scripts/generate-site-bundle.mjs +24 -0
  59. package/scripts/init-repo.mjs +26 -2
  60. package/scripts/materialize-self-release-candidate-version.mjs +131 -0
  61. package/scripts/release-tail.mjs +159 -0
  62. package/scripts/site-capability-metadata.mjs +11 -0
  63. package/scripts/v4-architecture.mjs +600 -0
  64. package/scripts/workflow-call-contract.mjs +184 -5
@@ -46,6 +46,11 @@ import {
46
46
  scaffoldReadme,
47
47
  } from "./paper-scaffold-content.js";
48
48
  import { executePaperNpmBootstrap as executePaperNpmBootstrapOperation } from "./paper-npm-bootstrap.js";
49
+ import {
50
+ appendPublicationRehearsalToml,
51
+ projectPublicationRehearsalToml,
52
+ publicationRehearsalWorkflow,
53
+ } from "./publication-rehearsal-projection.js";
49
54
 
50
55
  export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
51
56
  export {
@@ -114,6 +119,7 @@ const PAPER_SCAFFOLD_PATHS = Object.freeze([
114
119
  PAPER_PATHS.buildWorkflow,
115
120
  PAPER_PATHS.verifyWorkflow,
116
121
  PAPER_PATHS.releaseWorkflow,
122
+ PAPER_PATHS.rehearsalWorkflow,
117
123
  PAPER_PATHS.pnpmWorkspace,
118
124
  PAPER_PATHS.provisioningAuthority,
119
125
  "Makefile",
@@ -350,7 +356,7 @@ immutable_base_url = ${tomlString(joinUrl(siteBaseUrl, "archive").replace(/\/$/,
350
356
  registry_path = ".buildchain/publication/publication-registry.json"
351
357
  `
352
358
  : "";
353
- return `schema = 1
359
+ return appendPublicationRehearsalToml(`schema = 1
354
360
 
355
361
  [project]
356
362
  type = "publication-artifact"
@@ -384,7 +390,7 @@ command = "make pdf"
384
390
 
385
391
  [lifecycle.verify]
386
392
  command = "make check"
387
- `;
393
+ `);
388
394
  }
389
395
 
390
396
  function scaffoldBuildWorkflow(
@@ -525,6 +531,7 @@ export function createPaperProvisioningAuthority({
525
531
  buildWorkflow,
526
532
  verifyWorkflow,
527
533
  releaseWorkflow,
534
+ rehearsalWorkflow,
528
535
  agentEntry,
529
536
  agentInstructions,
530
537
  environment = "",
@@ -564,6 +571,12 @@ export function createPaperProvisioningAuthority({
564
571
  reusablePath: ".github/workflows/paper-release-sealed.yml",
565
572
  reusableRef: buildchainSha,
566
573
  },
574
+ rehearsal: {
575
+ path: PAPER_PATHS.rehearsalWorkflow,
576
+ sourceDigest: sha256Text(rehearsalWorkflow),
577
+ reusablePath: ".github/workflows/release-tail.yml",
578
+ reusableRef: buildchainSha,
579
+ },
567
580
  },
568
581
  agentEntry: {
569
582
  contract: PAPER_AGENT_ENTRY_CONTRACT,
@@ -630,6 +643,7 @@ function scaffoldFiles({
630
643
  releasePassportProductName: title,
631
644
  });
632
645
  const verifyWorkflow = scaffoldVerifyWorkflow(buildchainSha);
646
+ const rehearsalWorkflow = publicationRehearsalWorkflow(buildchainSha);
633
647
  const agentEntry = paperAgentEntryFiles({
634
648
  cwd,
635
649
  buildchainVersion,
@@ -647,6 +661,7 @@ function scaffoldFiles({
647
661
  buildWorkflow,
648
662
  verifyWorkflow,
649
663
  releaseWorkflow,
664
+ rehearsalWorkflow,
650
665
  agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
651
666
  agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
652
667
  });
@@ -667,6 +682,7 @@ function scaffoldFiles({
667
682
  [PAPER_PATHS.buildWorkflow, buildWorkflow],
668
683
  [PAPER_PATHS.verifyWorkflow, verifyWorkflow],
669
684
  [PAPER_PATHS.releaseWorkflow, releaseWorkflow],
685
+ [PAPER_PATHS.rehearsalWorkflow, rehearsalWorkflow],
670
686
  [PAPER_PATHS.pnpmWorkspace, paperPnpmWorkspace("", buildchainVersion)],
671
687
  [PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
672
688
  ...agentEntry,
@@ -964,6 +980,7 @@ function migrationFiles({
964
980
  releasePassportProductName: config.publication.title,
965
981
  });
966
982
  const verifyWorkflow = scaffoldVerifyWorkflow(runtimeSha);
983
+ const rehearsalWorkflow = publicationRehearsalWorkflow(runtimeSha);
967
984
  const agentEntry = paperAgentEntryFiles({
968
985
  cwd,
969
986
  buildchainVersion: runtimeIdentity.version,
@@ -978,6 +995,7 @@ function migrationFiles({
978
995
  buildWorkflow,
979
996
  verifyWorkflow,
980
997
  releaseWorkflow,
998
+ rehearsalWorkflow,
981
999
  agentEntry: agentEntry.get(PAPER_PATHS.agentEntry),
982
1000
  agentInstructions: agentEntry.get(PAPER_PATHS.agentInstructions),
983
1001
  });
@@ -997,11 +1015,18 @@ function migrationFiles({
997
1015
  runtimeIdentity.version,
998
1016
  );
999
1017
  const files = new Map([
1018
+ [
1019
+ PAPER_PATHS.config,
1020
+ projectPublicationRehearsalToml(
1021
+ fs.readFileSync(path.resolve(cwd, PAPER_PATHS.config), "utf8"),
1022
+ ),
1023
+ ],
1000
1024
  [PAPER_PATHS.contractLock, contractLockText],
1001
1025
  [PAPER_PATHS.versionPin, `${runtimeIdentity.version}\n`],
1002
1026
  [PAPER_PATHS.buildWorkflow, buildWorkflow],
1003
1027
  [PAPER_PATHS.verifyWorkflow, verifyWorkflow],
1004
1028
  [PAPER_PATHS.releaseWorkflow, releaseWorkflow],
1029
+ [PAPER_PATHS.rehearsalWorkflow, rehearsalWorkflow],
1005
1030
  [PAPER_PATHS.pnpmWorkspace, pnpmWorkspace],
1006
1031
  [PAPER_PATHS.provisioningAuthority, jsonText(provisioningAuthority)],
1007
1032
  ...agentEntry,
@@ -1755,6 +1780,7 @@ function validatePaperProvisioningAuthority(cwd) {
1755
1780
  value.workflows?.build,
1756
1781
  value.workflows?.verify,
1757
1782
  value.workflows?.release,
1783
+ value.workflows?.rehearsal,
1758
1784
  ]) {
1759
1785
  if (!workflow?.path || !workflow?.sourceDigest) {
1760
1786
  errors.push("paper workflow authority is incomplete");
@@ -0,0 +1,173 @@
1
+ import {
2
+ PUBLICATION_REHEARSAL_CAPSULE_CONTRACT,
3
+ PUBLICATION_REHEARSAL_COMMAND,
4
+ RELEASE_LOCAL_CONSTRUCTIBILITY_ADR,
5
+ RELEASE_LOCAL_CONSTRUCTIBILITY_INVARIANT,
6
+ } from "./publication-rehearsal-runtime.js";
7
+
8
+ export const PUBLICATION_REHEARSAL_AGENT_SECTION_START =
9
+ "<!-- buildchain:publication-rehearsal:v1:start -->";
10
+ export const PUBLICATION_REHEARSAL_AGENT_SECTION_END =
11
+ "<!-- buildchain:publication-rehearsal:v1:end -->";
12
+ export const PUBLICATION_REHEARSAL_WORKFLOW_PATH =
13
+ ".github/workflows/publication-rehearsal.yml";
14
+
15
+ function tomlString(value) {
16
+ return JSON.stringify(value);
17
+ }
18
+
19
+ export function publicationRehearsalToml() {
20
+ return `[publication_rehearsal]
21
+ contract = ${tomlString(PUBLICATION_REHEARSAL_CAPSULE_CONTRACT)}
22
+ adr = ${tomlString(RELEASE_LOCAL_CONSTRUCTIBILITY_ADR)}
23
+ invariant = ${tomlString(RELEASE_LOCAL_CONSTRUCTIBILITY_INVARIANT)}
24
+ command = ${tomlString(PUBLICATION_REHEARSAL_COMMAND)}
25
+ capsule = ".buildchain/publication/rehearsal-capsule.json"
26
+ capsule_root = ".buildchain/publication/candidate"
27
+ state = ".buildchain/publication/rehearsal-state.json"
28
+ evidence = ".buildchain/publication/rehearsal-evidence.json"
29
+ `;
30
+ }
31
+
32
+ export function assertPublicationRehearsalConfig(config) {
33
+ const section = config?.publication_rehearsal;
34
+ if (!section || typeof section !== "object" || Array.isArray(section)) {
35
+ throw new Error("publication_rehearsal table is missing");
36
+ }
37
+ const expected = {
38
+ contract: PUBLICATION_REHEARSAL_CAPSULE_CONTRACT,
39
+ adr: RELEASE_LOCAL_CONSTRUCTIBILITY_ADR,
40
+ invariant: RELEASE_LOCAL_CONSTRUCTIBILITY_INVARIANT,
41
+ command: PUBLICATION_REHEARSAL_COMMAND,
42
+ capsule: ".buildchain/publication/rehearsal-capsule.json",
43
+ capsule_root: ".buildchain/publication/candidate",
44
+ state: ".buildchain/publication/rehearsal-state.json",
45
+ evidence: ".buildchain/publication/rehearsal-evidence.json",
46
+ };
47
+ const actualKeys = Object.keys(section).sort();
48
+ const expectedKeys = Object.keys(expected).sort();
49
+ if (actualKeys.join("\n") !== expectedKeys.join("\n")) {
50
+ throw new Error(
51
+ `publication_rehearsal fields must be exactly: ${expectedKeys.join(", ")}`,
52
+ );
53
+ }
54
+ for (const [key, value] of Object.entries(expected)) {
55
+ if (section[key] !== value) {
56
+ throw new Error(`publication_rehearsal.${key} is stale or unsupported`);
57
+ }
58
+ }
59
+ return structuredClone(section);
60
+ }
61
+
62
+ export function appendPublicationRehearsalToml(source) {
63
+ const current = String(source || "").trimEnd();
64
+ if (/^\[publication_rehearsal\]$/mu.test(current)) {
65
+ throw new Error(
66
+ "buildchain config already contains a publication_rehearsal table",
67
+ );
68
+ }
69
+ return `${current}\n\n${publicationRehearsalToml()}`;
70
+ }
71
+
72
+ export function projectPublicationRehearsalToml(source) {
73
+ const current = String(source || "");
74
+ const start = current.search(/^\[publication_rehearsal\]\s*$/mu);
75
+ if (start === -1) return appendPublicationRehearsalToml(current);
76
+ const remainder = current.slice(start);
77
+ const nextTable = remainder
78
+ .slice(remainder.indexOf("\n") + 1)
79
+ .search(/^\[[^\n]+\]\s*$/mu);
80
+ const end =
81
+ nextTable === -1
82
+ ? current.length
83
+ : start + remainder.indexOf("\n") + 1 + nextTable;
84
+ const prefix = current.slice(0, start).trimEnd();
85
+ const suffix = current.slice(end).trimStart();
86
+ return `${prefix}\n\n${publicationRehearsalToml()}${suffix ? `\n${suffix}` : ""}`;
87
+ }
88
+
89
+ export function publicationRehearsalAgentInstructions() {
90
+ return `${PUBLICATION_REHEARSAL_AGENT_SECTION_START}
91
+ ## Publication rehearsal (required)
92
+
93
+ Buildchain release behavior follows
94
+ \`${RELEASE_LOCAL_CONSTRUCTIBILITY_ADR}\`. ${RELEASE_LOCAL_CONSTRUCTIBILITY_INVARIANT}
95
+
96
+ Before hosted publication, restore the explicit
97
+ \`${PUBLICATION_REHEARSAL_CAPSULE_CONTRACT}\` capsule and run exactly:
98
+
99
+ \`\`\`sh
100
+ ${PUBLICATION_REHEARSAL_COMMAND}
101
+ \`\`\`
102
+
103
+ Simulation and replay evidence never claim external publication truth. GitHub
104
+ Actions may add only declared credentials, transport, and unavoidable provider
105
+ effects; it may not add semantic inputs from runner environment or workspace.
106
+ ${PUBLICATION_REHEARSAL_AGENT_SECTION_END}`;
107
+ }
108
+
109
+ export function mergePublicationRehearsalAgentInstructions(current = "") {
110
+ const source = String(current || "");
111
+ const section = publicationRehearsalAgentInstructions();
112
+ const start = source.indexOf(PUBLICATION_REHEARSAL_AGENT_SECTION_START);
113
+ const end = source.indexOf(PUBLICATION_REHEARSAL_AGENT_SECTION_END);
114
+ if ((start === -1) !== (end === -1)) {
115
+ throw new Error(
116
+ "AGENTS.md has an incomplete Buildchain publication rehearsal section",
117
+ );
118
+ }
119
+ if (start === -1) {
120
+ return source.trim()
121
+ ? `${source.trimEnd()}\n\n${section}\n`
122
+ : `# AGENTS.md\n\n${section}\n`;
123
+ }
124
+ if (
125
+ source.indexOf(PUBLICATION_REHEARSAL_AGENT_SECTION_START, start + 1) !==
126
+ -1 ||
127
+ source.indexOf(PUBLICATION_REHEARSAL_AGENT_SECTION_END, end + 1) !== -1 ||
128
+ end < start
129
+ ) {
130
+ throw new Error(
131
+ "AGENTS.md has ambiguous Buildchain publication rehearsal sections",
132
+ );
133
+ }
134
+ return `${source.slice(0, start)}${section}${source.slice(
135
+ end + PUBLICATION_REHEARSAL_AGENT_SECTION_END.length,
136
+ )}`;
137
+ }
138
+
139
+ export function publicationRehearsalWorkflow(buildchainRef) {
140
+ const ref = String(buildchainRef || "").trim();
141
+ if (!ref)
142
+ throw new Error("publication rehearsal workflow requires a Buildchain ref");
143
+ return `name: Publication Rehearsal
144
+
145
+ on:
146
+ workflow_dispatch:
147
+ inputs:
148
+ capsule-path:
149
+ description: "Content-addressed publication rehearsal capsule"
150
+ required: true
151
+ default: ".buildchain/publication/rehearsal-capsule.json"
152
+ capsule-root:
153
+ description: "Repository-relative capsule file root"
154
+ required: true
155
+ default: ".buildchain/publication/candidate"
156
+
157
+ permissions:
158
+ contents: write
159
+
160
+ jobs:
161
+ rehearsal:
162
+ uses: kungfu-systems/buildchain/.github/workflows/release-tail.yml@${ref}
163
+ with:
164
+ buildchain-ref: ${ref}
165
+ capsule-contract: ${JSON.stringify(PUBLICATION_REHEARSAL_CAPSULE_CONTRACT)}
166
+ capsule-path: \${{ inputs.capsule-path }}
167
+ capsule-root: \${{ inputs.capsule-root }}
168
+ state-path: ".buildchain/publication/rehearsal-state.json"
169
+ evidence-path: ".buildchain/publication/rehearsal-evidence.json"
170
+ secrets:
171
+ http-token: \${{ secrets.BUILDCHAIN_PUBLICATION_HTTP_TOKEN }}
172
+ `;
173
+ }