@kungfu-tech/buildchain 4.0.1-alpha.8 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/actions/v4-release-candidate-promote/README.md +3 -0
- package/architecture/agent-change-map.md +1015 -0
- package/architecture/ci-lane-change-budget.json +70 -1
- package/architecture/decisions/0004-v4-declarative-release-tail.md +47 -0
- package/architecture/internal-capabilities.json +156 -11
- package/architecture/maintainability-debt.json +3229 -0
- package/architecture/maintainability-policy.json +480 -129
- package/architecture/v3-core-mechanism-inventory.json +4 -3
- package/architecture/v3-v4-capability-closure.md +59 -0
- package/architecture/v3-v4-live-capability-inventory.json +102404 -0
- package/architecture/v4-cross-platform-adopter-qualification.json +52 -0
- package/architecture/v4-delivery-warrant-shadow-fixtures.json +3 -3
- package/architecture/v4-runtime-semantic-closure.json +710 -0
- package/bin/internal/trust-release-release-handlers.mjs +5 -0
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/contracts/v4-publication-qualification-v1.schema.json +51 -0
- package/dist/site/agent-index.json +1 -0
- package/dist/site/artifact-schemas.json +2 -0
- package/dist/site/buildchain-contract.json +123 -32
- package/dist/site/buildchain-site.json +96 -28
- package/dist/site/capability-registry.json +6 -6
- package/dist/site/cli-registry.json +5 -2
- package/dist/site/controller-registry.json +41 -5
- package/dist/site/kfd-claims.json +170 -21
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +6 -6
- package/dist/site/node-api-registry.json +1474 -215
- package/dist/site/page-registry.json +85 -17
- package/dist/site/public-surface-audit.json +85 -20
- package/dist/site/publication-authority-registry.json +28 -1
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-provenance.json +5 -0
- package/dist/site/schemas/v4-publication-qualification-v1.schema.json +51 -0
- package/dist/site/site-manifest.json +10 -10
- package/dist/site/workflow-registry.json +94 -18
- package/docs/MAP.md +1 -1
- package/docs/cli-reference.md +4 -4
- package/docs/dev-delivery-warrant.md +12 -9
- package/docs/node-api-reference.md +291 -206
- package/docs/publish-transaction.md +11 -4
- package/docs/release-candidate.md +7 -0
- package/docs/v4-adopter-delivery.md +23 -4
- package/docs/v4-declarative-release-tail-migration.md +43 -0
- package/package.json +8 -3
- package/packages/core/adopter-delivery-passport.js +36 -0
- package/packages/core/buildchain-contract.js +31 -1
- package/packages/core/buildchain-publication-authority.js +1 -0
- package/packages/core/dev-delivery-warrant-settlement.js +239 -3
- package/packages/core/dev-delivery-warrant-state.js +15 -2
- package/packages/core/dev-delivery-warrant.js +21 -4
- package/packages/core/github-governance-authority.js +4 -4
- package/packages/core/index.js +1 -0
- package/packages/core/paper-scaffold-content.js +401 -0
- package/packages/core/paper.js +12 -378
- package/packages/core/publication-control-plane-audit.js +135 -111
- package/packages/core/publication-rehearsal-projection.js +104 -0
- package/packages/core/publication-rehearsal-runtime.js +190 -0
- package/packages/core/release-candidate-recovery.js +6 -5
- package/packages/core/release-passport.js +82 -184
- package/packages/core/v4-cross-platform-adopter-qualification.js +343 -0
- package/packages/core/v4-floating-consumer-policy.js +3 -2
- package/packages/core/v4-floating-consumer-release-passport.js +134 -15
- package/packages/core/v4-publication-qualification.js +222 -0
- package/scripts/artifact-signing-controller-core.mjs +1 -1
- package/scripts/audit-publication-control-plane.mjs +17 -17
- package/scripts/buildchain-cli-help.mjs +3 -0
- package/scripts/check-internal-architecture.mjs +23 -3
- package/scripts/check-inventory.mjs +23 -5
- package/scripts/check-maintainability.mjs +145 -4
- package/scripts/check-project-cut-merge-queue-admission.mjs +87 -0
- package/scripts/check-v3-v4-capability-inventory.mjs +574 -0
- package/scripts/check-v4-floating-consumer-policy-contract.mjs +10 -3
- package/scripts/check-v4-runtime-semantic-closure.mjs +266 -0
- package/scripts/dev-delivery-warrant-options.mjs +27 -11
- package/scripts/dev-delivery-warrant.mjs +45 -5
- package/scripts/dev-pr-auto-merge.mjs +25 -11
- package/scripts/dev-pr-delivery-warrant.mjs +44 -0
- package/scripts/dev-pr-prequeue-guard.mjs +0 -18
- package/scripts/dispatch-artifact-signing-authority.mjs +1 -1
- package/scripts/generate-agent-change-map.mjs +118 -0
- package/scripts/generate-release-candidate-passport.mjs +26 -1
- package/scripts/generate-site-bundle.mjs +6 -0
- package/scripts/maintainability-domain-metrics.mjs +237 -0
- package/scripts/maintainability-governance.mjs +473 -0
- package/scripts/maintainability-metrics.mjs +28 -6
- package/scripts/project-cut-merge-queue-admission.mjs +394 -0
- package/scripts/promotion-routing-evidence.mjs +35 -6
- package/scripts/release-candidate-resolver.mjs +44 -0
- package/scripts/release-line-policy.mjs +25 -15
- package/scripts/release-tail.mjs +19 -2
- package/scripts/resume-from-candidate-run.mjs +106 -103
- package/scripts/run-lifecycle-core.mjs +341 -376
- package/scripts/site-capability-metadata.mjs +4 -0
- package/scripts/stable-candidate-qualification.mjs +9 -10
- package/scripts/v3-v4-capability-catalog.mjs +439 -0
- package/scripts/v4-cross-platform-adopter-qualification.mjs +228 -0
- package/scripts/v4-declarative-promotion-admission.mjs +42 -0
|
@@ -5,10 +5,52 @@ import path from "node:path";
|
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
analyzeSource,
|
|
9
|
+
analyzeWorkflow,
|
|
9
10
|
collectMaintainabilityMetrics,
|
|
10
11
|
isHandMaintainedSource,
|
|
11
12
|
} from "./maintainability-metrics.mjs";
|
|
13
|
+
import {
|
|
14
|
+
calculateDebtMeasuredExcess,
|
|
15
|
+
evaluateDebtAuthority,
|
|
16
|
+
evaluateDebtBudget,
|
|
17
|
+
evaluateExceptionBudget,
|
|
18
|
+
evaluateExceptionGovernance,
|
|
19
|
+
evaluateTestBudgets,
|
|
20
|
+
evaluateWorkflowBudgets,
|
|
21
|
+
} from "./maintainability-governance.mjs";
|
|
22
|
+
|
|
23
|
+
function collectHotspots(root, current, limit = 20, shallowFallback = []) {
|
|
24
|
+
const maintained = new Set([
|
|
25
|
+
...Object.keys(current.files || {}),
|
|
26
|
+
...Object.keys(current.tests || {}),
|
|
27
|
+
...Object.keys(current.workflows || {}),
|
|
28
|
+
]);
|
|
29
|
+
// Shallow consumers cannot reproduce repository-wide churn ranking.
|
|
30
|
+
// Reuse the audited routes; full clones still re-rank them below.
|
|
31
|
+
// This keeps consumer verification deterministic without inventing history.
|
|
32
|
+
if (
|
|
33
|
+
gitOutput(root, ["rev-parse", "--is-shallow-repository"]).trim() === "true"
|
|
34
|
+
) {
|
|
35
|
+
return shallowFallback.slice(0, limit);
|
|
36
|
+
}
|
|
37
|
+
const counts = new Map();
|
|
38
|
+
const record = (file) =>
|
|
39
|
+
maintained.has(file) && counts.set(file, (counts.get(file) || 0) + 1);
|
|
40
|
+
for (const args of [
|
|
41
|
+
["log", "-n", "500", "--format=", "--name-only"],
|
|
42
|
+
["diff", "--name-only"],
|
|
43
|
+
])
|
|
44
|
+
for (const file of gitOutput(root, args).split("\n").filter(Boolean))
|
|
45
|
+
record(file);
|
|
46
|
+
return [...counts]
|
|
47
|
+
.sort(
|
|
48
|
+
([leftPath, left], [rightPath, right]) =>
|
|
49
|
+
right - left || leftPath.localeCompare(rightPath),
|
|
50
|
+
)
|
|
51
|
+
.slice(0, limit)
|
|
52
|
+
.map(([file]) => file);
|
|
53
|
+
}
|
|
12
54
|
|
|
13
55
|
function readJson(root, file) {
|
|
14
56
|
return JSON.parse(fs.readFileSync(path.join(root, file), "utf8"));
|
|
@@ -68,7 +110,35 @@ function sourceMetricsAtRevision(root, revision) {
|
|
|
68
110
|
return Object.fromEntries(
|
|
69
111
|
files.map((file) => [
|
|
70
112
|
file,
|
|
71
|
-
|
|
113
|
+
analyzeSource(file, gitOutput(root, ["show", `${revision}:${file}`])),
|
|
114
|
+
]),
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function testMetricsAtRevision(root, revision) {
|
|
119
|
+
const files = gitOutput(root, ["ls-tree", "-r", "--name-only", revision])
|
|
120
|
+
.split("\n")
|
|
121
|
+
.filter((file) =>
|
|
122
|
+
/(?:^tests\/|(?:^|\/)tests?\/).+\.(?:c|m)?js$/u.test(file),
|
|
123
|
+
)
|
|
124
|
+
.sort();
|
|
125
|
+
return Object.fromEntries(
|
|
126
|
+
files.map((file) => [
|
|
127
|
+
file,
|
|
128
|
+
analyzeSource(file, gitOutput(root, ["show", `${revision}:${file}`])),
|
|
129
|
+
]),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function workflowMetricsAtRevision(root, revision) {
|
|
134
|
+
const files = gitOutput(root, ["ls-tree", "-r", "--name-only", revision])
|
|
135
|
+
.split("\n")
|
|
136
|
+
.filter((file) => /^\.github\/workflows\/.*\.ya?ml$/u.test(file))
|
|
137
|
+
.sort();
|
|
138
|
+
return Object.fromEntries(
|
|
139
|
+
files.map((file) => [
|
|
140
|
+
file,
|
|
141
|
+
analyzeWorkflow(file, gitOutput(root, ["show", `${revision}:${file}`])),
|
|
72
142
|
]),
|
|
73
143
|
);
|
|
74
144
|
}
|
|
@@ -276,10 +346,14 @@ function evaluateRepositoryBudgets({ current, policy }) {
|
|
|
276
346
|
return issues;
|
|
277
347
|
}
|
|
278
348
|
|
|
349
|
+
function budgetsForFile(policy, file) {
|
|
350
|
+
return file.endsWith(".rs") ? policy.rustBudgets : policy.sourceBudgets;
|
|
351
|
+
}
|
|
352
|
+
|
|
279
353
|
function evaluateMaintainability({ current, baselineFiles, policy }) {
|
|
280
354
|
const issues = [];
|
|
281
|
-
const budgets = policy.sourceBudgets;
|
|
282
355
|
for (const [file, metrics] of Object.entries(current.files)) {
|
|
356
|
+
const budgets = budgetsForFile(policy, file);
|
|
283
357
|
const baseline = baselineFiles[file];
|
|
284
358
|
if (!baseline) {
|
|
285
359
|
const transition = policy.approvedNewFileTransitions?.[file];
|
|
@@ -381,15 +455,66 @@ function evaluateMaintainability({ current, baselineFiles, policy }) {
|
|
|
381
455
|
|
|
382
456
|
function checkMaintainability({ root = process.cwd() } = {}) {
|
|
383
457
|
const policy = readJson(root, "architecture/maintainability-policy.json");
|
|
458
|
+
if (policy.schemaVersion !== 2) {
|
|
459
|
+
throw new Error("maintainability policy schemaVersion must be 2");
|
|
460
|
+
}
|
|
384
461
|
const baseline = readJson(root, policy.baseline);
|
|
385
462
|
const enforcementRevision = policy.enforcementRevision || baseline.revision;
|
|
463
|
+
const extendedCoverageRevision =
|
|
464
|
+
policy.extendedCoverageRevision || enforcementRevision;
|
|
386
465
|
const hydratedRevisions = ensureMaintainabilityRevisionsAvailable(root, {
|
|
387
466
|
baselineRevision: baseline.revision,
|
|
388
467
|
enforcementRevision,
|
|
389
468
|
});
|
|
469
|
+
const hydratedExtendedCoverageRevision = ensureRevisionAvailable(
|
|
470
|
+
root,
|
|
471
|
+
extendedCoverageRevision,
|
|
472
|
+
);
|
|
390
473
|
const current = collectMaintainabilityMetrics({ root });
|
|
474
|
+
const debt = readJson(root, "architecture/maintainability-debt.json");
|
|
475
|
+
const architecture = readJson(
|
|
476
|
+
root,
|
|
477
|
+
"architecture/internal-capabilities.json",
|
|
478
|
+
);
|
|
391
479
|
const baselineFiles = sourceMetricsAtRevision(root, enforcementRevision);
|
|
392
|
-
const
|
|
480
|
+
const extendedSourceFiles = sourceMetricsAtRevision(
|
|
481
|
+
root,
|
|
482
|
+
extendedCoverageRevision,
|
|
483
|
+
);
|
|
484
|
+
for (const [file, metrics] of Object.entries(extendedSourceFiles)) {
|
|
485
|
+
if (file.endsWith(".rs")) baselineFiles[file] = metrics;
|
|
486
|
+
}
|
|
487
|
+
const baselineTests = testMetricsAtRevision(root, extendedCoverageRevision);
|
|
488
|
+
const baselineWorkflows = workflowMetricsAtRevision(
|
|
489
|
+
root,
|
|
490
|
+
extendedCoverageRevision,
|
|
491
|
+
);
|
|
492
|
+
const issues = evaluateExceptionGovernance({ policy });
|
|
493
|
+
issues.push(...evaluateExceptionBudget({ policy }));
|
|
494
|
+
const hotspots = collectHotspots(root, current, 20, debt.hotspots || []);
|
|
495
|
+
issues.push(
|
|
496
|
+
...evaluateDebtAuthority({
|
|
497
|
+
current,
|
|
498
|
+
policy,
|
|
499
|
+
debt,
|
|
500
|
+
capabilityIds: new Set(
|
|
501
|
+
architecture.capabilities.map((entry) => entry.id),
|
|
502
|
+
),
|
|
503
|
+
hotspots,
|
|
504
|
+
}),
|
|
505
|
+
);
|
|
506
|
+
issues.push(...evaluateDebtBudget({ debt, policy }));
|
|
507
|
+
issues.push(...evaluateMaintainability({ current, baselineFiles, policy }));
|
|
508
|
+
issues.push(
|
|
509
|
+
...evaluateTestBudgets({ current, baselineFiles: baselineTests, policy }),
|
|
510
|
+
);
|
|
511
|
+
issues.push(
|
|
512
|
+
...evaluateWorkflowBudgets({
|
|
513
|
+
current,
|
|
514
|
+
baselineFiles: baselineWorkflows,
|
|
515
|
+
policy,
|
|
516
|
+
}),
|
|
517
|
+
);
|
|
393
518
|
issues.push(...evaluateRepositoryBudgets({ current, policy }));
|
|
394
519
|
issues.push(
|
|
395
520
|
...evaluatePublicSurface({ root, revision: enforcementRevision, policy }),
|
|
@@ -401,12 +526,18 @@ function checkMaintainability({ root = process.cwd() } = {}) {
|
|
|
401
526
|
schemaVersion: 1,
|
|
402
527
|
baselineRevision: baseline.revision,
|
|
403
528
|
enforcementRevision,
|
|
529
|
+
extendedCoverageRevision,
|
|
404
530
|
hydratedBaselineRevision: hydratedRevisions[baseline.revision],
|
|
405
531
|
hydratedEnforcementRevision: hydratedRevisions[enforcementRevision],
|
|
532
|
+
hydratedExtendedCoverageRevision,
|
|
406
533
|
trackedFiles: current.repository.trackedFiles,
|
|
407
534
|
sourceFiles: current.repository.handMaintainedSourceFiles,
|
|
408
535
|
publicSurface: current.publicSurface,
|
|
409
536
|
hotspots: current.hotspots,
|
|
537
|
+
governedDebtSurfaces: Object.values(debt.surfaces).reduce(
|
|
538
|
+
(total, entries) => total + Object.keys(entries).length,
|
|
539
|
+
0,
|
|
540
|
+
),
|
|
410
541
|
};
|
|
411
542
|
}
|
|
412
543
|
|
|
@@ -427,11 +558,21 @@ if (
|
|
|
427
558
|
}
|
|
428
559
|
|
|
429
560
|
export {
|
|
561
|
+
calculateDebtMeasuredExcess,
|
|
430
562
|
checkMaintainability,
|
|
563
|
+
collectHotspots,
|
|
431
564
|
ensureMaintainabilityRevisionsAvailable,
|
|
432
565
|
ensureRevisionAvailable,
|
|
433
566
|
evaluateMaintainability,
|
|
567
|
+
evaluateDebtAuthority,
|
|
568
|
+
evaluateDebtBudget,
|
|
569
|
+
evaluateExceptionBudget,
|
|
570
|
+
evaluateExceptionGovernance,
|
|
434
571
|
evaluateRepositoryBudgets,
|
|
572
|
+
evaluateTestBudgets,
|
|
573
|
+
evaluateWorkflowBudgets,
|
|
435
574
|
evaluatePublicSurface,
|
|
436
575
|
sourceMetricsAtRevision,
|
|
576
|
+
testMetricsAtRevision,
|
|
577
|
+
workflowMetricsAtRevision,
|
|
437
578
|
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import {
|
|
4
|
+
ProjectCutAdmissionError,
|
|
5
|
+
qualifyProjectCut,
|
|
6
|
+
releaseFamilyQueueLease,
|
|
7
|
+
} from "./project-cut-merge-queue-admission.mjs";
|
|
8
|
+
|
|
9
|
+
function parseArguments(argv) {
|
|
10
|
+
const options = {};
|
|
11
|
+
const names = new Map([
|
|
12
|
+
["--base", "base"],
|
|
13
|
+
["--head", "head"],
|
|
14
|
+
["--initiative-id", "initiativeId"],
|
|
15
|
+
["--assignment-id", "assignmentId"],
|
|
16
|
+
["--delivery-class", "deliveryClass"],
|
|
17
|
+
["--queue-attempt", "queueAttempt"],
|
|
18
|
+
["--admission-proof-root", "admissionProofRoot"],
|
|
19
|
+
["--release-family-marker", "releaseFamilyMarker"],
|
|
20
|
+
["--expected-pr-head", "expectedPullRequestHead"],
|
|
21
|
+
["--terminal-reason", "terminalReason"],
|
|
22
|
+
["--evidence-root", "evidenceRoot"],
|
|
23
|
+
]);
|
|
24
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
25
|
+
const name = argv[index];
|
|
26
|
+
const key = names.get(name);
|
|
27
|
+
if (!key) throw new Error(`unknown argument: ${name}`);
|
|
28
|
+
const value = argv[index + 1];
|
|
29
|
+
if (value === undefined || value.startsWith("--"))
|
|
30
|
+
throw new Error(`${name} requires a value`);
|
|
31
|
+
if (Object.hasOwn(options, key))
|
|
32
|
+
throw new Error(`${name} was provided more than once`);
|
|
33
|
+
options[key] = value;
|
|
34
|
+
index += 1;
|
|
35
|
+
}
|
|
36
|
+
return options;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function markerText(path) {
|
|
40
|
+
return path === "-"
|
|
41
|
+
? fs.readFileSync(0, "utf8")
|
|
42
|
+
: fs.readFileSync(path, "utf8");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function repairReceipt(error) {
|
|
46
|
+
return {
|
|
47
|
+
schema: "project.cut.merge-queue-admission/v1",
|
|
48
|
+
ok: false,
|
|
49
|
+
decision: "repair-required",
|
|
50
|
+
retryable: false,
|
|
51
|
+
compositionChanged: false,
|
|
52
|
+
reasonCodes: [error.reasonCode],
|
|
53
|
+
error: error.message,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function main(argv = process.argv.slice(2)) {
|
|
58
|
+
try {
|
|
59
|
+
const options = parseArguments(argv);
|
|
60
|
+
if (options.releaseFamilyMarker) {
|
|
61
|
+
console.log(
|
|
62
|
+
JSON.stringify(
|
|
63
|
+
releaseFamilyQueueLease(
|
|
64
|
+
markerText(options.releaseFamilyMarker),
|
|
65
|
+
options,
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
if (!options.base || !options.head)
|
|
72
|
+
throw new Error("--base and --head are required");
|
|
73
|
+
console.log(
|
|
74
|
+
JSON.stringify(qualifyProjectCut({ cwd: process.cwd(), ...options })),
|
|
75
|
+
);
|
|
76
|
+
return 0;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error instanceof ProjectCutAdmissionError) {
|
|
79
|
+
console.log(JSON.stringify(repairReceipt(error)));
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
console.error(`project-cut admission error: ${error.message}`);
|
|
83
|
+
return 2;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (import.meta.url === `file://${process.argv[1]}`) process.exitCode = main();
|