@agent-teams/engineering-foundation 1.4.2 → 1.5.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.
Files changed (150) hide show
  1. package/dist/capabilities/public-api-compatibility/adapters/inbound/authority/growth-authority-contract.d.ts +10 -0
  2. package/dist/capabilities/public-api-compatibility/adapters/inbound/authority/growth-authority-contract.d.ts.map +1 -0
  3. package/dist/capabilities/public-api-compatibility/adapters/inbound/authority/growth-authority-contract.js +2 -0
  4. package/dist/capabilities/public-api-compatibility/adapters/inbound/authority/growth-authority-contract.js.map +1 -0
  5. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/load-pinned-audit-sdk.d.ts +1 -0
  6. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/load-pinned-audit-sdk.d.ts.map +1 -1
  7. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/load-pinned-audit-sdk.js +1 -0
  8. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/load-pinned-audit-sdk.js.map +1 -1
  9. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/microsoft-public-api-observer.d.ts.map +1 -1
  10. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/microsoft-public-api-observer.js +10 -1
  11. package/dist/capabilities/public-api-compatibility/adapters/outbound/api-extractor/microsoft-public-api-observer.js.map +1 -1
  12. package/dist/capabilities/public-api-compatibility/adapters/outbound/crypto/node-change-fingerprint.d.ts +2 -1
  13. package/dist/capabilities/public-api-compatibility/adapters/outbound/crypto/node-change-fingerprint.d.ts.map +1 -1
  14. package/dist/capabilities/public-api-compatibility/adapters/outbound/crypto/node-change-fingerprint.js +4 -1
  15. package/dist/capabilities/public-api-compatibility/adapters/outbound/crypto/node-change-fingerprint.js.map +1 -1
  16. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/artifact-public-api-evidence.d.ts +7 -1
  17. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/artifact-public-api-evidence.d.ts.map +1 -1
  18. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/artifact-public-api-evidence.js +16 -0
  19. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/artifact-public-api-evidence.js.map +1 -1
  20. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/filesystem-public-api-repository.d.ts +6 -0
  21. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/filesystem-public-api-repository.d.ts.map +1 -1
  22. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/filesystem-public-api-repository.js +22 -2
  23. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/filesystem-public-api-repository.js.map +1 -1
  24. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-invocation.d.ts +3 -1
  25. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-invocation.d.ts.map +1 -1
  26. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-invocation.js +10 -7
  27. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-invocation.js.map +1 -1
  28. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-metadata-root-sources.d.ts +13 -0
  29. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-metadata-root-sources.d.ts.map +1 -0
  30. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-metadata-root-sources.js +38 -0
  31. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-metadata-root-sources.js.map +1 -0
  32. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-report-writer.d.ts +3 -0
  33. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-report-writer.d.ts.map +1 -1
  34. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-report-writer.js +17 -0
  35. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/growth-report-writer.js.map +1 -1
  36. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-baseline-mapper.d.ts +1 -1
  37. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-baseline-mapper.d.ts.map +1 -1
  38. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-baseline-mapper.js +6 -2
  39. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-baseline-mapper.js.map +1 -1
  40. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-evidence-files.d.ts.map +1 -1
  41. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-evidence-files.js +64 -26
  42. package/dist/capabilities/public-api-compatibility/adapters/outbound/filesystem/public-api-evidence-files.js.map +1 -1
  43. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/reviewrouter-growth-authority-acl.d.ts +18 -0
  44. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/reviewrouter-growth-authority-acl.d.ts.map +1 -0
  45. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/reviewrouter-growth-authority-acl.js +51 -0
  46. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/reviewrouter-growth-authority-acl.js.map +1 -0
  47. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/strict-json-response.d.ts +5 -0
  48. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/strict-json-response.d.ts.map +1 -0
  49. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/strict-json-response.js +118 -0
  50. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/strict-json-response.js.map +1 -0
  51. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-input-context.d.ts +28 -0
  52. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-input-context.d.ts.map +1 -0
  53. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-input-context.js +163 -0
  54. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-input-context.js.map +1 -0
  55. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-observation.d.ts +8 -0
  56. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-observation.d.ts.map +1 -0
  57. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-observation.js +59 -0
  58. package/dist/capabilities/public-api-compatibility/adapters/outbound/reviewrouter/verified-growth-observation.js.map +1 -0
  59. package/dist/capabilities/public-api-compatibility/api.d.ts +1 -0
  60. package/dist/capabilities/public-api-compatibility/api.d.ts.map +1 -1
  61. package/dist/capabilities/public-api-compatibility/application/model/growth-admission-context.d.ts +9 -0
  62. package/dist/capabilities/public-api-compatibility/application/model/growth-admission-context.d.ts.map +1 -1
  63. package/dist/capabilities/public-api-compatibility/application/model/growth-authority.d.ts +243 -0
  64. package/dist/capabilities/public-api-compatibility/application/model/growth-authority.d.ts.map +1 -0
  65. package/dist/capabilities/public-api-compatibility/application/model/growth-authority.js +5 -0
  66. package/dist/capabilities/public-api-compatibility/application/model/growth-authority.js.map +1 -0
  67. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-admission.d.ts +18 -2
  68. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-admission.d.ts.map +1 -1
  69. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-admission.js +35 -15
  70. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-admission.js.map +1 -1
  71. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-release-compatibility.d.ts +4 -2
  72. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-release-compatibility.d.ts.map +1 -1
  73. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-release-compatibility.js +76 -9
  74. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-growth-release-compatibility.js.map +1 -1
  75. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-initial-release.d.ts +15 -0
  76. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-initial-release.d.ts.map +1 -0
  77. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-initial-release.js +26 -0
  78. package/dist/capabilities/public-api-compatibility/application/policies/evaluate-initial-release.js.map +1 -0
  79. package/dist/capabilities/public-api-compatibility/application/policies/normalize-growth-observation.d.ts.map +1 -1
  80. package/dist/capabilities/public-api-compatibility/application/policies/normalize-growth-observation.js +2 -1
  81. package/dist/capabilities/public-api-compatibility/application/policies/normalize-growth-observation.js.map +1 -1
  82. package/dist/capabilities/public-api-compatibility/application/policies/project-growth-report.js +47 -19
  83. package/dist/capabilities/public-api-compatibility/application/policies/project-growth-report.js.map +1 -1
  84. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority-primitives.d.ts +18 -0
  85. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority-primitives.d.ts.map +1 -0
  86. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority-primitives.js +153 -0
  87. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority-primitives.js.map +1 -0
  88. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority.d.ts +24 -0
  89. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority.d.ts.map +1 -0
  90. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority.js +610 -0
  91. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-authority.js.map +1 -0
  92. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-installed-inventory.d.ts +8 -0
  93. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-installed-inventory.d.ts.map +1 -0
  94. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-installed-inventory.js +11 -0
  95. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-installed-inventory.js.map +1 -0
  96. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-metadata-root.d.ts +13 -0
  97. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-metadata-root.d.ts.map +1 -0
  98. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-metadata-root.js +121 -0
  99. package/dist/capabilities/public-api-compatibility/application/policies/validate-growth-metadata-root.js.map +1 -0
  100. package/dist/capabilities/public-api-compatibility/application/ports/change-fingerprint.d.ts +2 -1
  101. package/dist/capabilities/public-api-compatibility/application/ports/change-fingerprint.d.ts.map +1 -1
  102. package/dist/capabilities/public-api-compatibility/application/ports/growth-authority.d.ts +17 -0
  103. package/dist/capabilities/public-api-compatibility/application/ports/growth-authority.d.ts.map +1 -0
  104. package/dist/capabilities/public-api-compatibility/application/ports/growth-authority.js +2 -0
  105. package/dist/capabilities/public-api-compatibility/application/ports/growth-authority.js.map +1 -0
  106. package/dist/capabilities/public-api-compatibility/application/ports/growth-input-context.d.ts +11 -1
  107. package/dist/capabilities/public-api-compatibility/application/ports/growth-input-context.d.ts.map +1 -1
  108. package/dist/capabilities/public-api-compatibility/application/ports/public-api-repository.d.ts +6 -0
  109. package/dist/capabilities/public-api-compatibility/application/ports/public-api-repository.d.ts.map +1 -1
  110. package/dist/capabilities/public-api-compatibility/application/use-cases/admit-sdk-growth.d.ts.map +1 -1
  111. package/dist/capabilities/public-api-compatibility/application/use-cases/admit-sdk-growth.js +31 -5
  112. package/dist/capabilities/public-api-compatibility/application/use-cases/admit-sdk-growth.js.map +1 -1
  113. package/dist/capabilities/public-api-compatibility/application/use-cases/check-sdk-growth.d.ts +11 -2
  114. package/dist/capabilities/public-api-compatibility/application/use-cases/check-sdk-growth.d.ts.map +1 -1
  115. package/dist/capabilities/public-api-compatibility/application/use-cases/check-sdk-growth.js +11 -8
  116. package/dist/capabilities/public-api-compatibility/application/use-cases/check-sdk-growth.js.map +1 -1
  117. package/dist/capabilities/public-api-compatibility/application/use-cases/preflight-public-api-promotions.d.ts +2 -1
  118. package/dist/capabilities/public-api-compatibility/application/use-cases/preflight-public-api-promotions.d.ts.map +1 -1
  119. package/dist/capabilities/public-api-compatibility/application/use-cases/preflight-public-api-promotions.js +16 -4
  120. package/dist/capabilities/public-api-compatibility/application/use-cases/preflight-public-api-promotions.js.map +1 -1
  121. package/dist/capabilities/public-api-compatibility/application/use-cases/promote-public-api-baselines.js +9 -7
  122. package/dist/capabilities/public-api-compatibility/application/use-cases/promote-public-api-baselines.js.map +1 -1
  123. package/dist/capabilities/public-api-compatibility/application/use-cases/qualify-sdk-growth.d.ts +16 -0
  124. package/dist/capabilities/public-api-compatibility/application/use-cases/qualify-sdk-growth.d.ts.map +1 -0
  125. package/dist/capabilities/public-api-compatibility/application/use-cases/qualify-sdk-growth.js +45 -0
  126. package/dist/capabilities/public-api-compatibility/application/use-cases/qualify-sdk-growth.js.map +1 -0
  127. package/dist/capabilities/public-api-compatibility/authority-module.d.ts +30 -0
  128. package/dist/capabilities/public-api-compatibility/authority-module.d.ts.map +1 -0
  129. package/dist/capabilities/public-api-compatibility/authority-module.js +142 -0
  130. package/dist/capabilities/public-api-compatibility/authority-module.js.map +1 -0
  131. package/dist/capabilities/public-api-compatibility/module.d.ts +16 -0
  132. package/dist/capabilities/public-api-compatibility/module.d.ts.map +1 -1
  133. package/dist/capabilities/public-api-compatibility/module.js +6 -6
  134. package/dist/capabilities/public-api-compatibility/module.js.map +1 -1
  135. package/dist/composition/quality-coverage.d.ts +1 -1
  136. package/dist/composition/quality-coverage.d.ts.map +1 -1
  137. package/dist/composition/sdk-growth-authority.d.ts +13 -0
  138. package/dist/composition/sdk-growth-authority.d.ts.map +1 -0
  139. package/dist/composition/sdk-growth-authority.js +19 -0
  140. package/dist/composition/sdk-growth-authority.js.map +1 -0
  141. package/dist/features/validation-reporting/api.d.ts +1 -1
  142. package/dist/features/validation-reporting/api.d.ts.map +1 -1
  143. package/dist/features/validation-reporting/api.js.map +1 -1
  144. package/dist/features/validation-reporting/application/model.d.ts +2 -3
  145. package/dist/features/validation-reporting/application/model.d.ts.map +1 -1
  146. package/dist/sdk-growth-authority.d.ts +15 -0
  147. package/dist/sdk-growth-authority.d.ts.map +1 -0
  148. package/dist/sdk-growth-authority.js +2 -0
  149. package/dist/sdk-growth-authority.js.map +1 -0
  150. package/package.json +5 -1
@@ -0,0 +1,610 @@
1
+ import { growthAuthorityRequiredPhases, growthAuthoritySchemaVersion } from "../model/growth-authority.js";
2
+ import { hashGrowthPayload } from "./compare-growth-surfaces.js";
3
+ import { validateGrowthMetadataRoots } from "./validate-growth-metadata-root.js";
4
+ export { growthDecisionDigest, prepareGrowthDecisions } from "./evaluate-growth-admission.js";
5
+ import { growthCanonicalJson, growthObservationReference, growthUniqueSorted, normalizeGrowthInvocation, normalizeGrowthObservation } from "./normalize-growth-observation.js";
6
+ import { array, commit, custodyPath, date, digest, exact, exactVersion, integrity, invalid, member, object, repositoryPath, source, text, uniqueMap } from "./validate-growth-authority-primitives.js";
7
+ export { validateGrowthInstalledInventory } from "./validate-growth-installed-inventory.js";
8
+ export function growthAuthorityRepositoryIdentity(repository) {
9
+ return `${repository.provider}:${repository.repositoryId}`;
10
+ }
11
+ function validateRepository(value) {
12
+ const row = object(value, ["provider", "repositoryId", "owner", "name"]);
13
+ const provider = text(row["provider"]), repositoryId = text(row["repositoryId"]);
14
+ if (!/^[a-z][a-z0-9.-]*$/u.test(provider) || !/^(?:0|[1-9]\d*)$/u.test(repositoryId)) {
15
+ invalid("growth-authority-repository-invalid");
16
+ }
17
+ return { provider, repositoryId, owner: text(row["owner"]), name: text(row["name"]) };
18
+ }
19
+ export function validateGrowthAuthorityBinding(value) {
20
+ const row = object(value, ["invocation", "target", "verifier", "tool", "policy", "historyDigest", "evidenceManifestDigest"]);
21
+ const targetRow = object(row["target"], ["repository", "pullRequestNumber", "head", "base", "mergeBase", "evaluation", "evaluationKind"]);
22
+ const repository = validateRepository(targetRow["repository"]), pullRequestNumber = targetRow["pullRequestNumber"];
23
+ if (!Number.isSafeInteger(pullRequestNumber) || pullRequestNumber <= 0) {
24
+ invalid("growth-authority-pr-invalid");
25
+ }
26
+ if (!["head", "merge-result", "release-preimage"].includes(String(targetRow["evaluationKind"]))) {
27
+ invalid("growth-authority-evaluation-kind-invalid");
28
+ }
29
+ const head = source(targetRow["head"]), base = source(targetRow["base"]), mergeBase = source(targetRow["mergeBase"]), evaluation = source(targetRow["evaluation"]);
30
+ if (targetRow["evaluationKind"] === "head") {
31
+ exact(evaluation, head, "growth-authority-evaluation-mismatch");
32
+ }
33
+ const verifier = object(row["verifier"], ["identity", "immutableRevision", "artifactDigest"]);
34
+ const tool = object(row["tool"], ["packageName", "version", "archiveDigest", "archiveIntegrity", "distributionDigest", "extractorVersion"]);
35
+ if (tool["packageName"] !== "@agent-teams/engineering-foundation") {
36
+ invalid("growth-authority-tool-invalid");
37
+ }
38
+ const policy = object(row["policy"], ["contractRevision", "policyVersion", "enrollmentRevision", "configurationDigest", "scopeDigest", "commandDigest"]);
39
+ if (policy["contractRevision"] !== "foundation:sdk-growth:c0:5" || policy["policyVersion"] !== "foundation:sdk-growth:policy:1") {
40
+ invalid("growth-authority-policy-invalid");
41
+ }
42
+ const invocation = normalizeGrowthInvocation(row["invocation"]);
43
+ if (invocation.repository !== growthAuthorityRepositoryIdentity(repository)
44
+ || invocation.sourceCommit !== evaluation.commit || invocation.sourceTree !== evaluation.tree) {
45
+ invalid("growth-authority-evaluation-mismatch");
46
+ }
47
+ const version = exactVersion(tool["version"]), extractorVersion = text(tool["extractorVersion"]), distributionDigest = digest(tool["distributionDigest"]);
48
+ if (version !== invocation.tool.version || extractorVersion !== invocation.tool.extractorVersion || distributionDigest !== invocation.tool.artifactDigest) {
49
+ invalid("growth-authority-tool-binding-mismatch");
50
+ }
51
+ return {
52
+ invocation,
53
+ target: { repository, pullRequestNumber: pullRequestNumber, head, base, mergeBase, evaluation,
54
+ evaluationKind: targetRow["evaluationKind"] },
55
+ verifier: { identity: text(verifier["identity"]), immutableRevision: commit(verifier["immutableRevision"]), artifactDigest: digest(verifier["artifactDigest"]) },
56
+ tool: { packageName: "@agent-teams/engineering-foundation", version, archiveDigest: digest(tool["archiveDigest"]),
57
+ archiveIntegrity: integrity(tool["archiveIntegrity"]), distributionDigest, extractorVersion },
58
+ policy: { contractRevision: "foundation:sdk-growth:c0:5", policyVersion: "foundation:sdk-growth:policy:1",
59
+ enrollmentRevision: commit(policy["enrollmentRevision"]), configurationDigest: digest(policy["configurationDigest"]),
60
+ scopeDigest: digest(policy["scopeDigest"]), commandDigest: digest(policy["commandDigest"]) },
61
+ historyDigest: digest(row["historyDigest"]), evidenceManifestDigest: digest(row["evidenceManifestDigest"])
62
+ };
63
+ }
64
+ function validateSelectors(value) {
65
+ const row = object(structuredClone(value), ["trustedBasePath", "decisionsPath", "released"]);
66
+ if (!Array.isArray(row["released"]) || row["released"].length > 10_000) {
67
+ invalid("growth-authority-selectors-invalid");
68
+ }
69
+ const released = row["released"].map((entry) => {
70
+ const kind = member(entry, "kind");
71
+ if (kind !== "released" && kind !== "initial-unreleased") {
72
+ return invalid("growth-authority-selectors-invalid");
73
+ }
74
+ const wire = object(entry, kind === "released"
75
+ ? ["packageName", "kind", "observationPath"] : ["packageName", "kind", "trustedHistoryPath"]);
76
+ const packageName = text(wire["packageName"]);
77
+ return kind === "released"
78
+ ? { packageName, kind: "released", observationPath: repositoryPath(wire["observationPath"]) }
79
+ : { packageName, kind: "initial-unreleased", trustedHistoryPath: repositoryPath(wire["trustedHistoryPath"]) };
80
+ });
81
+ uniqueMap(released, (entry) => entry.packageName, "growth-authority-selector-duplicate");
82
+ return { trustedBasePath: repositoryPath(row["trustedBasePath"]), decisionsPath: repositoryPath(row["decisionsPath"]),
83
+ released: growthUniqueSorted(released, (entry) => entry.packageName) };
84
+ }
85
+ function validateGrowthAuthorityRequest(value) {
86
+ const row = object(value, ["schemaVersion", "kind", "operation", "admissionReceiptId", "binding", "contextSelectors", "decisionDigests", "requiredPhases"]);
87
+ if (row["schemaVersion"] !== growthAuthoritySchemaVersion || row["kind"] !== "request" || !["check", "promote-release"].includes(String(row["operation"]))) {
88
+ invalid("growth-authority-request-invalid");
89
+ }
90
+ if (!Array.isArray(row["decisionDigests"]) || row["decisionDigests"].length > 10_000) {
91
+ invalid("growth-authority-decision-budget-exhausted");
92
+ }
93
+ const decisionDigests = row["decisionDigests"].map(digest);
94
+ if (new Set(decisionDigests).size !== decisionDigests.length) {
95
+ invalid("growth-authority-decision-duplicate");
96
+ }
97
+ if ((row["operation"] === "check" && row["admissionReceiptId"] !== null)
98
+ || (row["operation"] === "promote-release" && (typeof row["admissionReceiptId"] !== "string" || row["admissionReceiptId"].trim() === ""))) {
99
+ invalid("growth-authority-admission-receipt-invalid");
100
+ }
101
+ if (!Array.isArray(row["requiredPhases"])) {
102
+ invalid("growth-authority-phases-invalid");
103
+ }
104
+ exact(row["requiredPhases"], growthAuthorityRequiredPhases, "growth-authority-phases-invalid");
105
+ return { schemaVersion: growthAuthoritySchemaVersion, kind: "request", operation: row["operation"],
106
+ admissionReceiptId: row["admissionReceiptId"], binding: validateGrowthAuthorityBinding(row["binding"]),
107
+ contextSelectors: validateSelectors(row["contextSelectors"]),
108
+ decisionDigests: growthUniqueSorted(decisionDigests, (entry) => entry), requiredPhases: growthAuthorityRequiredPhases };
109
+ }
110
+ export function growthAuthorityRequestDigest(request, fingerprint) {
111
+ return hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:request:3", request: validateGrowthAuthorityRequest(request) }, fingerprint);
112
+ }
113
+ export function growthAuthorityGrantDigest(grant, fingerprint) {
114
+ return hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:grant:3", grant }, fingerprint);
115
+ }
116
+ export function growthAuthorityCompletionDigest(completion, fingerprint) {
117
+ return hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:completion:3", completion }, fingerprint);
118
+ }
119
+ export function growthPromotionPlanDigest(plan, fingerprint) {
120
+ return hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:promotion-plan:3", plan }, fingerprint);
121
+ }
122
+ export function growthReportAuthorityDigests(report, fingerprint) {
123
+ return { coverageDigest: hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:coverage:3", coverage: report.coverage }, fingerprint),
124
+ phasesDigest: hashGrowthPayload({ domain: "reviewrouter:sdk-growth-authority:phases:3", phases: report.phases }, fingerprint) };
125
+ }
126
+ function validateOwnerEvidence(value) {
127
+ const row = object(value, ["decisionId", "ownerRef", "decisionDigest", "authenticatedSubjectId", "authorizationEvidenceDigest", "approvalEvidenceDigest", "sourceBindingDigest"]);
128
+ return { decisionId: text(row["decisionId"]), ownerRef: text(row["ownerRef"]), decisionDigest: digest(row["decisionDigest"]),
129
+ authenticatedSubjectId: text(row["authenticatedSubjectId"]), authorizationEvidenceDigest: digest(row["authorizationEvidenceDigest"]),
130
+ approvalEvidenceDigest: digest(row["approvalEvidenceDigest"]), sourceBindingDigest: digest(row["sourceBindingDigest"]) };
131
+ }
132
+ function validateReleaseEvidence(value, packageName) {
133
+ const declaredBumpInput = member(value, "declaredBump");
134
+ const prereleaseInitialVersionInput = member(value, "prereleaseInitialVersion");
135
+ const prereleaseTagInput = member(value, "prereleaseTag");
136
+ const row = object(value, ["packageName", "packageVersion", ...(declaredBumpInput === undefined ? [] : ["declaredBump"]),
137
+ ...(prereleaseInitialVersionInput === undefined ? [] : ["prereleaseInitialVersion"]), ...(prereleaseTagInput === undefined ? [] : ["prereleaseTag"])]);
138
+ if (row["packageName"] !== packageName) {
139
+ invalid("growth-authority-release-identity-mismatch");
140
+ }
141
+ const declaredBump = row["declaredBump"];
142
+ if (declaredBump !== undefined && declaredBump !== "patch" && declaredBump !== "minor" && declaredBump !== "major") {
143
+ invalid("growth-authority-release-invalid");
144
+ }
145
+ const prereleaseInitialVersion = row["prereleaseInitialVersion"], prereleaseTag = row["prereleaseTag"];
146
+ if ((prereleaseInitialVersion === undefined) !== (prereleaseTag === undefined)) {
147
+ invalid("growth-authority-release-invalid");
148
+ }
149
+ return { packageName, packageVersion: exactVersion(row["packageVersion"]),
150
+ ...(declaredBump === undefined ? {} : { declaredBump }),
151
+ ...(prereleaseInitialVersion === undefined ? {} : { prereleaseInitialVersion: exactVersion(prereleaseInitialVersion), prereleaseTag: text(prereleaseTag) }) };
152
+ }
153
+ function rejectSnapshotProxy(value, inspection, reason) {
154
+ try {
155
+ if (inspection.isProxy(value)) {
156
+ invalid(reason);
157
+ }
158
+ }
159
+ catch {
160
+ invalid(reason);
161
+ }
162
+ }
163
+ function snapshotObject(value, keys, inspection, reason) {
164
+ rejectSnapshotProxy(value, inspection, reason);
165
+ return object(value, keys, reason);
166
+ }
167
+ function snapshotArray(value, limit, inspection, reason) {
168
+ rejectSnapshotProxy(value, inspection, reason);
169
+ return array(value, limit, reason);
170
+ }
171
+ function snapshotSignature(value, reason) {
172
+ if (typeof value !== "string") {
173
+ invalid(reason);
174
+ }
175
+ let length = 0;
176
+ for (const codePoint of value) {
177
+ if (codePoint !== "") {
178
+ length += 1;
179
+ }
180
+ if (length > 10_000) {
181
+ invalid(reason);
182
+ }
183
+ }
184
+ return value;
185
+ }
186
+ function validatePublicApiSnapshot(value, inspection) {
187
+ const reason = "growth-authority-release-snapshot-invalid";
188
+ const row = snapshotObject(value, ["schemaVersion", "packageName", "packageVersion", "extractorVersion", "entrypoints"], inspection, reason);
189
+ if (row["schemaVersion"] !== 1) {
190
+ invalid(reason);
191
+ }
192
+ const packageName = text(row["packageName"]);
193
+ const entrypoints = snapshotArray(row["entrypoints"], 10_000, inspection, reason).map((entrypointInput) => {
194
+ const entrypoint = snapshotObject(entrypointInput, ["exportPath", "items"], inspection, reason);
195
+ const items = snapshotArray(entrypoint["items"], 100_000, inspection, reason).map((itemInput) => {
196
+ rejectSnapshotProxy(itemInput, inspection, reason);
197
+ const parentReference = member(itemInput, "parentReference");
198
+ const item = snapshotObject(itemInput, ["canonicalReference", "kind",
199
+ ...(parentReference === undefined ? [] : ["parentReference"]), "parentKind", "signature"], inspection, reason);
200
+ return { canonicalReference: text(item["canonicalReference"]), kind: text(item["kind"]),
201
+ ...(parentReference === undefined ? {} : { parentReference: text(parentReference) }),
202
+ parentKind: text(item["parentKind"]), signature: snapshotSignature(item["signature"], reason) };
203
+ });
204
+ return { exportPath: text(entrypoint["exportPath"]), items };
205
+ });
206
+ return { schemaVersion: 1, packageName, packageVersion: exactVersion(row["packageVersion"]),
207
+ extractorVersion: text(row["extractorVersion"]), entrypoints };
208
+ }
209
+ function validateReleased(value, repositoryIdentity, inspection) {
210
+ const observationInput = member(value, "observation");
211
+ const row = object(value, ["packageName", "releaseEvidence", ...(observationInput === undefined ? [] : ["observation"]), "evidence"]);
212
+ const packageName = text(row["packageName"]), releaseEvidence = validateReleaseEvidence(row["releaseEvidence"], packageName);
213
+ const evidence = row["evidence"], kind = member(evidence, "kind");
214
+ if (kind !== "released" && kind !== "initial-unreleased") {
215
+ return invalid("growth-authority-release-kind-invalid");
216
+ }
217
+ const wire = object(evidence, kind === "released" ? ["kind", "typed", "artifact"] : ["kind", "historyDigest"], kind === "released" ? "growth-authority-release-snapshot-invalid" : "growth-authority-contract-invalid");
218
+ const observation = observationInput === undefined ? undefined : normalizeGrowthObservation(observationInput);
219
+ if (observation !== undefined && observation.repository !== repositoryIdentity) {
220
+ invalid("growth-authority-release-repository-mismatch");
221
+ }
222
+ if (wire["kind"] === "released") {
223
+ const typed = validatePublicApiSnapshot(wire["typed"], inspection);
224
+ const artifact = validatePublicApiSnapshot(wire["artifact"], inspection);
225
+ return { packageName, releaseEvidence, ...(observation === undefined ? {} : { observation }),
226
+ evidence: { kind: "released", typed, artifact } };
227
+ }
228
+ if (wire["kind"] === "initial-unreleased") {
229
+ return { packageName, releaseEvidence, ...(observation === undefined ? {} : { observation }),
230
+ evidence: { kind: "initial-unreleased", historyDigest: digest(wire["historyDigest"]) } };
231
+ }
232
+ return invalid("growth-authority-release-kind-invalid");
233
+ }
234
+ function custodyDigest(evidence, fingerprint) {
235
+ return hashGrowthPayload({ domain: "foundation:sdk-growth:custody:1", payload: evidence }, fingerprint);
236
+ }
237
+ /** One archive representation: canonical JSON containing sorted paths and lowercase
238
+ * hexadecimal file bytes. Transport compression is deliberately outside this identity. */
239
+ function validateCustodyEvidence(value, fingerprint) {
240
+ const row = object(value, ["archiveDigest", "archiveIntegrity", "archivePayload", "archiveManifest", "installedFiles"]);
241
+ const payload = row["archivePayload"];
242
+ if (typeof payload !== "string" || payload.length > 64 * 1024 * 1024) {
243
+ invalid("growth-authority-custody-payload-invalid");
244
+ }
245
+ let parsed;
246
+ try {
247
+ parsed = JSON.parse(payload);
248
+ }
249
+ catch {
250
+ invalid("growth-authority-custody-payload-invalid");
251
+ }
252
+ const archive = object(parsed, ["schemaVersion", "files"]);
253
+ if (archive["schemaVersion"] !== "foundation:sdk-growth:archive:1") {
254
+ invalid("growth-authority-custody-payload-invalid");
255
+ }
256
+ const paths = new Set();
257
+ const files = array(archive["files"], 100_000, "growth-authority-custody-invalid").map((fileValue) => {
258
+ const file = object(fileValue, ["path", "contentHex"]), name = custodyPath(file["path"]), contentHex = file["contentHex"];
259
+ if (typeof contentHex !== "string" || !/^(?:[a-f0-9]{2})*$/u.test(contentHex)) {
260
+ invalid("growth-authority-custody-payload-invalid");
261
+ }
262
+ const identity = name.toLowerCase();
263
+ if (paths.has(identity)) {
264
+ invalid("growth-authority-custody-duplicate-path");
265
+ }
266
+ paths.add(identity);
267
+ return { path: name, contentHex };
268
+ }).toSorted((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
269
+ // Equality and hierarchy both use the same case-folded path identities.
270
+ for (const identity of paths) {
271
+ const parts = identity.split("/");
272
+ for (let index = 1; index < parts.length; index += 1) {
273
+ if (paths.has(parts.slice(0, index).join("/"))) {
274
+ invalid("growth-authority-path-invalid");
275
+ }
276
+ }
277
+ }
278
+ if (payload !== growthCanonicalJson({ schemaVersion: "foundation:sdk-growth:archive:1", files })) {
279
+ invalid("growth-authority-custody-payload-invalid");
280
+ }
281
+ const archiveDigest = `sha256:${fingerprint.sha256(payload)}`;
282
+ if (fingerprint.sha512Integrity === undefined) {
283
+ invalid("growth-authority-custody-integrity-unavailable");
284
+ }
285
+ const archiveIntegrity = fingerprint.sha512Integrity(payload);
286
+ if (archiveDigest !== digest(row["archiveDigest"])) {
287
+ invalid("growth-authority-archive-digest-mismatch");
288
+ }
289
+ if (archiveIntegrity !== integrity(row["archiveIntegrity"])) {
290
+ invalid("growth-authority-archive-integrity-mismatch");
291
+ }
292
+ const archiveManifest = files.map((file) => ({ path: file.path,
293
+ digest: `sha256:${fingerprint.sha256(Uint8Array.from(file.contentHex.match(/../gu) ?? [], (byte) => Number.parseInt(byte, 16)))}` }));
294
+ for (const field of ["archiveManifest", "installedFiles"]) {
295
+ const inventory = array(row[field], 100_000, "growth-authority-custody-invalid").map((fileValue) => {
296
+ const file = object(fileValue, ["path", "digest"]);
297
+ return { path: custodyPath(file["path"]), digest: digest(file["digest"]) };
298
+ });
299
+ uniqueMap(inventory, (file) => file.path.toLowerCase(), "growth-authority-custody-duplicate-path");
300
+ exact(inventory, archiveManifest, "growth-authority-custody-manifest-mismatch");
301
+ }
302
+ return { archiveDigest, archiveIntegrity, archivePayload: payload, archiveManifest, installedFiles: archiveManifest };
303
+ }
304
+ /** Package coordinates are read from the canonical archive, never inferred from
305
+ * transport labels or a producer's manifest. Retained observations are not packages. */
306
+ function validateArchivePackage(custody, packageName, packageVersion) {
307
+ const archive = JSON.parse(custody.archivePayload);
308
+ const manifest = archive.files.find((file) => file.path === "package.json");
309
+ if (manifest === undefined) {
310
+ invalid("growth-authority-archive-package-missing");
311
+ }
312
+ let metadata;
313
+ try {
314
+ const bytes = Uint8Array.from(manifest.contentHex.match(/../gu) ?? [], (byte) => Number.parseInt(byte, 16));
315
+ metadata = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
316
+ }
317
+ catch {
318
+ invalid("growth-authority-archive-package-invalid");
319
+ }
320
+ if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)
321
+ || member(metadata, "name") !== packageName || member(metadata, "version") !== packageVersion) {
322
+ invalid("growth-authority-archive-package-mismatch");
323
+ }
324
+ }
325
+ function validatePackedEvidence(value, repositoryIdentity, fingerprint) {
326
+ const row = object(value, ["packageName", "packageVersion", "source", "archiveDigest", "archiveIntegrity", "observation",
327
+ "observationDigest", "coverage", "custodyEvidence", "custodyEvidenceDigest", "installedDistribution"]);
328
+ const packageName = text(row["packageName"]), packageVersion = exactVersion(row["packageVersion"]);
329
+ const archiveSource = source(row["source"]), archiveDigest = digest(row["archiveDigest"]);
330
+ const archiveIntegrity = integrity(row["archiveIntegrity"]);
331
+ const observation = normalizeGrowthObservation(row["observation"]);
332
+ if (observation.repository !== repositoryIdentity) {
333
+ invalid("growth-authority-packed-repository-mismatch");
334
+ }
335
+ exact(archiveSource, { commit: observation.sourceCommit, tree: observation.sourceTree }, "growth-authority-archive-source-mismatch");
336
+ if (observation.coverage.length !== 1 || observation.coverage[0]?.packageName !== packageName
337
+ || observation.entries.some((entry) => entry.coordinate.packageName !== packageName)) {
338
+ invalid("growth-authority-packed-scope-mismatch");
339
+ }
340
+ const observationDigest = digest(row["observationDigest"]);
341
+ if (observationDigest !== growthObservationReference(observation, fingerprint).surfaceDigest) {
342
+ invalid("growth-authority-packed-observation-mismatch");
343
+ }
344
+ exact(row["coverage"], observation.coverage[0], "growth-authority-packed-coverage-mismatch");
345
+ const installed = object(row["installedDistribution"], ["packageName", "packageVersion", "source", "archiveDigest", "archiveIntegrity", "observationDigest"]);
346
+ const installedDistribution = { packageName: text(installed["packageName"]), packageVersion: exactVersion(installed["packageVersion"]),
347
+ source: source(installed["source"]), archiveDigest: digest(installed["archiveDigest"]), archiveIntegrity: integrity(installed["archiveIntegrity"]),
348
+ observationDigest: digest(installed["observationDigest"]) };
349
+ exact(installedDistribution, { packageName, packageVersion, source: archiveSource, archiveDigest, archiveIntegrity, observationDigest }, "growth-authority-installed-distribution-mismatch");
350
+ const custodyEvidence = validateCustodyEvidence(row["custodyEvidence"], fingerprint);
351
+ validateArchivePackage(custodyEvidence, packageName, packageVersion);
352
+ exact({ archiveDigest, archiveIntegrity }, { archiveDigest: custodyEvidence.archiveDigest, archiveIntegrity: custodyEvidence.archiveIntegrity }, "growth-authority-custody-inventory-mismatch");
353
+ const custodyEvidenceDigest = custodyDigest(custodyEvidence, fingerprint);
354
+ if (custodyEvidenceDigest !== digest(row["custodyEvidenceDigest"])) {
355
+ invalid("growth-authority-custody-digest-mismatch");
356
+ }
357
+ return { packageName, packageVersion, source: archiveSource, archiveDigest, archiveIntegrity, observation,
358
+ observationDigest, coverage: observation.coverage[0], custodyEvidenceDigest, custodyEvidence, installedDistribution };
359
+ }
360
+ function validateAdmissionReceipt(value, request, binding, fingerprint, timing) {
361
+ const kind = member(value, "kind");
362
+ const row = object(value, kind === "none" ? ["kind"] : ["kind", "receipt"]);
363
+ if (request.operation === "check") {
364
+ if (row["kind"] !== "none") {
365
+ invalid("growth-authority-admission-receipt-invalid");
366
+ }
367
+ return { kind: "none" };
368
+ }
369
+ if (row["kind"] !== "receipt") {
370
+ invalid("growth-authority-admission-receipt-invalid");
371
+ }
372
+ const receiptValue = row["receipt"];
373
+ const receiptKeys = ["schemaVersion", "kind", "receiptId", "grantId", "grantDigest", "requestDigest", "completionDigest", "provenance",
374
+ "binding", "reportDigest", "coverageDigest", "phasesDigest", "verdict", "releaseEligible", "qualification", "operation", "promotion", "custodyRef", "issuedAt"];
375
+ const receiptRow = object(receiptValue, receiptKeys);
376
+ if (receiptRow["schemaVersion"] !== growthAuthoritySchemaVersion || receiptRow["kind"] !== "receipt" || receiptRow["receiptId"] !== request.admissionReceiptId
377
+ || receiptRow["operation"] !== "check" || receiptRow["qualification"] !== "qualified" || receiptRow["verdict"] !== "admitted"
378
+ || receiptRow["releaseEligible"] !== true) {
379
+ invalid("growth-authority-admission-receipt-invalid");
380
+ }
381
+ const promotion = object(receiptRow["promotion"], ["kind"]);
382
+ if (promotion["kind"] !== "none") {
383
+ invalid("growth-authority-admission-receipt-invalid");
384
+ }
385
+ const receiptBinding = validateGrowthAuthorityBinding(receiptRow["binding"]);
386
+ exact(receiptBinding, binding, "growth-authority-admission-binding-mismatch");
387
+ const checkRequest = { ...request, operation: "check", admissionReceiptId: null };
388
+ const requestDigest = digest(receiptRow["requestDigest"]);
389
+ if (requestDigest !== growthAuthorityRequestDigest(checkRequest, fingerprint)) {
390
+ invalid("growth-authority-admission-request-mismatch");
391
+ }
392
+ const result = { schemaVersion: growthAuthoritySchemaVersion, kind: "receipt", receiptId: text(receiptRow["receiptId"]),
393
+ grantId: text(receiptRow["grantId"]), grantDigest: digest(receiptRow["grantDigest"]), requestDigest,
394
+ completionDigest: digest(receiptRow["completionDigest"]), binding: receiptBinding,
395
+ reportDigest: digest(receiptRow["reportDigest"]), coverageDigest: digest(receiptRow["coverageDigest"]), phasesDigest: digest(receiptRow["phasesDigest"]),
396
+ verdict: "admitted", releaseEligible: true, qualification: "qualified", operation: "check", promotion: { kind: "none" },
397
+ custodyRef: text(receiptRow["custodyRef"]), issuedAt: date(receiptRow["issuedAt"]) };
398
+ if (receiptKeys.includes("provenance")) {
399
+ return validateAdmissionProvenance(result, receiptRow, checkRequest, fingerprint, timing);
400
+ }
401
+ return { kind: "receipt", receipt: result };
402
+ }
403
+ function validateAdmissionProvenance(result, receiptRow, checkRequest, fingerprint, timing) {
404
+ if (timing.inspection === undefined) {
405
+ invalid("growth-authority-admission-provenance-invalid");
406
+ }
407
+ const provenance = object(receiptRow["provenance"], ["grant", "completion"]);
408
+ if (Date.parse(result.issuedAt) > timing.now.getTime()) {
409
+ invalid("growth-authority-admission-provenance-invalid");
410
+ }
411
+ const checkGrant = validateGrowthAuthorityGrant(provenance["grant"], checkRequest, fingerprint, timing.inspection, new Date(result.issuedAt));
412
+ const completionRow = object(provenance["completion"], ["schemaVersion", "kind", "grantId", "grantDigest", "requestDigest", "binding",
413
+ "reportDigest", "reportByteLength", "coverageDigest", "phasesDigest", "verdict", "releaseEligible", "publication", "promotion"]);
414
+ if (completionRow["schemaVersion"] !== growthAuthoritySchemaVersion || completionRow["kind"] !== "completion"
415
+ || completionRow["publication"] !== "finalized" || !Number.isSafeInteger(completionRow["reportByteLength"])
416
+ || completionRow["reportByteLength"] <= 0) {
417
+ invalid("growth-authority-admission-provenance-invalid");
418
+ }
419
+ const completion = provenance["completion"];
420
+ if (growthAuthorityGrantDigest(checkGrant, fingerprint) !== result.grantDigest
421
+ || checkGrant.grantId !== result.grantId
422
+ || growthAuthorityCompletionDigest(completion, fingerprint) !== result.completionDigest
423
+ || completion.grantId !== result.grantId || completion.grantDigest !== result.grantDigest) {
424
+ invalid("growth-authority-admission-provenance-mismatch");
425
+ }
426
+ validateGrowthAuthorityReceipt(result, completion, "check", fingerprint);
427
+ if (completion.coverageDigest !== checkGrant.requiredCoverageDigest) {
428
+ invalid("growth-authority-coverage-mismatch");
429
+ }
430
+ return { kind: "receipt", receipt: { ...result, provenance: { grant: checkGrant, completion } } };
431
+ }
432
+ function validateGrantEnvelope(row, now) {
433
+ const issuedAt = date(row["issuedAt"]), expiresAt = date(row["expiresAt"]);
434
+ if (Date.parse(issuedAt) > now.getTime() || Date.parse(expiresAt) <= now.getTime() || Date.parse(expiresAt) <= Date.parse(issuedAt)) {
435
+ invalid("growth-authority-grant-expired");
436
+ }
437
+ const collections = [row["released"], row["ownerEvidence"], row["archives"], row["candidates"]];
438
+ if (collections.some((entry) => !Array.isArray(entry) || entry.length > 10_000)) {
439
+ invalid("growth-authority-grant-invalid");
440
+ }
441
+ if (!Array.isArray(row["requiredPhases"])) {
442
+ invalid("growth-authority-phases-invalid");
443
+ }
444
+ exact(row["requiredPhases"], growthAuthorityRequiredPhases, "growth-authority-phases-invalid");
445
+ return { issuedAt, expiresAt };
446
+ }
447
+ /** Validates protocol framing and exact request bindings. Content schemas are
448
+ * validated by the verified context adapter before application policy sees it. */
449
+ export function validateGrowthAuthorityGrant(value, request, fingerprint, inspection, now) {
450
+ const row = object(value, ["schemaVersion", "kind", "grantId", "requestDigest", "admissionReceipt", "binding", "workflowRef", "runRef", "issuedAt", "expiresAt",
451
+ "trustedBase", "trustedBaseReference", "retainedHistory", "released", "ownerEvidence", "archives", "candidates", "metadataRoots", "requiredCoverageDigest", "requiredPhases"]);
452
+ if (row["schemaVersion"] !== growthAuthoritySchemaVersion || row["kind"] !== "grant") {
453
+ invalid("growth-authority-grant-invalid");
454
+ }
455
+ const binding = validateGrowthAuthorityBinding(row["binding"]);
456
+ exact(binding, request.binding, "growth-authority-binding-mismatch");
457
+ const requestDigest = digest(row["requestDigest"]);
458
+ if (requestDigest !== growthAuthorityRequestDigest(request, fingerprint)) {
459
+ invalid("growth-authority-request-mismatch");
460
+ }
461
+ const { issuedAt, expiresAt } = validateGrantEnvelope(row, now);
462
+ const trustedBase = normalizeGrowthObservation(row["trustedBase"]);
463
+ if (trustedBase.repository !== binding.invocation.repository) {
464
+ invalid("growth-authority-base-repository-mismatch");
465
+ }
466
+ const referenceRow = object(row["trustedBaseReference"], ["sourceCommit", "sourceTree", "surfaceDigest", "topologyDigest", "lockDigest", "toolchainDigest", "artifactDigests"]);
467
+ if (!Array.isArray(referenceRow["artifactDigests"])) {
468
+ invalid("growth-authority-base-reference-invalid");
469
+ }
470
+ const trustedBaseReference = { sourceCommit: commit(referenceRow["sourceCommit"]), sourceTree: commit(referenceRow["sourceTree"]),
471
+ surfaceDigest: digest(referenceRow["surfaceDigest"]), topologyDigest: digest(referenceRow["topologyDigest"]), lockDigest: digest(referenceRow["lockDigest"]),
472
+ toolchainDigest: digest(referenceRow["toolchainDigest"]), artifactDigests: growthUniqueSorted(referenceRow["artifactDigests"].map(digest), (entry) => entry) };
473
+ exact(trustedBaseReference, growthObservationReference(trustedBase, fingerprint), "growth-authority-base-reference-mismatch");
474
+ const historyValue = row["retainedHistory"];
475
+ const history = object(historyValue, ["targetSource", "targetSurfaceDigest", "receiptDigest", "custodyEvidenceDigest", "custodyEvidence"]);
476
+ const targetSource = source(history["targetSource"]);
477
+ exact(targetSource, { commit: trustedBase.sourceCommit, tree: trustedBase.sourceTree }, "growth-authority-history-source-mismatch");
478
+ if (digest(history["targetSurfaceDigest"]) !== trustedBaseReference.surfaceDigest) {
479
+ invalid("growth-authority-history-target-mismatch");
480
+ }
481
+ const releasedInput = row["released"], ownerInput = row["ownerEvidence"];
482
+ const archiveInput = row["archives"], candidateInput = row["candidates"];
483
+ const releasedRows = releasedInput.map((entry) => validateReleased(entry, binding.invocation.repository, inspection));
484
+ const ownerRows = ownerInput.map(validateOwnerEvidence);
485
+ const archiveRows = archiveInput.map((entry) => validatePackedEvidence(entry, binding.invocation.repository, fingerprint));
486
+ const candidateRows = candidateInput.map((entry) => validatePackedEvidence(entry, binding.invocation.repository, fingerprint));
487
+ const historicalCustody = digest(history["custodyEvidenceDigest"]);
488
+ const historicalEvidence = validateCustodyEvidence(history["custodyEvidence"], fingerprint);
489
+ if (custodyDigest(historicalEvidence, fingerprint) !== historicalCustody) {
490
+ invalid("growth-authority-history-custody-mismatch");
491
+ }
492
+ const retainedBase = historicalEvidence.archiveManifest.find((file) => file.path === "trusted-base.json");
493
+ if (retainedBase?.digest !== `sha256:${fingerprint.sha256(growthCanonicalJson(trustedBase))}`) {
494
+ invalid("growth-authority-history-custody-mismatch");
495
+ }
496
+ const releasedByPackage = uniqueMap(releasedRows, (entry) => entry.packageName, "growth-authority-release-duplicate");
497
+ uniqueMap(ownerRows, (entry) => entry.decisionId, "growth-authority-owner-duplicate");
498
+ const archiveByPackage = uniqueMap(archiveRows, (entry) => entry.packageName, "growth-authority-archive-duplicate");
499
+ const candidateByPackage = uniqueMap(candidateRows, (entry) => entry.packageName, "growth-authority-candidate-duplicate");
500
+ const released = [...releasedByPackage.values()].toSorted((left, right) => left.packageName < right.packageName ? -1 : left.packageName > right.packageName ? 1 : 0);
501
+ const ownerEvidence = ownerRows.toSorted((left, right) => left.decisionId < right.decisionId ? -1 : left.decisionId > right.decisionId ? 1 : 0);
502
+ const archives = [...archiveByPackage.values()].toSorted((left, right) => left.packageName < right.packageName ? -1 : left.packageName > right.packageName ? 1 : 0);
503
+ const candidates = [...candidateByPackage.values()].toSorted((left, right) => left.packageName < right.packageName ? -1 : left.packageName > right.packageName ? 1 : 0);
504
+ const metadataRoots = validateGrowthMetadataRoots(row["metadataRoots"], { binding, base: trustedBase, requestDigest,
505
+ releaseScope: new Set([...releasedByPackage.keys(), ...archiveByPackage.keys(), ...candidateByPackage.keys()]) }, fingerprint);
506
+ exact(released.map((entry) => ({ packageName: entry.packageName, kind: entry.evidence.kind })), request.contextSelectors.released.map((entry) => ({ packageName: entry.packageName, kind: entry.kind })), "growth-authority-release-selector-mismatch");
507
+ const requestedDecisions = new Set(request.decisionDigests);
508
+ for (const owner of ownerEvidence) {
509
+ if (owner.sourceBindingDigest !== requestDigest || !requestedDecisions.has(owner.decisionDigest)) {
510
+ invalid("growth-authority-owner-source-mismatch");
511
+ }
512
+ }
513
+ const packageNames = released.map((entry) => entry.packageName);
514
+ exact(candidates.map((entry) => entry.packageName), packageNames, "growth-authority-candidate-scope-mismatch");
515
+ const releasedPackageNames = released.filter((entry) => entry.evidence.kind === "released").map((entry) => entry.packageName);
516
+ exact(archives.map((entry) => entry.packageName), releasedPackageNames, "growth-authority-archive-scope-mismatch");
517
+ for (const releasedRow of released) {
518
+ const candidate = candidateByPackage.get(releasedRow.packageName);
519
+ const candidateInvocation = normalizeGrowthInvocation({
520
+ repository: candidate.observation.repository,
521
+ sourceCommit: candidate.observation.sourceCommit,
522
+ sourceTree: candidate.observation.sourceTree,
523
+ topologyDigest: candidate.observation.topologyDigest,
524
+ lockDigest: candidate.observation.lockDigest,
525
+ toolchainDigest: candidate.observation.toolchainDigest,
526
+ artifactDigests: candidate.observation.artifactDigests,
527
+ tool: candidate.observation.tool
528
+ });
529
+ exact(candidateInvocation, binding.invocation, "growth-authority-candidate-invocation-mismatch");
530
+ exact(candidate.source, binding.target.evaluation, "growth-authority-candidate-source-mismatch");
531
+ if (candidate.packageVersion !== releasedRow.releaseEvidence.packageVersion) {
532
+ invalid("growth-authority-candidate-version-mismatch");
533
+ }
534
+ if (releasedRow.evidence.kind === "initial-unreleased") {
535
+ continue;
536
+ }
537
+ const archive = archiveByPackage.get(releasedRow.packageName);
538
+ if (releasedRow.evidence.typed.packageVersion !== releasedRow.evidence.artifact.packageVersion
539
+ || archive.packageVersion !== releasedRow.evidence.artifact.packageVersion) {
540
+ invalid("growth-authority-archive-version-mismatch");
541
+ }
542
+ if (releasedRow.observation === undefined) {
543
+ invalid("growth-authority-release-observation-missing");
544
+ }
545
+ exact(archive.observation, releasedRow.observation, "growth-authority-archive-observation-mismatch");
546
+ }
547
+ const evidenceManifestDigest = hashGrowthPayload({ domain: "foundation:sdk-growth:evidence-manifest:2", payload: {
548
+ archives: archives.map((entry) => ({ packageName: entry.packageName, custodyEvidenceDigest: entry.custodyEvidenceDigest })),
549
+ candidates: candidates.map((entry) => ({ packageName: entry.packageName, custodyEvidenceDigest: entry.custodyEvidenceDigest })),
550
+ metadataRoots: metadataRoots.map((entry) => ({ packageName: entry.evidence.packageName, evidenceDigest: entry.evidenceDigest })),
551
+ retainedHistory: historicalCustody
552
+ } }, fingerprint);
553
+ if (evidenceManifestDigest !== binding.evidenceManifestDigest) {
554
+ invalid("growth-authority-evidence-manifest-mismatch");
555
+ }
556
+ return { schemaVersion: growthAuthoritySchemaVersion, kind: "grant", grantId: text(row["grantId"]), requestDigest,
557
+ admissionReceipt: validateAdmissionReceipt(row["admissionReceipt"], request, binding, fingerprint, { inspection, now }), binding,
558
+ workflowRef: text(row["workflowRef"]), runRef: text(row["runRef"]), issuedAt, expiresAt, trustedBase, trustedBaseReference,
559
+ retainedHistory: { targetSource, targetSurfaceDigest: digest(history["targetSurfaceDigest"]), receiptDigest: digest(history["receiptDigest"]),
560
+ custodyEvidenceDigest: historicalCustody, custodyEvidence: historicalEvidence }, released, ownerEvidence, archives, candidates, metadataRoots,
561
+ requiredCoverageDigest: digest(row["requiredCoverageDigest"]), requiredPhases: growthAuthorityRequiredPhases };
562
+ }
563
+ function validatePromotion(value) {
564
+ const row = object(value, member(value, "kind") === "none" ? ["kind"] : ["kind", "planDigest"]);
565
+ if (row["kind"] === "none") {
566
+ return { kind: "none" };
567
+ }
568
+ if (row["kind"] === "plan") {
569
+ return { kind: "plan", planDigest: digest(row["planDigest"]) };
570
+ }
571
+ return invalid("growth-authority-promotion-invalid");
572
+ }
573
+ export function validateGrowthAuthorityReceipt(value, completion, operation, fingerprint) {
574
+ const row = object(value, ["schemaVersion", "kind", "receiptId", "grantId", "grantDigest", "requestDigest", "completionDigest", "binding", "reportDigest",
575
+ "coverageDigest", "phasesDigest", "verdict", "releaseEligible", "qualification", "operation", "promotion", "custodyRef", "issuedAt"]);
576
+ if (row["schemaVersion"] !== growthAuthoritySchemaVersion || row["kind"] !== "receipt" || row["operation"] !== operation) {
577
+ invalid("growth-authority-receipt-invalid");
578
+ }
579
+ const binding = validateGrowthAuthorityBinding(row["binding"]), promotion = validatePromotion(row["promotion"]);
580
+ exact(binding, completion.binding, "growth-authority-receipt-binding-mismatch");
581
+ if ((operation === "check") !== (promotion.kind === "none")) {
582
+ invalid("growth-authority-promotion-invalid");
583
+ }
584
+ const verdict = row["verdict"], releaseEligible = row["releaseEligible"], qualification = row["qualification"];
585
+ if ((verdict !== "admitted" && verdict !== "rejected" && verdict !== "incomplete") || typeof releaseEligible !== "boolean"
586
+ || (qualification !== "qualified" && qualification !== "not-qualified")) {
587
+ invalid("growth-authority-receipt-invalid");
588
+ }
589
+ const receipt = { schemaVersion: growthAuthoritySchemaVersion, kind: "receipt", receiptId: text(row["receiptId"]),
590
+ grantId: text(row["grantId"]), grantDigest: digest(row["grantDigest"]), requestDigest: digest(row["requestDigest"]),
591
+ completionDigest: digest(row["completionDigest"]), binding,
592
+ reportDigest: digest(row["reportDigest"]), coverageDigest: digest(row["coverageDigest"]), phasesDigest: digest(row["phasesDigest"]),
593
+ verdict, releaseEligible, qualification, operation, promotion,
594
+ custodyRef: text(row["custodyRef"]), issuedAt: date(row["issuedAt"]) };
595
+ exact({ grantId: receipt.grantId, grantDigest: receipt.grantDigest, requestDigest: receipt.requestDigest,
596
+ binding: receipt.binding, reportDigest: receipt.reportDigest, coverageDigest: receipt.coverageDigest,
597
+ phasesDigest: receipt.phasesDigest, verdict: receipt.verdict, releaseEligible: receipt.releaseEligible,
598
+ promotion: receipt.promotion }, { grantId: completion.grantId, grantDigest: completion.grantDigest, requestDigest: completion.requestDigest,
599
+ binding: completion.binding, reportDigest: completion.reportDigest, coverageDigest: completion.coverageDigest,
600
+ phasesDigest: completion.phasesDigest, verdict: completion.verdict, releaseEligible: completion.releaseEligible,
601
+ promotion: completion.promotion }, "growth-authority-receipt-mismatch");
602
+ if (receipt.completionDigest !== growthAuthorityCompletionDigest(completion, fingerprint)) {
603
+ invalid("growth-authority-completion-mismatch");
604
+ }
605
+ if ((receipt.qualification === "qualified") !== (receipt.verdict === "admitted" && receipt.releaseEligible)) {
606
+ invalid("growth-authority-qualification-mismatch");
607
+ }
608
+ return receipt;
609
+ }
610
+ //# sourceMappingURL=validate-growth-authority.js.map