@kungfu-tech/buildchain 4.1.3-alpha.0 → 4.1.3-alpha.2

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 (217) hide show
  1. package/architecture/action-taxonomy.json +16 -0
  2. package/architecture/agent-change-map.md +245 -4
  3. package/architecture/ci-lane-change-budget.json +289 -0
  4. package/architecture/decisions/0005-minimal-consumer-contract.md +122 -0
  5. package/architecture/decisions/0006-business-attempt-journal.md +89 -0
  6. package/architecture/decisions/0007-hosted-pipeline-controller.md +106 -0
  7. package/architecture/decisions/0008-pipeline-product-publication.md +99 -0
  8. package/architecture/internal-capabilities.json +340 -4
  9. package/architecture/maintainability-debt.json +3 -1
  10. package/architecture/maintainability-policy.json +8 -8
  11. package/architecture/minimal-consumer-migration.json +7558 -0
  12. package/architecture/release-topology.json +248 -11
  13. package/architecture/universal-workflow-bootstrap.json +10 -0
  14. package/architecture/universal-workflow-capability-policy.json +6 -6
  15. package/architecture/workflow-taxonomy.json +55 -0
  16. package/contracts/release-discussion-v1.schema.json +3 -0
  17. package/dist/readers/business-attempt.cjs +805 -0
  18. package/dist/readers/release-discussion.cjs +4 -0
  19. package/dist/site/buildchain-contract.json +7 -5
  20. package/dist/site/buildchain-site.json +25 -15
  21. package/dist/site/capability-registry.json +3 -3
  22. package/dist/site/kfd-claims.json +311 -10
  23. package/dist/site/kfd-upstream-aggregate.json +1 -1
  24. package/dist/site/manual-registry.json +1 -1
  25. package/dist/site/node-api-registry.json +9 -9
  26. package/dist/site/page-registry.json +20 -10
  27. package/dist/site/public-surface-audit.json +201 -7
  28. package/dist/site/publication-authority-registry.json +121 -1
  29. package/dist/site/publication-registry.json +4 -4
  30. package/dist/site/site-manifest.json +5 -5
  31. package/dist/site/workflow-registry.json +416 -7
  32. package/docs/node-api-reference.md +12 -12
  33. package/docs/release-discussions.md +44 -5
  34. package/docs/runtime-entry.md +45 -5
  35. package/docs/workflow-catalog.md +5 -0
  36. package/package.json +4 -3
  37. package/packages/core/consumer/contract/entries.js +85 -0
  38. package/packages/core/consumer/contract/examples.js +96 -0
  39. package/packages/core/consumer/contract/identity.js +65 -0
  40. package/packages/core/consumer/contract/inspection.js +45 -0
  41. package/packages/core/consumer/contract/plan.js +99 -0
  42. package/packages/core/consumer/contract/products.js +101 -0
  43. package/packages/core/consumer/contract/shape.js +46 -0
  44. package/packages/core/dev-delivery/candidate/admission.js +9 -5
  45. package/packages/core/dev-delivery/candidate/reservation.js +11 -0
  46. package/packages/core/dev-delivery/candidate/source-paths.js +12 -4
  47. package/packages/core/dev-delivery/native/actions.js +7 -1
  48. package/packages/core/dev-delivery/native/heartbeat-action.js +16 -0
  49. package/packages/core/dev-delivery/native/heartbeat.js +6 -4
  50. package/packages/core/dev-delivery/queue/landing-action.js +5 -0
  51. package/packages/core/governance/buildchain-publication-authority.js +5 -0
  52. package/packages/core/paper/operations/bootstrap.js +2 -0
  53. package/packages/core/paper/paper-npm-bootstrap.js +2 -2
  54. package/packages/core/providers/github/attempt-index.js +60 -0
  55. package/packages/core/providers/github/attempt-journal.js +154 -0
  56. package/packages/core/providers/github/discussions/materials.js +23 -7
  57. package/packages/core/providers/github/discussions/transport.js +16 -5
  58. package/packages/core/providers/github/pipeline-checkout.js +49 -0
  59. package/packages/core/providers/github/pipeline-events.js +52 -0
  60. package/packages/core/providers/github/pipeline-integration.js +95 -0
  61. package/packages/core/providers/github/pipeline-policy.js +213 -0
  62. package/packages/core/providers/github/pipeline-product-payload.js +50 -0
  63. package/packages/core/providers/github/pipeline-product-release.js +191 -0
  64. package/packages/core/providers/github/pipeline-publication-artifacts.js +153 -0
  65. package/packages/core/providers/github/pipeline-run-entry.js +86 -0
  66. package/packages/core/providers/github/pipeline-runs.js +132 -0
  67. package/packages/core/providers/github/pipeline-source.js +178 -0
  68. package/packages/core/providers/github/pipeline-version.js +201 -0
  69. package/packages/core/providers/github/pipeline-worker.js +108 -0
  70. package/packages/core/publication/candidate/registry-hydration.js +2 -2
  71. package/packages/core/publication/npm/pack-preview.js +2 -2
  72. package/packages/core/publication/npm/pack-result.js +31 -0
  73. package/packages/core/publication/npm/package.js +3 -6
  74. package/packages/core/publication/npm/pipeline-channel.js +87 -0
  75. package/packages/core/publication/npm/pipeline-provider.js +109 -0
  76. package/packages/core/publication/npm/registry.js +12 -9
  77. package/packages/core/publication/pipeline/actions.js +100 -0
  78. package/packages/core/publication/pipeline/apply.js +182 -0
  79. package/packages/core/publication/pipeline/build-segments.js +107 -0
  80. package/packages/core/publication/pipeline/capsules.js +89 -0
  81. package/packages/core/publication/pipeline/context.js +39 -0
  82. package/packages/core/publication/pipeline/development-anchor.js +91 -0
  83. package/packages/core/publication/pipeline/development-current.js +63 -0
  84. package/packages/core/publication/pipeline/development-pr.js +85 -0
  85. package/packages/core/publication/pipeline/development-proof.js +76 -0
  86. package/packages/core/publication/pipeline/development-transition.js +112 -0
  87. package/packages/core/publication/pipeline/distribution.js +124 -0
  88. package/packages/core/publication/pipeline/documents.js +156 -0
  89. package/packages/core/publication/pipeline/effects.js +162 -0
  90. package/packages/core/publication/pipeline/files.js +66 -0
  91. package/packages/core/publication/pipeline/imported-materials.js +32 -0
  92. package/packages/core/publication/pipeline/journal.js +110 -0
  93. package/packages/core/publication/pipeline/next-development.js +116 -0
  94. package/packages/core/publication/pipeline/pack.js +151 -0
  95. package/packages/core/publication/pipeline/package-policy.js +22 -0
  96. package/packages/core/publication/pipeline/plan.js +114 -0
  97. package/packages/core/publication/pipeline/prepare.js +151 -0
  98. package/packages/core/publication/pipeline/qualification.js +170 -0
  99. package/packages/core/publication/pipeline/qualify.js +104 -0
  100. package/packages/core/publication/pipeline/recovery-admission.js +122 -0
  101. package/packages/core/publication/pipeline/recovery-build-download.js +80 -0
  102. package/packages/core/publication/pipeline/recovery-build-plan.js +122 -0
  103. package/packages/core/publication/pipeline/recovery-build-readback.js +68 -0
  104. package/packages/core/publication/pipeline/recovery-capsules.js +54 -0
  105. package/packages/core/publication/pipeline/recovery-import.js +80 -0
  106. package/packages/core/publication/pipeline/recovery-inspection.js +218 -0
  107. package/packages/core/publication/pipeline/recovery-materials.js +104 -0
  108. package/packages/core/publication/pipeline/recovery-plan.js +46 -0
  109. package/packages/core/publication/pipeline/recovery-prepare.js +73 -0
  110. package/packages/core/publication/pipeline/recovery-qualification.js +128 -0
  111. package/packages/core/publication/pipeline/recovery-readback.js +56 -0
  112. package/packages/core/publication/pipeline/recovery-signing.js +58 -0
  113. package/packages/core/publication/pipeline/sealed-products.js +79 -0
  114. package/packages/core/publication/pipeline/settle.js +43 -0
  115. package/packages/core/publication/pipeline/signing.js +140 -0
  116. package/packages/core/publication/pipeline/source-plan.js +83 -0
  117. package/packages/core/publication/pipeline/version.js +81 -0
  118. package/packages/core/publication/publication-reproducibility.js +2 -2
  119. package/packages/core/release/discussion/binary.js +11 -0
  120. package/packages/core/release/discussion/checkpoints.js +45 -4
  121. package/packages/core/release/discussion/envelope.js +1 -0
  122. package/packages/core/release/discussion/evidence.js +51 -0
  123. package/packages/core/release/discussion/presentation.js +92 -0
  124. package/packages/core/release/discussion/publication.js +3 -1
  125. package/packages/core/release/discussion/qualification.js +1 -0
  126. package/packages/core/release/discussion/reader.js +9 -0
  127. package/packages/core/release/discussion/session.js +2 -0
  128. package/packages/core/release/discussion/store.js +28 -31
  129. package/packages/core/release/discussion/threads.js +83 -0
  130. package/packages/core/release/promote-candidate/product-provider-adapters.js +4 -3
  131. package/packages/core/release/promote-ref/internal/npm-existing-evidence.js +2 -1
  132. package/packages/core/release/promote-ref/internal/publish-command.js +16 -5
  133. package/packages/core/runtime/buildchain-domain.wasm +0 -0
  134. package/packages/core/runtime/domain-wasm-artifact.js +2 -2
  135. package/packages/core/runtime/entry/actions.js +27 -25
  136. package/packages/core/runtime/entry/attempt.js +25 -0
  137. package/packages/core/runtime/entry/selection.js +14 -0
  138. package/packages/core/runtime/entry/source.js +62 -0
  139. package/packages/core/workflow/attempt/identity.js +165 -0
  140. package/packages/core/workflow/attempt/journal.js +87 -0
  141. package/packages/core/workflow/attempt/materials.js +72 -0
  142. package/packages/core/workflow/attempt/reader-entry.js +12 -0
  143. package/packages/core/workflow/attempt/reader.js +149 -0
  144. package/packages/core/workflow/attempt/records.js +153 -0
  145. package/packages/core/workflow/attempt/store.js +75 -0
  146. package/packages/core/workflow/commands/pipeline-build.mjs +23 -0
  147. package/packages/core/workflow/pipeline/action-output.js +11 -0
  148. package/packages/core/workflow/pipeline/actions.js +62 -0
  149. package/packages/core/workflow/pipeline/build-control.js +140 -0
  150. package/packages/core/workflow/pipeline/build-evidence.js +92 -0
  151. package/packages/core/workflow/pipeline/build-qualification.js +145 -0
  152. package/packages/core/workflow/pipeline/build-result.js +69 -0
  153. package/packages/core/workflow/pipeline/build.js +95 -0
  154. package/packages/core/workflow/pipeline/cancellation.js +169 -0
  155. package/packages/core/workflow/pipeline/channel-control.js +127 -0
  156. package/packages/core/workflow/pipeline/controller.js +133 -0
  157. package/packages/core/workflow/pipeline/delivery-control.js +204 -0
  158. package/packages/core/workflow/pipeline/delivery-observation.js +118 -0
  159. package/packages/core/workflow/pipeline/delivery-request.js +198 -0
  160. package/packages/core/workflow/pipeline/events.js +84 -0
  161. package/packages/core/workflow/pipeline/fence.js +42 -0
  162. package/packages/core/workflow/pipeline/group-control.js +56 -0
  163. package/packages/core/workflow/pipeline/guard-build.js +37 -0
  164. package/packages/core/workflow/pipeline/guard.js +156 -0
  165. package/packages/core/workflow/pipeline/host.js +114 -0
  166. package/packages/core/workflow/pipeline/materials.js +58 -0
  167. package/packages/core/workflow/pipeline/notifications.js +36 -0
  168. package/packages/core/workflow/pipeline/parent-notification.js +27 -0
  169. package/packages/core/workflow/pipeline/platforms.js +21 -0
  170. package/packages/core/workflow/pipeline/progress.js +108 -0
  171. package/packages/core/workflow/pipeline/projection.js +20 -0
  172. package/packages/core/workflow/pipeline/reconcile.js +194 -0
  173. package/packages/core/workflow/pipeline/recovery-action.js +30 -0
  174. package/packages/core/workflow/pipeline/recovery-admission.js +122 -0
  175. package/packages/core/workflow/pipeline/recovery-build-control.js +95 -0
  176. package/packages/core/workflow/pipeline/recovery-build-evidence.js +71 -0
  177. package/packages/core/workflow/pipeline/recovery-build.js +121 -0
  178. package/packages/core/workflow/pipeline/recovery-controller.js +91 -0
  179. package/packages/core/workflow/pipeline/recovery-integration.js +66 -0
  180. package/packages/core/workflow/pipeline/recovery-merge-proof.js +90 -0
  181. package/packages/core/workflow/pipeline/recovery-ownership-settlement.js +150 -0
  182. package/packages/core/workflow/pipeline/recovery-ownership.js +91 -0
  183. package/packages/core/workflow/pipeline/recovery-plan.js +126 -0
  184. package/packages/core/workflow/pipeline/recovery-runtime.js +68 -0
  185. package/packages/core/workflow/pipeline/recovery-session.js +129 -0
  186. package/packages/core/workflow/pipeline/recovery-transition.js +135 -0
  187. package/packages/core/workflow/pipeline/recovery-unrecorded-build.js +74 -0
  188. package/packages/core/workflow/pipeline/runtime-source.js +111 -0
  189. package/packages/core/workflow/pipeline/selection.js +106 -0
  190. package/packages/core/workflow/pipeline/session.js +72 -0
  191. package/packages/core/workflow/pipeline/settlement.js +137 -0
  192. package/packages/core/workflow/pipeline/wake.js +38 -0
  193. package/packages/core/workflow/pipeline/web-status.js +108 -0
  194. package/scripts/build-release-discussion-reader.mjs +11 -7
  195. package/scripts/check-pipeline-publication-topology.mjs +36 -0
  196. package/scripts/check-release-topology.mjs +6 -1
  197. package/scripts/generate-minimal-consumer-contract.mjs +155 -0
  198. package/scripts/verify-golden-path.mjs +5 -1
  199. package/templates/minimal-consumer/binary/.buildchain/buildchain.toml +45 -0
  200. package/templates/minimal-consumer/binary/.github/workflows/buildchain-recover.yml +30 -0
  201. package/templates/minimal-consumer/binary/.github/workflows/buildchain.yml +28 -0
  202. package/templates/minimal-consumer/binary/package.json +6 -0
  203. package/templates/minimal-consumer/binary/src/build.mjs +5 -0
  204. package/templates/minimal-consumer/binary/src/hello.c +2 -0
  205. package/templates/minimal-consumer/binary/src/verify.mjs +3 -0
  206. package/templates/minimal-consumer/npm/.buildchain/buildchain.toml +46 -0
  207. package/templates/minimal-consumer/npm/.github/workflows/buildchain-recover.yml +30 -0
  208. package/templates/minimal-consumer/npm/.github/workflows/buildchain.yml +28 -0
  209. package/templates/minimal-consumer/npm/package.json +6 -0
  210. package/templates/minimal-consumer/npm/src/build.mjs +5 -0
  211. package/templates/minimal-consumer/npm/src/verify.mjs +3 -0
  212. package/templates/minimal-consumer/paper/.buildchain/buildchain.toml +45 -0
  213. package/templates/minimal-consumer/paper/.github/workflows/buildchain-recover.yml +30 -0
  214. package/templates/minimal-consumer/paper/.github/workflows/buildchain.yml +28 -0
  215. package/templates/minimal-consumer/paper/package.json +6 -0
  216. package/templates/minimal-consumer/paper/src/build.mjs +12 -0
  217. package/templates/minimal-consumer/paper/src/verify.mjs +3 -0
@@ -0,0 +1,805 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // packages/core/workflow/attempt/reader-entry.js
30
+ var reader_entry_exports = {};
31
+ __export(reader_entry_exports, {
32
+ readBusinessAttempt: () => readBusinessAttempt
33
+ });
34
+ module.exports = __toCommonJS(reader_entry_exports);
35
+ var import_node_fs = __toESM(require("fs"), 1);
36
+
37
+ // packages/core/release/discussion/envelope.js
38
+ var import_node_crypto = require("crypto");
39
+ var ENVELOPE_SCHEMA = "buildchain.discussion-record/v1";
40
+ var INTENT_SCHEMA = "buildchain.release-discussion/v1";
41
+ var PAYLOAD_SCHEMA = "buildchain.release-progress/v1";
42
+ var MARKER = "<!-- buildchain-transaction\n";
43
+ var MAX_RECORD_BYTES = 48e3;
44
+ function canonicalJson(value) {
45
+ if (typeof value === "number" && !Number.isFinite(value))
46
+ throw new Error("Transaction numbers must be finite");
47
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
48
+ if (value && typeof value === "object")
49
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
50
+ const encoded = JSON.stringify(value);
51
+ if (encoded === void 0)
52
+ throw new Error("Transaction records must contain JSON values");
53
+ return encoded;
54
+ }
55
+ function recordDigest(value) {
56
+ return `sha256:${(0, import_node_crypto.createHash)("sha256").update(canonicalJson(value)).digest("hex")}`;
57
+ }
58
+ function requireString(value, label) {
59
+ if (typeof value !== "string" || !value.trim())
60
+ throw new Error(`${label} is required`);
61
+ return value;
62
+ }
63
+ function validateRuntime(runtime) {
64
+ if (!/^[\w.-]+\/[\w.-]+$/u.test(runtime?.repository || "") || !/^[a-f0-9]{40}$/u.test(runtime?.sha || "") || !/^sha256:[a-f0-9]{64}$/u.test(runtime?.readerDigest || ""))
65
+ throw new Error(
66
+ "Record requires selected runtime repository, exact revision and reader digest"
67
+ );
68
+ return runtime;
69
+ }
70
+ function encodeRecord(record, summary = "Buildchain release transaction record") {
71
+ const body = `${summary}
72
+
73
+ ${MARKER}${canonicalJson(record)}
74
+ -->`;
75
+ if (Buffer.byteLength(body) > MAX_RECORD_BYTES)
76
+ throw new Error(
77
+ "Transaction record exceeds the bounded body size; retain material as artifacts"
78
+ );
79
+ return body;
80
+ }
81
+ function decodeRecord(body) {
82
+ if (typeof body !== "string" || !body.includes(MARKER)) return void 0;
83
+ if (Buffer.byteLength(body) > MAX_RECORD_BYTES)
84
+ throw new Error("Oversized transaction record");
85
+ const start = body.indexOf(MARKER) + MARKER.length;
86
+ const end = body.indexOf("\n-->", start);
87
+ if (end < 0 || body.indexOf(MARKER, start) >= 0)
88
+ throw new Error("Malformed transaction envelope");
89
+ const record = JSON.parse(body.slice(start, end));
90
+ if (![ENVELOPE_SCHEMA, INTENT_SCHEMA].includes(record.schema))
91
+ throw new Error("Unsupported transaction envelope schema");
92
+ return record;
93
+ }
94
+ function createIntent({
95
+ repository,
96
+ key,
97
+ expectedNodes,
98
+ runtime,
99
+ source
100
+ }) {
101
+ requireString(repository, "Consumer repository");
102
+ requireString(key, "Release intent key");
103
+ if (key.length > 240 || /[\r\n<>]/u.test(key))
104
+ throw new Error("Invalid release intent key");
105
+ if (!Array.isArray(expectedNodes) || !expectedNodes.length || new Set(expectedNodes).size !== expectedNodes.length || expectedNodes.some((node) => !/^[a-z][a-z0-9-]*$/u.test(node)))
106
+ throw new Error("Release intent requires unique expected semantic nodes");
107
+ validateRuntime(runtime);
108
+ const identity = { repository, key };
109
+ return {
110
+ schema: INTENT_SCHEMA,
111
+ id: recordDigest(identity),
112
+ ...identity,
113
+ expectedNodes,
114
+ organization: "attempt-threads/v1",
115
+ runtime,
116
+ source
117
+ };
118
+ }
119
+ function createProgress({
120
+ intent,
121
+ attempt,
122
+ predecessor = "",
123
+ runtime,
124
+ node,
125
+ status,
126
+ payload = {},
127
+ sequence = 0,
128
+ kind = "progress",
129
+ writer = attempt
130
+ }) {
131
+ validateRuntime(runtime);
132
+ requireString(writer, "Record writer");
133
+ requireString(attempt, "Workflow attempt");
134
+ if (node !== "attempt" && !intent.expectedNodes.includes(node))
135
+ throw new Error(`Undeclared release node: ${node}`);
136
+ if (!["running", "success", "failure", "cancelled"].includes(status))
137
+ throw new Error("Invalid release node status");
138
+ if (!Number.isSafeInteger(sequence) || sequence < 0)
139
+ throw new Error("Invalid record sequence");
140
+ if (predecessor === attempt) throw new Error("Attempt cannot recover itself");
141
+ if (!["progress", "checkpoint"].includes(kind))
142
+ throw new Error("Invalid transaction record kind");
143
+ const event = {
144
+ kind,
145
+ writer,
146
+ schema: ENVELOPE_SCHEMA,
147
+ intent: intent.id,
148
+ attempt,
149
+ predecessor,
150
+ runtime,
151
+ payloadSchema: PAYLOAD_SCHEMA,
152
+ node,
153
+ status,
154
+ sequence,
155
+ payload
156
+ };
157
+ return { ...event, id: recordDigest(event) };
158
+ }
159
+
160
+ // packages/core/release/discussion/reader.js
161
+ function readReleaseDiscussion({ body, records }) {
162
+ const intent = decodeRecord(body);
163
+ if (intent?.schema !== INTENT_SCHEMA)
164
+ throw new Error("Missing release Discussion intent");
165
+ if (intent.id !== recordDigest({ repository: intent.repository, key: intent.key }))
166
+ throw new Error("Release intent identity mismatch");
167
+ if (!Array.isArray(intent.expectedNodes) || !intent.expectedNodes.length || new Set(intent.expectedNodes).size !== intent.expectedNodes.length)
168
+ throw new Error("Missing or duplicate expected nodes");
169
+ if (intent.organization && intent.organization !== "attempt-threads/v1")
170
+ throw new Error(
171
+ "Discussion organization requires its historical runtime reader"
172
+ );
173
+ const attempts = groupAttempts(validateRecords(intent, records));
174
+ if (!attempts.size)
175
+ return {
176
+ intent,
177
+ status: "pending",
178
+ attempts: [],
179
+ missingNodes: intent.expectedNodes
180
+ };
181
+ const { head, lineage } = resolveLineage(attempts);
182
+ const nodes = currentNodes(attempts.get(head).events);
183
+ const missingNodes = intent.expectedNodes.filter((node) => !nodes[node]);
184
+ const complete = intent.expectedNodes.every(
185
+ (node) => nodes[node]?.status === "success"
186
+ );
187
+ const failed = Object.values(nodes).some(
188
+ (event) => ["failure", "cancelled"].includes(event.status)
189
+ );
190
+ return {
191
+ intent,
192
+ attempt: head,
193
+ attempts: lineage.reverse(),
194
+ nodes,
195
+ missingNodes,
196
+ status: complete ? "complete" : failed ? "failed" : "running",
197
+ handoff: {
198
+ schema: "buildchain.release-handoff/v1",
199
+ intent: intent.id,
200
+ predecessor: head,
201
+ completedNodes: intent.expectedNodes.filter(
202
+ (node) => nodes[node]?.status === "success"
203
+ )
204
+ }
205
+ };
206
+ }
207
+ function validateRecords(intent, records) {
208
+ const events = /* @__PURE__ */ new Map();
209
+ for (const raw of records) {
210
+ const event = typeof raw === "string" ? decodeRecord(raw) : raw;
211
+ if (!event) continue;
212
+ validateRuntime(event.runtime);
213
+ if (!["progress", "checkpoint"].includes(event.kind) || !event.writer || !event.attempt || typeof event.predecessor !== "string")
214
+ throw new Error("Invalid record ownership");
215
+ const { id, ...content } = event;
216
+ if (event.schema !== ENVELOPE_SCHEMA || event.payloadSchema !== PAYLOAD_SCHEMA)
217
+ throw new Error("Record requires its historical runtime reader");
218
+ if (event.intent !== intent.id || id !== recordDigest(content))
219
+ throw new Error("Release record identity mismatch");
220
+ if (event.node !== "attempt" && !intent.expectedNodes.includes(event.node))
221
+ throw new Error("Undeclared release node");
222
+ if (!["running", "success", "failure", "cancelled"].includes(event.status) || !Number.isSafeInteger(event.sequence) || event.sequence < 0)
223
+ throw new Error("Invalid release progress");
224
+ events.set(id, event);
225
+ }
226
+ return events;
227
+ }
228
+ function groupAttempts(events) {
229
+ const attempts = /* @__PURE__ */ new Map();
230
+ for (const event of events.values()) {
231
+ const attempt = attempts.get(event.attempt) || {
232
+ predecessor: event.predecessor,
233
+ events: []
234
+ };
235
+ if (attempt.predecessor !== event.predecessor)
236
+ throw new Error("Conflicting workflow attempt identity");
237
+ attempt.events.push(event);
238
+ attempts.set(event.attempt, attempt);
239
+ }
240
+ return attempts;
241
+ }
242
+ function resolveLineage(attempts) {
243
+ const predecessors = new Set(
244
+ [...attempts.values()].map((attempt) => attempt.predecessor).filter(Boolean)
245
+ );
246
+ for (const predecessor of predecessors)
247
+ if (!attempts.has(predecessor))
248
+ throw new Error("Recovery predecessor is missing");
249
+ const heads = [...attempts.keys()].filter((id) => !predecessors.has(id));
250
+ if (heads.length !== 1)
251
+ throw new Error("Release attempt succession is ambiguous or cyclic");
252
+ const lineage = [];
253
+ let current = heads[0];
254
+ while (current) {
255
+ if (lineage.includes(current)) throw new Error("Cyclic recovery chain");
256
+ lineage.push(current);
257
+ current = attempts.get(current).predecessor;
258
+ }
259
+ if (lineage.length !== attempts.size)
260
+ throw new Error("Disconnected recovery chain");
261
+ return { head: heads[0], lineage };
262
+ }
263
+ function currentNodes(events) {
264
+ const nodes = {}, sequences = /* @__PURE__ */ new Map();
265
+ for (const event of events) {
266
+ if (event.kind === "checkpoint") continue;
267
+ const key = `${event.node}:${event.sequence}`;
268
+ if (sequences.has(key) && sequences.get(key) !== event.id)
269
+ throw new Error("Conflicting node progress at the same sequence");
270
+ sequences.set(key, event.id);
271
+ const old = nodes[event.node];
272
+ if (!old || old.sequence < event.sequence) nodes[event.node] = event;
273
+ }
274
+ return nodes;
275
+ }
276
+
277
+ // packages/core/consumer/contract/shape.js
278
+ function object(value, required, optional = [], location = "config") {
279
+ if (!value || Object.getPrototypeOf(value) !== Object.prototype)
280
+ throw new Error(`${location}: expected a table`);
281
+ for (const key of Object.keys(value))
282
+ if (![...required, ...optional].includes(key))
283
+ throw new Error(`${location}.${key}: unknown field`);
284
+ for (const key of required)
285
+ if (!Object.hasOwn(value, key))
286
+ throw new Error(`${location}.${key}: required field`);
287
+ return value;
288
+ }
289
+ function text(value, location, pattern = /\S/u) {
290
+ if (typeof value !== "string" || !pattern.test(value) || value.includes("\0"))
291
+ throw new Error(`${location}: invalid string`);
292
+ return value;
293
+ }
294
+ function choice(value, choices, location) {
295
+ if (!choices.includes(value))
296
+ throw new Error(`${location}: expected ${choices.join(" or ")}`);
297
+ return value;
298
+ }
299
+ function list(value, location, validate) {
300
+ if (!Array.isArray(value) || !value.length)
301
+ throw new Error(`${location}: expected a nonempty list`);
302
+ return value.map((item, index) => validate(item, `${location}[${index}]`));
303
+ }
304
+ function unique(values, location) {
305
+ if (new Set(values).size !== values.length)
306
+ throw new Error(`${location}: duplicate identity`);
307
+ }
308
+ function relativePath(value, location) {
309
+ text(value, location, /^[A-Za-z0-9_.][A-Za-z0-9_./*-]*$/u);
310
+ if (value.split("/").some((part) => !part || part === ".." || part === "."))
311
+ throw new Error(`${location}: expected a repository-relative path`);
312
+ return value;
313
+ }
314
+
315
+ // packages/core/consumer/contract/plan.js
316
+ var CONSUMER_CONTRACT = "buildchain.consumer-contract/v2";
317
+
318
+ // packages/core/workflow/attempt/identity.js
319
+ var PIPELINE_PHASES = [
320
+ "admission",
321
+ "build",
322
+ "review",
323
+ "warrant",
324
+ "merge",
325
+ "publish",
326
+ "distribution",
327
+ "next-development"
328
+ ];
329
+ var SOURCE_GENERATION = "buildchain.source-generation/v1";
330
+ var BUSINESS_ATTEMPT = "buildchain.business-attempt/v1";
331
+ var ROOT = /^sha256:[0-9a-f]{64}$/u;
332
+ function pipelineIntent({
333
+ repository,
334
+ repositoryId,
335
+ pullRequest,
336
+ targetBranch,
337
+ phases,
338
+ runtime
339
+ }) {
340
+ text(repository, "repository", /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u);
341
+ text(repositoryId, "repositoryId");
342
+ if (!Number.isSafeInteger(pullRequest) || pullRequest < 1)
343
+ throw new Error("Invalid PR intent number");
344
+ text(
345
+ targetBranch,
346
+ "targetBranch",
347
+ /^(?:dev|alpha|release|publish-gate)\/[A-Za-z0-9/._-]+$/u
348
+ );
349
+ list(
350
+ phases,
351
+ "phases",
352
+ (phase, field) => choice(phase, PIPELINE_PHASES, field)
353
+ );
354
+ unique(phases, "phases");
355
+ if (phases.some(
356
+ (phase, i) => i && PIPELINE_PHASES.indexOf(phase) <= PIPELINE_PHASES.indexOf(phases[i - 1])
357
+ ))
358
+ throw new Error("Intent phases must follow pipeline order");
359
+ if (phases[0] !== "admission")
360
+ throw new Error("Intent must begin with admission");
361
+ return createIntent({
362
+ repository,
363
+ key: `pr-${pullRequest}:${targetBranch}`,
364
+ expectedNodes: phases,
365
+ runtime,
366
+ source: { kind: "pipeline", repositoryId, pullRequest, targetBranch }
367
+ });
368
+ }
369
+ function sourceGeneration(intent, source, baseCommit) {
370
+ object(
371
+ source,
372
+ [
373
+ "schema",
374
+ "repository",
375
+ "commit",
376
+ "tree",
377
+ "configPath",
378
+ "configBlob",
379
+ "configDigest",
380
+ "contract"
381
+ ],
382
+ [],
383
+ "source"
384
+ );
385
+ if (source.schema !== "buildchain.consumer-source/v1" || source.contract !== CONSUMER_CONTRACT || source.repository !== intent.repository)
386
+ throw new Error("Generation requires the admitted consumer source");
387
+ for (const key of ["commit", "tree", "configBlob"])
388
+ text(source[key], `source.${key}`, /^[0-9a-f]{40}$/u);
389
+ relativePath(source.configPath, "source.configPath");
390
+ text(source.configDigest, "source.configDigest", ROOT);
391
+ text(baseCommit, "baseCommit", /^[0-9a-f]{40}$/u);
392
+ const value = {
393
+ schema: SOURCE_GENERATION,
394
+ intent: intent.id,
395
+ source: structuredClone(source),
396
+ baseCommit
397
+ };
398
+ return { ...value, id: recordDigest(value) };
399
+ }
400
+ function validateGeneration(value, intent) {
401
+ object(
402
+ value,
403
+ ["schema", "intent", "source", "baseCommit", "id"],
404
+ [],
405
+ "generation"
406
+ );
407
+ const expected = sourceGeneration(intent, value.source, value.baseCommit);
408
+ if (recordDigest(value) !== recordDigest(expected))
409
+ throw new Error("Generation identity mismatch");
410
+ return value;
411
+ }
412
+ function businessAttempt({
413
+ intent,
414
+ generation,
415
+ predecessor = "",
416
+ requestKey
417
+ }) {
418
+ validateGeneration(generation, intent);
419
+ text(requestKey, "requestKey");
420
+ if (requestKey.length > 240)
421
+ throw new Error("Attempt request key exceeds its bound");
422
+ if (predecessor) text(predecessor, "predecessor", /^attempt-[0-9a-f]{64}$/u);
423
+ const value = {
424
+ schema: BUSINESS_ATTEMPT,
425
+ intent: intent.id,
426
+ generation: generation.id,
427
+ predecessor,
428
+ requestKey
429
+ };
430
+ return { ...value, id: `attempt-${recordDigest(value).slice(7)}` };
431
+ }
432
+ function validateAttempt(value, intent, generation) {
433
+ object(
434
+ value,
435
+ ["schema", "intent", "generation", "predecessor", "requestKey", "id"],
436
+ [],
437
+ "attempt"
438
+ );
439
+ const expected = businessAttempt({
440
+ intent,
441
+ generation,
442
+ predecessor: value.predecessor,
443
+ requestKey: value.requestKey
444
+ });
445
+ if (recordDigest(value) !== recordDigest(expected))
446
+ throw new Error("Business attempt identity mismatch");
447
+ return value;
448
+ }
449
+ function providerWriter(value, repository) {
450
+ object(value, ["repository", "runId", "runAttempt", "jobId"], [], "writer");
451
+ if (value.repository !== repository)
452
+ throw new Error("Writer belongs to a different repository");
453
+ for (const key of ["runId", "runAttempt", "jobId"])
454
+ text(value[key], `writer.${key}`, /^[1-9][0-9]*$/u);
455
+ return `${value.runId}:${value.runAttempt}:${value.jobId}`;
456
+ }
457
+
458
+ // packages/core/workflow/attempt/materials.js
459
+ var import_node_crypto2 = require("crypto");
460
+ var MATERIAL_KINDS = [
461
+ "artifact",
462
+ "checkpoint",
463
+ "receipt",
464
+ "passport",
465
+ "provider-readback"
466
+ ];
467
+ function materialReference(value, attempt, repository = "") {
468
+ object(
469
+ value,
470
+ ["id", "kind", "digest", "bytes", "url", "generation", "producerAttempt"],
471
+ [],
472
+ "material"
473
+ );
474
+ text(value.id, "material.id", /^[a-z][a-z0-9._/-]*$/u);
475
+ choice(value.kind, MATERIAL_KINDS, "material.kind");
476
+ text(value.digest, "material.digest", /^sha256:[0-9a-f]{64}$/u);
477
+ if (!Number.isSafeInteger(value.bytes) || value.bytes < 1)
478
+ throw new Error("Invalid material byte size");
479
+ const url = new URL(value.url);
480
+ if (url.protocol !== "https:" || url.username || url.password || url.search || url.hash || !["github.com", "api.github.com"].includes(url.hostname))
481
+ throw new Error(
482
+ "Material must use a permanent GitHub URL without credentials or signed queries"
483
+ );
484
+ if (repository && !(url.hostname === "github.com" ? url.pathname.startsWith(`/${repository}/releases/download/`) || url.pathname.startsWith(`/${repository}/actions/runs/`) : url.pathname.startsWith(`/repos/${repository}/actions/artifacts/`) || url.pathname.startsWith(`/repos/${repository}/releases/assets/`)))
485
+ throw new Error("Material belongs to another consumer repository");
486
+ if (value.generation !== attempt.generation || value.producerAttempt !== attempt.id)
487
+ throw new Error(
488
+ "Material is not qualified for this exact attempt and generation"
489
+ );
490
+ return { ...value };
491
+ }
492
+ function indexMaterials(index, references, attempt) {
493
+ for (const reference of references) {
494
+ materialReference(reference, attempt);
495
+ const old = index[reference.id];
496
+ if (old && recordDigest(old) !== recordDigest(reference))
497
+ throw new Error(`Immutable material identity conflict: ${reference.id}`);
498
+ index[reference.id] = { ...reference };
499
+ }
500
+ return index;
501
+ }
502
+
503
+ // packages/core/workflow/attempt/records.js
504
+ var ATTEMPT_EVENT = "buildchain.business-attempt-event/v1";
505
+ var STATES = [
506
+ "running",
507
+ "waiting",
508
+ "success",
509
+ "failure",
510
+ "cancelled",
511
+ "superseded"
512
+ ];
513
+ var ENVELOPE_STATUS = {
514
+ running: "running",
515
+ waiting: "running",
516
+ success: "success",
517
+ failure: "failure",
518
+ cancelled: "cancelled",
519
+ superseded: "cancelled"
520
+ };
521
+ function attemptRecord({
522
+ intent,
523
+ attempt,
524
+ generation,
525
+ writer,
526
+ runtime,
527
+ previous = null,
528
+ eventKey,
529
+ phase,
530
+ state,
531
+ reason = "",
532
+ materials = []
533
+ }) {
534
+ validateAttempt(attempt, intent, generation);
535
+ const writerId = providerWriter(writer, intent.repository);
536
+ choice(state, STATES, "state");
537
+ text(eventKey, "eventKey");
538
+ if (eventKey.length > 240 || typeof reason !== "string" || reason.length > 2e3)
539
+ throw new Error("Attempt event text exceeds its bound");
540
+ if (!previous && (phase !== "attempt" || state !== "running"))
541
+ throw new Error("Open an attempt root before phase progress");
542
+ if (previous && (previous.attempt !== attempt.id || previous.payload.generation.id !== generation.id))
543
+ throw new Error(
544
+ "Record predecessor belongs to another attempt or generation"
545
+ );
546
+ if (!Array.isArray(materials) || materials.length > 100)
547
+ throw new Error("Attempt event material bound exceeded");
548
+ unique(
549
+ materials.map((item) => item.id),
550
+ "materials"
551
+ );
552
+ materials.forEach(
553
+ (item) => materialReference(item, attempt, intent.repository)
554
+ );
555
+ return createProgress({
556
+ intent,
557
+ attempt: attempt.id,
558
+ predecessor: attempt.predecessor,
559
+ writer: writerId,
560
+ runtime,
561
+ node: phase,
562
+ status: ENVELOPE_STATUS[state],
563
+ sequence: previous ? previous.sequence + 1 : 0,
564
+ payload: {
565
+ schema: ATTEMPT_EVENT,
566
+ identity: attempt,
567
+ generation,
568
+ writer: { ...writer },
569
+ previous: previous?.id || "",
570
+ eventKey,
571
+ state,
572
+ reason,
573
+ materials: structuredClone(materials)
574
+ }
575
+ });
576
+ }
577
+ function validateAttemptRecord(record, intent) {
578
+ const value = record.payload;
579
+ object(
580
+ value,
581
+ [
582
+ "schema",
583
+ "identity",
584
+ "generation",
585
+ "writer",
586
+ "previous",
587
+ "eventKey",
588
+ "state",
589
+ "reason",
590
+ "materials"
591
+ ],
592
+ [],
593
+ "attemptEvent"
594
+ );
595
+ if (value.schema !== ATTEMPT_EVENT)
596
+ throw new Error("Attempt event requires its historical runtime reader");
597
+ validateAttempt(value.identity, intent, value.generation);
598
+ const { id, ...content } = record;
599
+ if (id !== recordDigest(content) || record.attempt !== value.identity.id || record.intent !== intent.id || record.predecessor !== value.identity.predecessor)
600
+ throw new Error("Attempt record identity mismatch");
601
+ if (providerWriter(value.writer, intent.repository) !== record.writer)
602
+ throw new Error("Attempt provider writer mismatch");
603
+ choice(value.state, STATES, "attemptEvent.state");
604
+ if (record.status !== ENVELOPE_STATUS[value.state])
605
+ throw new Error("Attempt record status mismatch");
606
+ if (value.previous)
607
+ text(value.previous, "previous", /^sha256:[0-9a-f]{64}$/u);
608
+ const expected = attemptRecord({
609
+ intent,
610
+ attempt: value.identity,
611
+ generation: value.generation,
612
+ writer: value.writer,
613
+ runtime: record.runtime,
614
+ previous: value.previous ? {
615
+ id: value.previous,
616
+ attempt: record.attempt,
617
+ payload: value,
618
+ sequence: record.sequence - 1
619
+ } : null,
620
+ eventKey: value.eventKey,
621
+ phase: record.node,
622
+ state: value.state,
623
+ reason: value.reason,
624
+ materials: value.materials
625
+ });
626
+ if (recordDigest(expected) !== recordDigest(record))
627
+ throw new Error("Invalid attempt record envelope");
628
+ encodeRecord(record);
629
+ return record;
630
+ }
631
+
632
+ // packages/core/workflow/attempt/reader.js
633
+ var MAX_ATTEMPT_RECORDS = 1e4;
634
+ var MAX_HISTORY_BYTES = 32 * 1024 * 1024;
635
+ function validateIntent(intent) {
636
+ const source = intent.source;
637
+ if (source?.kind !== "pipeline") throw new Error("Not a pipeline intent");
638
+ const expected = pipelineIntent({
639
+ ...source,
640
+ repository: intent.repository,
641
+ phases: intent.expectedNodes,
642
+ runtime: intent.runtime
643
+ });
644
+ if (recordDigest(expected) !== recordDigest(intent))
645
+ throw new Error("Pipeline intent identity mismatch");
646
+ }
647
+ function foldAttempt(events, intent) {
648
+ events.sort((a, b) => a.sequence - b.sequence);
649
+ const roots = events.filter((record) => record.node === "attempt");
650
+ if (roots.length !== 1 || roots[0] !== events[0])
651
+ throw new Error("Attempt requires exactly one initial root");
652
+ const phases = /* @__PURE__ */ Object.create(null), materials = /* @__PURE__ */ Object.create(null), keys = /* @__PURE__ */ new Set(), runs = /* @__PURE__ */ new Map();
653
+ let previous = null;
654
+ for (const record of events) {
655
+ const value = record.payload;
656
+ if (value.identity.id !== roots[0].payload.identity.id || value.generation.id !== roots[0].payload.generation.id)
657
+ throw new Error("Attempt changed its immutable generation");
658
+ if (record.sequence !== (previous ? previous.sequence + 1 : 0) || value.previous !== (previous?.id || ""))
659
+ throw new Error(
660
+ "Attempt record chain has a gap, fork or missing predecessor"
661
+ );
662
+ if (keys.has(value.eventKey))
663
+ throw new Error("Conflicting duplicate event key");
664
+ keys.add(value.eventKey);
665
+ if (record.node !== "attempt") {
666
+ const before = intent.expectedNodes.slice(
667
+ 0,
668
+ intent.expectedNodes.indexOf(record.node)
669
+ );
670
+ if (before.some((phase) => phases[phase]?.payload.state !== "success"))
671
+ throw new Error("Phase predecessor has not succeeded");
672
+ const old = phases[record.node];
673
+ if (old && ["success", "failure", "cancelled", "superseded"].includes(
674
+ old.payload.state
675
+ ))
676
+ throw new Error(
677
+ "Terminal phase history is immutable; recover in a successor attempt"
678
+ );
679
+ phases[record.node] = record;
680
+ }
681
+ indexMaterials(materials, value.materials, value.identity);
682
+ runs.set(record.writer, value.writer);
683
+ previous = record;
684
+ }
685
+ return {
686
+ identity: roots[0].payload.identity,
687
+ generation: roots[0].payload.generation,
688
+ head: previous.id,
689
+ events,
690
+ phases,
691
+ materials,
692
+ runs: [...runs.values()]
693
+ };
694
+ }
695
+ function readBusinessAttempt({ intent, records }) {
696
+ validateIntent(intent);
697
+ if (!Array.isArray(records) || records.length > MAX_ATTEMPT_RECORDS)
698
+ throw new Error("Attempt record count exceeds its bound");
699
+ if (Buffer.byteLength(canonicalJson(records)) > MAX_HISTORY_BYTES)
700
+ throw new Error("Attempt history byte bound exceeded");
701
+ const unique2 = /* @__PURE__ */ new Map(), grouped = /* @__PURE__ */ new Map();
702
+ for (const record of records) {
703
+ validateAttemptRecord(record, intent);
704
+ unique2.set(record.id, record);
705
+ }
706
+ for (const record of unique2.values()) {
707
+ const events = grouped.get(record.attempt) || [];
708
+ events.push(record);
709
+ grouped.set(record.attempt, events);
710
+ }
711
+ const lineage = readReleaseDiscussion({
712
+ body: encodeRecord(intent),
713
+ records: [...unique2.values()]
714
+ });
715
+ const history = lineage.attempts.map(
716
+ (id) => foldAttempt(grouped.get(id), intent)
717
+ );
718
+ const current = history.at(-1);
719
+ if (!current)
720
+ return {
721
+ intent,
722
+ status: "pending",
723
+ reason: "not-admitted",
724
+ attempt: "",
725
+ missing: intent.expectedNodes,
726
+ history,
727
+ recovery: null
728
+ };
729
+ const missing = intent.expectedNodes.filter(
730
+ (phase) => current.phases[phase]?.payload.state !== "success"
731
+ );
732
+ const states = Object.values(current.phases).map((record) => record.payload);
733
+ const stopped = states.find(
734
+ (value) => ["failure", "cancelled", "superseded"].includes(value.state)
735
+ );
736
+ const waiting = states.find((value) => value.state === "waiting");
737
+ const status = stopped?.state || (missing.length ? waiting ? "waiting" : "running" : "complete");
738
+ return {
739
+ intent,
740
+ attempt: current.identity.id,
741
+ generation: current.generation.id,
742
+ status,
743
+ reason: stopped?.reason || waiting?.reason || status,
744
+ head: current.head,
745
+ missing,
746
+ phases: current.phases,
747
+ materials: current.materials,
748
+ runs: current.runs,
749
+ history,
750
+ recovery: status === "complete" ? null : { attempt: current.identity.id }
751
+ };
752
+ }
753
+
754
+ // packages/core/workflow/attempt/reader-entry.js
755
+ if (typeof require !== "undefined" && require.main === module) {
756
+ const state = readBusinessAttempt(JSON.parse(import_node_fs.default.readFileSync(0, "utf8")));
757
+ const { status, reason, attempt, generation, missing, recovery } = state;
758
+ process.stdout.write(
759
+ `${JSON.stringify({ status, reason, attempt, generation, missing, recovery })}
760
+ `
761
+ );
762
+ }
763
+ // Annotate the CommonJS export names for ESM import in node:
764
+ 0 && (module.exports = {
765
+ readBusinessAttempt
766
+ });
767
+ /*! Bundled license information:
768
+
769
+ smol-toml/dist/date.js:
770
+ smol-toml/dist/error.js:
771
+ smol-toml/dist/primitive.js:
772
+ smol-toml/dist/util.js:
773
+ smol-toml/dist/extract.js:
774
+ smol-toml/dist/struct.js:
775
+ smol-toml/dist/parse.js:
776
+ smol-toml/dist/stringify.js:
777
+ smol-toml/dist/index.js:
778
+ (*!
779
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
780
+ * SPDX-License-Identifier: BSD-3-Clause
781
+ *
782
+ * Redistribution and use in source and binary forms, with or without
783
+ * modification, are permitted provided that the following conditions are met:
784
+ *
785
+ * 1. Redistributions of source code must retain the above copyright notice, this
786
+ * list of conditions and the following disclaimer.
787
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
788
+ * this list of conditions and the following disclaimer in the
789
+ * documentation and/or other materials provided with the distribution.
790
+ * 3. Neither the name of the copyright holder nor the names of its contributors
791
+ * may be used to endorse or promote products derived from this software without
792
+ * specific prior written permission.
793
+ *
794
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
795
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
796
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
797
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
798
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
799
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
800
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
801
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
802
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
803
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
804
+ *)
805
+ */