@topogram/cli 0.3.64 → 0.3.65

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 (245) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/agent-ops/query-builders/auth.js +375 -0
  5. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  6. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  7. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  8. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  9. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  10. package/src/agent-ops/query-builders/change-risk.js +25 -0
  11. package/src/agent-ops/query-builders/common.js +149 -0
  12. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  13. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  14. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  15. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  16. package/src/agent-ops/query-builders/work-packets.js +417 -0
  17. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  18. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  19. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  20. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  21. package/src/agent-ops/query-builders.d.ts +26 -26
  22. package/src/agent-ops/query-builders.js +42 -5021
  23. package/src/catalog/constants.js +10 -0
  24. package/src/catalog/copy.js +60 -0
  25. package/src/catalog/diagnostics.js +15 -0
  26. package/src/catalog/entries.js +42 -0
  27. package/src/catalog/files.js +67 -0
  28. package/src/catalog/provenance.js +122 -0
  29. package/src/catalog/source.js +150 -0
  30. package/src/catalog/validation.js +252 -0
  31. package/src/catalog.d.ts +2 -0
  32. package/src/catalog.js +18 -746
  33. package/src/cli/commands/catalog/check.js +31 -0
  34. package/src/cli/commands/catalog/copy.js +59 -0
  35. package/src/cli/commands/catalog/doctor.js +248 -0
  36. package/src/cli/commands/catalog/help.js +21 -0
  37. package/src/cli/commands/catalog/list.js +52 -0
  38. package/src/cli/commands/catalog/runner.js +92 -0
  39. package/src/cli/commands/catalog/shared.js +17 -0
  40. package/src/cli/commands/catalog/show.js +134 -0
  41. package/src/cli/commands/catalog.js +30 -615
  42. package/src/cli/commands/generator-policy/package-info.js +162 -0
  43. package/src/cli/commands/generator-policy/payloads.js +372 -0
  44. package/src/cli/commands/generator-policy/printers.js +159 -0
  45. package/src/cli/commands/generator-policy/runner.js +81 -0
  46. package/src/cli/commands/generator-policy/shared.js +39 -0
  47. package/src/cli/commands/generator-policy.js +15 -783
  48. package/src/cli/commands/import/adopt.js +170 -0
  49. package/src/cli/commands/import/check.js +91 -0
  50. package/src/cli/commands/import/diff.js +84 -0
  51. package/src/cli/commands/import/help.js +47 -0
  52. package/src/cli/commands/import/paths.js +277 -0
  53. package/src/cli/commands/import/plan.js +284 -0
  54. package/src/cli/commands/import/refresh.js +470 -0
  55. package/src/cli/commands/import/status-history.js +196 -0
  56. package/src/cli/commands/import/workspace.js +230 -0
  57. package/src/cli/commands/import.js +33 -1732
  58. package/src/cli/commands/package/constants.js +17 -0
  59. package/src/cli/commands/package/doctor.js +240 -0
  60. package/src/cli/commands/package/help.js +27 -0
  61. package/src/cli/commands/package/lockfile.js +135 -0
  62. package/src/cli/commands/package/npm.js +97 -0
  63. package/src/cli/commands/package/reporting.js +35 -0
  64. package/src/cli/commands/package/runner.js +33 -0
  65. package/src/cli/commands/package/shared.js +9 -0
  66. package/src/cli/commands/package/update-cli.js +252 -0
  67. package/src/cli/commands/package/versions.js +35 -0
  68. package/src/cli/commands/package.js +29 -813
  69. package/src/cli/commands/query/change-plan.js +68 -0
  70. package/src/cli/commands/query/definitions.js +202 -0
  71. package/src/cli/commands/query/import-adopt.js +121 -0
  72. package/src/cli/commands/query/runner/artifacts.js +102 -0
  73. package/src/cli/commands/query/runner/boundaries.js +211 -0
  74. package/src/cli/commands/query/runner/change.js +182 -0
  75. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  76. package/src/cli/commands/query/runner/index.js +31 -0
  77. package/src/cli/commands/query/runner/output.js +12 -0
  78. package/src/cli/commands/query/runner/workflow.js +241 -0
  79. package/src/cli/commands/query/runner.js +3 -0
  80. package/src/cli/commands/query/workflow-context.js +5 -0
  81. package/src/cli/commands/query/workspace.js +274 -0
  82. package/src/cli/commands/query.js +9 -1300
  83. package/src/cli/commands/template/baseline.js +100 -0
  84. package/src/cli/commands/template/check.js +466 -0
  85. package/src/cli/commands/template/constants.js +8 -0
  86. package/src/cli/commands/template/diagnostics.js +26 -0
  87. package/src/cli/commands/template/help.js +28 -0
  88. package/src/cli/commands/template/lifecycle.js +404 -0
  89. package/src/cli/commands/template/list-show.js +287 -0
  90. package/src/cli/commands/template/policy.js +422 -0
  91. package/src/cli/commands/template/shared.js +127 -0
  92. package/src/cli/commands/template/updates.js +352 -0
  93. package/src/cli/commands/template.js +41 -2143
  94. package/src/generator/api/contracts.js +497 -0
  95. package/src/generator/api/metadata.js +221 -0
  96. package/src/generator/api/openapi.js +559 -0
  97. package/src/generator/api/schema.js +124 -0
  98. package/src/generator/api/types.d.ts +98 -0
  99. package/src/generator/api.js +3 -1195
  100. package/src/generator/context/shared/domain-sdlc.js +282 -0
  101. package/src/generator/context/shared/maintained-boundary.js +665 -0
  102. package/src/generator/context/shared/metrics.js +85 -0
  103. package/src/generator/context/shared/primitives.js +64 -0
  104. package/src/generator/context/shared/relationships.js +453 -0
  105. package/src/generator/context/shared/summaries.js +263 -0
  106. package/src/generator/context/shared/types.d.ts +207 -0
  107. package/src/generator/context/shared.d.ts +42 -0
  108. package/src/generator/context/shared.js +80 -1390
  109. package/src/generator/context/slice/core.js +397 -0
  110. package/src/generator/context/slice/sdlc.js +417 -0
  111. package/src/generator/context/slice/ui-packets.js +183 -0
  112. package/src/generator/context/slice.js +2 -859
  113. package/src/generator/registry/index.js +507 -0
  114. package/src/generator/registry.js +18 -504
  115. package/src/generator/runtime/environment/index.js +666 -0
  116. package/src/generator/runtime/environment.js +4 -666
  117. package/src/generator/runtime/runtime-check/index.js +554 -0
  118. package/src/generator/runtime/runtime-check.js +4 -554
  119. package/src/generator/runtime/shared/index.js +572 -0
  120. package/src/generator/runtime/shared.js +19 -570
  121. package/src/generator/shared.d.ts +2 -0
  122. package/src/generator/surfaces/shared.d.ts +3 -0
  123. package/src/generator/widget-conformance/behavior-report.js +258 -0
  124. package/src/generator/widget-conformance/checks.js +371 -0
  125. package/src/generator/widget-conformance/projection-context.js +200 -0
  126. package/src/generator/widget-conformance/report.js +166 -0
  127. package/src/generator/widget-conformance/types.d.ts +121 -0
  128. package/src/generator/widget-conformance.js +3 -824
  129. package/src/import/core/context.d.ts +3 -0
  130. package/src/import/core/contracts.d.ts +1 -0
  131. package/src/import/core/registry.d.ts +4 -0
  132. package/src/import/core/runner/candidates.js +217 -0
  133. package/src/import/core/runner/options.js +22 -0
  134. package/src/import/core/runner/reports.js +50 -0
  135. package/src/import/core/runner/run.js +79 -0
  136. package/src/import/core/runner/tracks.js +150 -0
  137. package/src/import/core/runner/ui-drafts.js +337 -0
  138. package/src/import/core/runner.js +3 -698
  139. package/src/import/core/shared/api-routes.js +221 -0
  140. package/src/import/core/shared/candidates.js +97 -0
  141. package/src/import/core/shared/files.js +177 -0
  142. package/src/import/core/shared/next-app.js +389 -0
  143. package/src/import/core/shared/types.d.ts +51 -0
  144. package/src/import/core/shared/ui-routes.js +230 -0
  145. package/src/import/core/shared.js +60 -861
  146. package/src/new-project/constants.js +128 -0
  147. package/src/new-project/create.js +83 -0
  148. package/src/new-project/json.js +28 -0
  149. package/src/new-project/metadata.js +96 -0
  150. package/src/new-project/package-spec.js +161 -0
  151. package/src/new-project/project-files.js +348 -0
  152. package/src/new-project/template-policy.js +269 -0
  153. package/src/new-project/template-resolution.js +368 -0
  154. package/src/new-project/template-snapshots.js +430 -0
  155. package/src/new-project/template-updates.js +512 -0
  156. package/src/new-project/types.d.ts +83 -0
  157. package/src/new-project.js +6 -2277
  158. package/src/parser.d.ts +87 -1
  159. package/src/parser.js +118 -0
  160. package/src/policy/review-boundaries.d.ts +15 -0
  161. package/src/project-config/index.js +564 -0
  162. package/src/project-config.js +19 -561
  163. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  164. package/src/resolver/enrich/bug.js +2 -0
  165. package/src/resolver/enrich/pitch.js +2 -0
  166. package/src/resolver/enrich/requirement.js +2 -0
  167. package/src/resolver/enrich/task.js +2 -0
  168. package/src/resolver/index.js +19 -2089
  169. package/src/resolver/normalize.js +384 -1
  170. package/src/resolver/plans.js +168 -0
  171. package/src/resolver/projections-api.js +494 -0
  172. package/src/resolver/projections-db.js +133 -0
  173. package/src/resolver/projections-ui.js +317 -0
  174. package/src/resolver/shapes.js +251 -0
  175. package/src/resolver/shared.js +278 -0
  176. package/src/resolver/widgets.js +132 -0
  177. package/src/template-trust/constants.js +62 -0
  178. package/src/template-trust/content.js +258 -0
  179. package/src/template-trust/diff.js +92 -0
  180. package/src/template-trust/policy.js +61 -0
  181. package/src/template-trust/record.js +90 -0
  182. package/src/template-trust/status.js +182 -0
  183. package/src/template-trust.js +24 -687
  184. package/src/text-helpers.d.ts +1 -0
  185. package/src/topogram-types.d.ts +69 -0
  186. package/src/validator/common.js +488 -0
  187. package/src/validator/data-model.js +237 -0
  188. package/src/validator/docs.js +167 -0
  189. package/src/validator/expressions.js +146 -1
  190. package/src/validator/index.d.ts +23 -0
  191. package/src/validator/index.js +32 -3585
  192. package/src/validator/kinds.d.ts +41 -0
  193. package/src/validator/kinds.js +2 -0
  194. package/src/validator/model-helpers.js +46 -0
  195. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  196. package/src/validator/per-kind/bug.js +6 -0
  197. package/src/validator/per-kind/domain.js +15 -2
  198. package/src/validator/per-kind/pitch.js +7 -0
  199. package/src/validator/per-kind/requirement.js +5 -0
  200. package/src/validator/per-kind/task.js +7 -0
  201. package/src/validator/per-kind/widget.js +14 -0
  202. package/src/validator/projections/api-http-async.js +410 -0
  203. package/src/validator/projections/api-http-authz.js +88 -0
  204. package/src/validator/projections/api-http-core.js +205 -0
  205. package/src/validator/projections/api-http-policies.js +339 -0
  206. package/src/validator/projections/api-http-responses.js +233 -0
  207. package/src/validator/projections/api-http.js +44 -0
  208. package/src/validator/projections/db.js +353 -0
  209. package/src/validator/projections/generator-defaults.js +45 -0
  210. package/src/validator/projections/helpers.js +87 -0
  211. package/src/validator/projections/ui-helpers.js +214 -0
  212. package/src/validator/projections/ui-navigation.js +344 -0
  213. package/src/validator/projections/ui-structure.js +364 -0
  214. package/src/validator/projections/ui-widgets.js +493 -0
  215. package/src/validator/projections/ui.js +46 -0
  216. package/src/validator/registry.js +48 -1
  217. package/src/validator/utils.d.ts +20 -0
  218. package/src/validator/utils.js +115 -12
  219. package/src/widget-behavior.d.ts +1 -0
  220. package/src/workflows/import-app/api/collect.js +221 -0
  221. package/src/workflows/import-app/api/openapi.js +257 -0
  222. package/src/workflows/import-app/api/routes.js +327 -0
  223. package/src/workflows/import-app/api/sources.js +22 -0
  224. package/src/workflows/import-app/api.js +2 -797
  225. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  226. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  227. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  228. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  229. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  230. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  231. package/src/workflows/reconcile/adoption-plan.js +30 -740
  232. package/src/workflows/reconcile/auth/closures.js +115 -0
  233. package/src/workflows/reconcile/auth/formatters.js +142 -0
  234. package/src/workflows/reconcile/auth/inference.js +330 -0
  235. package/src/workflows/reconcile/auth/roles.js +122 -0
  236. package/src/workflows/reconcile/auth.js +35 -690
  237. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  238. package/src/workflows/reconcile/bundle-core.js +12 -598
  239. package/src/workflows/reconcile/canonical-surface.js +1 -1
  240. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  241. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  242. package/src/workflows/reconcile/impacts/patches.js +252 -0
  243. package/src/workflows/reconcile/impacts/reports.js +80 -0
  244. package/src/workflows/reconcile/impacts.js +14 -623
  245. package/src/workspace-docs.d.ts +29 -0
@@ -0,0 +1,665 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { parseDocFile } from "../../../workspace-docs.js";
5
+ import {
6
+ ownershipBoundaryForMaintainedSurface,
7
+ reviewBoundaryForMaintainedClassification
8
+ } from "../../../policy/review-boundaries.js";
9
+ import { seamIdHint, stableSortedStrings, titleCaseWords } from "./primitives.js";
10
+ import { buildMaintainedWriteScope, recommendedVerificationTargets } from "./metrics.js";
11
+
12
+ const bundledRepoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), "..", "..", "..", "..");
13
+
14
+ /**
15
+ * @param {import("./types.d.ts").ContextGraph} graph
16
+ * @returns {any}
17
+ */
18
+ export function repoRootFromGraph(graph) {
19
+ let current = path.resolve(graph.root);
20
+ while (true) {
21
+ if (fs.existsSync(path.join(current, "examples", "maintained", "proof-app")) && fs.existsSync(path.join(current, "engine"))) {
22
+ return current;
23
+ }
24
+ const parent = path.dirname(current);
25
+ if (parent === current) {
26
+ if (
27
+ fs.existsSync(path.join(bundledRepoRoot, "examples", "maintained", "proof-app")) &&
28
+ fs.existsSync(path.join(bundledRepoRoot, "engine"))
29
+ ) {
30
+ return bundledRepoRoot;
31
+ }
32
+ return path.resolve(graph.root, "..", "..");
33
+ }
34
+ current = parent;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @param {import("./types.d.ts").ContextGraph} graph
40
+ * @param {string} targetPath
41
+ * @returns {any}
42
+ */
43
+ export function relativePathFromGraph(graph, targetPath) {
44
+ return path.relative(repoRootFromGraph(graph), targetPath);
45
+ }
46
+
47
+ /**
48
+ * @param {import("./types.d.ts").ContextGraph} graph
49
+ * @returns {any}
50
+ */
51
+ function workspaceRootFromGraph(graph) {
52
+ const root = path.resolve(graph.root);
53
+ return path.basename(root) === "topogram" ? path.dirname(root) : root;
54
+ }
55
+
56
+ /**
57
+ * @param {string} workspaceRoot
58
+ * @returns {any}
59
+ */
60
+ function collectMaintainedProofDocPaths(workspaceRoot) {
61
+ const candidateDirs = [
62
+ path.join(workspaceRoot, "proof"),
63
+ path.join(workspaceRoot, "docs", "proof")
64
+ ];
65
+ const proofFiles = [];
66
+
67
+ for (const dirPath of candidateDirs) {
68
+ if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
69
+ continue;
70
+ }
71
+ for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
72
+ if (entry.isFile() && /^maintained-.*\.md$/.test(entry.name)) {
73
+ proofFiles.push(path.join(dirPath, entry.name));
74
+ }
75
+ }
76
+ }
77
+
78
+ return stableSortedStrings(proofFiles);
79
+ }
80
+
81
+ /**
82
+ * @param {string} workspaceRoot
83
+ * @returns {any}
84
+ */
85
+ function readLocalMaintainedProofMetadataFromWorkspace(workspaceRoot) {
86
+ return collectMaintainedProofDocPaths(workspaceRoot)
87
+ .map(/** @param {any} filePath */ (filePath) => parseDocFile(filePath, workspaceRoot))
88
+ .filter(/** @param {import("./types.d.ts").ContextDoc} doc */ (doc) => !doc.parseError)
89
+ .map(/** @param {import("./types.d.ts").ContextDoc} doc */ (doc) => {
90
+ const classification = doc.metadata.classification || null;
91
+ const maintainedFiles = stableSortedStrings(doc.metadata.maintained_files || []);
92
+ const emittedDependencies = stableSortedStrings(doc.metadata.emitted_dependencies || []);
93
+ const humanOwnedSeams = stableSortedStrings(doc.metadata.human_owned_seams || []);
94
+
95
+ if (!classification || maintainedFiles.length === 0 || emittedDependencies.length === 0 || humanOwnedSeams.length === 0) {
96
+ return null;
97
+ }
98
+
99
+ return {
100
+ classification,
101
+ maintainedFiles,
102
+ emittedDependencies,
103
+ humanOwnedSeams,
104
+ seamFamilyId: doc.metadata.seam_family_id || null,
105
+ seamFamilyLabel: doc.metadata.seam_family_label || null,
106
+ exists: true,
107
+ absolutePath: doc.file,
108
+ relativePath: doc.relativePath,
109
+ reviewBoundary: reviewBoundaryForMaintainedClassification(classification),
110
+ ownership_boundary: ownershipBoundaryForMaintainedSurface()
111
+ };
112
+ })
113
+ .filter(Boolean);
114
+ }
115
+
116
+ /**
117
+ * @param {import("./types.d.ts").ContextGraph} graph
118
+ * @returns {any}
119
+ */
120
+ export function readLocalMaintainedProofMetadata(graph) {
121
+ return readLocalMaintainedProofMetadataFromWorkspace(workspaceRootFromGraph(graph));
122
+ }
123
+
124
+ /**
125
+ * @param {import("./types.d.ts").MaintainedBoundaryOptions} arg1
126
+ * @returns {any}
127
+ */
128
+ export function buildMaintainedBoundaryArtifact(arg1 = {}) {
129
+ const {
130
+ proofStories = [],
131
+ verificationTargets = null,
132
+ graph = null
133
+ } = arg1;
134
+ if (!proofStories.length) {
135
+ return null;
136
+ }
137
+
138
+ const seams = buildMaintainedSeams(proofStories);
139
+ const outputs = buildMaintainedOutputs({
140
+ seams,
141
+ proofStories,
142
+ ownershipBoundary: ownershipBoundaryForMaintainedSurface(),
143
+ verificationTargets,
144
+ graph
145
+ });
146
+ const maintainedFiles = stableSortedStrings(proofStories.flatMap(/** @param {any} item */ (item) => item.maintainedFiles || []));
147
+ const emittedDependencies = stableSortedStrings(proofStories.flatMap(/** @param {any} item */ (item) => item.emittedDependencies || []));
148
+ const humanOwnedSeams = stableSortedStrings(proofStories.flatMap(/** @param {any} item */ (item) => item.humanOwnedSeams || []));
149
+
150
+ return {
151
+ type: "maintained_boundary",
152
+ version: 2,
153
+ summary: {
154
+ focus: "Maintained-app files, emitted constraints, and explicit review boundaries",
155
+ maintained_file_count: maintainedFiles.length,
156
+ accepted_change_count: proofStories.filter(/** @param {any} item */ (item) => item.classification === "accepted_change").length,
157
+ guarded_change_count: proofStories.filter(/** @param {any} item */ (item) => item.classification === "guarded_manual_decision").length,
158
+ no_go_count: proofStories.filter(/** @param {any} item */ (item) => item.classification === "no_go").length
159
+ },
160
+ maintained_files_in_scope: maintainedFiles,
161
+ emitted_artifact_dependencies: emittedDependencies,
162
+ human_owned_seams: humanOwnedSeams,
163
+ outputs,
164
+ seams,
165
+ proof_stories: proofStories.map(/** @param {any} item */ (item) => ({
166
+ classification: item.classification,
167
+ relativePath: item.relativePath,
168
+ maintained_files: item.maintainedFiles || [],
169
+ emitted_dependencies: item.emittedDependencies || [],
170
+ human_owned_seams: item.humanOwnedSeams || [],
171
+ seam_family_id: item.seamFamilyId || null,
172
+ seam_family_label: item.seamFamilyLabel || null,
173
+ review_boundary: item.reviewBoundary,
174
+ ownership_boundary: item.ownership_boundary
175
+ })),
176
+ ownership_boundary: ownershipBoundaryForMaintainedSurface()
177
+ };
178
+ }
179
+
180
+ /**
181
+ * @param {string} workspaceRoot
182
+ * @param {import("./types.d.ts").ContextGraph | null} graph
183
+ * @returns {any}
184
+ */
185
+ export function buildLocalMaintainedBoundaryArtifact(workspaceRoot, graph = null) {
186
+ const proofStories = readLocalMaintainedProofMetadataFromWorkspace(path.resolve(workspaceRoot));
187
+ if (!proofStories.length) {
188
+ return null;
189
+ }
190
+
191
+ const emittedDependencies = stableSortedStrings(proofStories.flatMap(/** @param {any} item */ (item) => item.emittedDependencies || []));
192
+ const verificationTargets = graph
193
+ ? recommendedVerificationTargets(graph, emittedDependencies, {
194
+ includeMaintainedApp: true,
195
+ rationale: "Local maintained proof stories should point agents at emitted dependency checks plus any maintained proof gates."
196
+ })
197
+ : null;
198
+
199
+ return buildMaintainedBoundaryArtifact({
200
+ proofStories,
201
+ verificationTargets,
202
+ graph
203
+ });
204
+ }
205
+
206
+ /**
207
+ * @param {import("./types.d.ts").ContextGraph} graph
208
+ * @returns {any}
209
+ */
210
+ export function maintainedProofMetadata(graph) {
211
+ const repoRoot = repoRootFromGraph(graph);
212
+ const staticFiles = [
213
+ {
214
+ classification: "accepted_change",
215
+ path: "examples/maintained/proof-app/proof/issues-ownership-visibility-story.md",
216
+ maintainedFiles: ["examples/maintained/proof-app/src/issues.js"],
217
+ emittedDependencies: ["proj_web", "proj_api", "journey_issue_resolution_and_closure"],
218
+ humanOwnedSeams: ["maintained presenter structure", "detail/list rendering treatment"]
219
+ },
220
+ {
221
+ classification: "accepted_change",
222
+ path: "examples/maintained/proof-app/proof/issues-cross-surface-alignment-story.md",
223
+ maintainedFiles: ["examples/maintained/proof-app/src/issues.js"],
224
+ emittedDependencies: ["proj_web", "proj_api", "journey_issue_creation_and_assignment", "journey_issue_resolution_and_closure"],
225
+ humanOwnedSeams: [
226
+ "issues detail action state",
227
+ "issues list/card summary state",
228
+ "issues route and action metadata"
229
+ ],
230
+ seamFamilyId: "issues_cross_surface_alignment",
231
+ seamFamilyLabel: "issues cross-surface ownership alignment"
232
+ },
233
+ {
234
+ classification: "guarded_manual_decision",
235
+ path: "examples/maintained/proof-app/proof/content-approval-workflow-decision-story.md",
236
+ maintainedFiles: ["examples/maintained/proof-app/src/content-approval-change-guards.js"],
237
+ emittedDependencies: ["cap_request_article_revision", "journey_editorial_review_and_revision"],
238
+ humanOwnedSeams: ["new workflow affordance treatment", "action placement and copy"]
239
+ },
240
+ {
241
+ classification: "no_go",
242
+ path: "examples/maintained/proof-app/proof/issues-ownership-visibility-drift-story.md",
243
+ maintainedFiles: ["examples/maintained/proof-app/src/issues.js"],
244
+ emittedDependencies: ["proj_web", "journey_issue_resolution_and_closure"],
245
+ humanOwnedSeams: ["owner visibility semantics must not drift"]
246
+ },
247
+ {
248
+ classification: "no_go",
249
+ path: "examples/maintained/proof-app/proof/content-approval-unsupported-change-story.md",
250
+ maintainedFiles: ["examples/maintained/proof-app/src/content-approval.js", "examples/maintained/proof-app/src/content-approval-change-guards.js"],
251
+ emittedDependencies: ["proj_web", "proj_api", "proj_db"],
252
+ humanOwnedSeams: ["unsupported relation and workflow meaning changes"]
253
+ },
254
+ {
255
+ classification: "no_go",
256
+ path: "examples/maintained/proof-app/proof/todo-project-owner-unsupported-change-story.md",
257
+ maintainedFiles: ["examples/maintained/proof-app/src/todo-change-guards.js"],
258
+ emittedDependencies: ["entity_project", "proj_web", "proj_api"],
259
+ humanOwnedSeams: ["ownership retargeting remains manual"]
260
+ },
261
+ {
262
+ classification: "independent_review",
263
+ path: "examples/maintained/proof-app/proof/maintained-contract-review.md",
264
+ maintainedFiles: [
265
+ "examples/maintained/proof-app/src/issues.js",
266
+ "examples/maintained/proof-app/src/content-approval-change-guards.js",
267
+ "examples/maintained/proof-app/src/todo-change-guards.js"
268
+ ],
269
+ emittedDependencies: ["maintained-proof-package"],
270
+ humanOwnedSeams: ["human audit of emitted contracts vs maintained code"]
271
+ },
272
+ {
273
+ classification: "accepted_change",
274
+ path: "examples/generated/content-approval/implementation/proof/web-reference-seam-story.md",
275
+ maintainedFiles: ["examples/generated/content-approval/implementation/web/reference.js"],
276
+ emittedDependencies: ["proj_web", "journey_editorial_review_and_revision"],
277
+ humanOwnedSeams: ["example web reference composition"]
278
+ },
279
+ {
280
+ classification: "accepted_change",
281
+ path: "examples/generated/content-approval/implementation/proof/backend-reference-seam-story.md",
282
+ maintainedFiles: ["examples/generated/content-approval/implementation/backend/reference.js"],
283
+ emittedDependencies: ["proj_api", "proj_db"],
284
+ humanOwnedSeams: ["example backend reference integration"]
285
+ }
286
+ ];
287
+
288
+ const staticProofs = staticFiles
289
+ .map(/** @param {any} item */ (item) => {
290
+ const absolutePath = path.join(repoRoot, item.path);
291
+ return {
292
+ ...item,
293
+ exists: fs.existsSync(absolutePath),
294
+ absolutePath,
295
+ relativePath: item.path,
296
+ reviewBoundary: reviewBoundaryForMaintainedClassification(item.classification),
297
+ ownership_boundary: ownershipBoundaryForMaintainedSurface()
298
+ };
299
+ })
300
+ .filter(/** @param {any} item */ (item) => item.exists);
301
+
302
+ return [
303
+ ...staticProofs,
304
+ ...readLocalMaintainedProofMetadata(graph)
305
+ ];
306
+ }
307
+
308
+ /**
309
+ * @param {any} label
310
+ * @returns {any}
311
+ */
312
+ function maintainedSeamKind(label) {
313
+ const normalized = String(label || "").toLowerCase();
314
+ if (/audit|contract|review/.test(normalized)) {
315
+ return "verification_harness";
316
+ }
317
+ if (/workflow|affordance|action|copy/.test(normalized)) {
318
+ return "workflow_affordance";
319
+ }
320
+ if (/visibility|ownership|relation|policy/.test(normalized)) {
321
+ return "policy_interpretation";
322
+ }
323
+ if (/route|navigation/.test(normalized)) {
324
+ return "route_glue";
325
+ }
326
+ return "ui_presenter";
327
+ }
328
+
329
+ /**
330
+ * @param {any} reviewBoundary
331
+ * @returns {any}
332
+ */
333
+ function maintainedSeamStatus(reviewBoundary) {
334
+ const automationClass = reviewBoundary?.automation_class || "review_required";
335
+ return automationClass === "safe" ? "aligned" : automationClass;
336
+ }
337
+
338
+ /**
339
+ * @param {any} classification
340
+ * @returns {any}
341
+ */
342
+ function maintainedSeamOwnershipClass(classification) {
343
+ if (classification === "accepted_change") {
344
+ return "contract_bound";
345
+ }
346
+ if (classification === "guarded_manual_decision" || classification === "independent_review") {
347
+ return "advisory_only";
348
+ }
349
+ if (classification === "no_go") {
350
+ return "out_of_bounds";
351
+ }
352
+ return "contract_bound";
353
+ }
354
+
355
+ /**
356
+ * @param {any} classification
357
+ * @returns {any}
358
+ */
359
+ function maintainedSeamAllowedChangeClasses(classification) {
360
+ if (classification === "accepted_change") {
361
+ return ["safe", "review_required"];
362
+ }
363
+ if (classification === "guarded_manual_decision") {
364
+ return ["review_required", "manual_decision"];
365
+ }
366
+ if (classification === "independent_review") {
367
+ return ["review_required"];
368
+ }
369
+ if (classification === "no_go") {
370
+ return ["no_go"];
371
+ }
372
+ return ["review_required"];
373
+ }
374
+
375
+ /**
376
+ * @param {any} emittedDependencies
377
+ * @returns {any}
378
+ */
379
+ function maintainedSeamDriftSignals(emittedDependencies = []) {
380
+ const signals = new Set();
381
+ for (const dependency of emittedDependencies || []) {
382
+ if (dependency === "maintained-proof-package") {
383
+ signals.add("verification_expectation_changed");
384
+ continue;
385
+ }
386
+ if (dependency.startsWith("journey_") || dependency.startsWith("workflow_")) {
387
+ signals.add("workflow_state_changed");
388
+ continue;
389
+ }
390
+ if (dependency.startsWith("proj_ui") || dependency === "proj_web") {
391
+ signals.add("emitted_contract_changed");
392
+ signals.add("route_or_navigation_changed");
393
+ continue;
394
+ }
395
+ if (
396
+ dependency.startsWith("proj_") ||
397
+ dependency.startsWith("cap_") ||
398
+ dependency.startsWith("entity_") ||
399
+ dependency.startsWith("shape_")
400
+ ) {
401
+ signals.add("emitted_contract_changed");
402
+ }
403
+ }
404
+ return stableSortedStrings([...signals]);
405
+ }
406
+
407
+ /**
408
+ * @param {any} filePaths
409
+ * @returns {any}
410
+ */
411
+ function maintainedOutputDescriptor(filePaths = []) {
412
+ const files = stableSortedStrings(filePaths);
413
+ if (files.some(/** @param {any} file */ (file) => String(file).startsWith("examples/maintained/proof-app/"))) {
414
+ return {
415
+ output_id: "maintained_app",
416
+ label: "Maintained App",
417
+ kind: "maintained_runtime",
418
+ root_paths: ["examples/maintained/proof-app/**"]
419
+ };
420
+ }
421
+ const exampleImplementationMatch = files
422
+ .map(/** @param {any} file */ (file) => String(file).match(/^examples\/(?:(generated)\/)?([^/]+)\/implementation\/(web|backend|runtime)\//))
423
+ .find(Boolean);
424
+ if (exampleImplementationMatch) {
425
+ const [, category, slug, outputKind] = exampleImplementationMatch;
426
+ const outputId = `output_${seamIdHint(`examples_${slug}_${outputKind}`)}`;
427
+ const rootPrefix = category ? `examples/${category}/${slug}` : `examples/${slug}`;
428
+ const root = `${rootPrefix}/implementation/${outputKind}`;
429
+ return {
430
+ output_id: outputId,
431
+ label: `${titleCaseWords(slug)} ${titleCaseWords(outputKind)} Reference`,
432
+ kind: outputKind === "web" ? "web_app" : outputKind === "backend" ? "backend_adapter" : "maintained_runtime",
433
+ root_paths: [`${root}/**`]
434
+ };
435
+ }
436
+ if (files.some(/** @param {any} file */ (file) => String(file).startsWith("src/"))) {
437
+ return {
438
+ output_id: "output_src",
439
+ label: "Source",
440
+ kind: "backend_adapter",
441
+ root_paths: ["src/**"]
442
+ };
443
+ }
444
+
445
+ const firstFile = files[0] || "";
446
+ const segments = String(firstFile).split("/").filter(Boolean);
447
+ const root = segments.length >= 2 ? segments.slice(0, 2).join("/") : (segments[0] || "maintained");
448
+ const outputStem = seamIdHint(root);
449
+ return {
450
+ output_id: `output_${outputStem}`,
451
+ label: titleCaseWords(root.replaceAll("/", "_")),
452
+ kind: "maintained_runtime",
453
+ root_paths: [`${root}/**`]
454
+ };
455
+ }
456
+
457
+ /**
458
+ * @param {any} existing
459
+ * @param {any} next
460
+ * @returns {any}
461
+ */
462
+ function mergeMaintainedSeam(existing, next) {
463
+ if (!existing) {
464
+ return {
465
+ ...next,
466
+ seam_family_id: next.seam_family_id || null,
467
+ seam_family_label: next.seam_family_label || null,
468
+ maintained_modules: stableSortedStrings(next.maintained_modules || []),
469
+ emitted_dependencies: stableSortedStrings(next.emitted_dependencies || []),
470
+ human_owned_aspects: stableSortedStrings(next.human_owned_aspects || []),
471
+ allowed_change_classes: stableSortedStrings(next.allowed_change_classes || []),
472
+ drift_signals: stableSortedStrings(next.drift_signals || []),
473
+ proof_stories: [...(next.proof_stories || [])]
474
+ };
475
+ }
476
+
477
+ const statusPriority = ["aligned", "review_required", "manual_decision", "no_go"];
478
+ const ownershipPriority = ["engine_owned", "contract_bound", "advisory_only", "out_of_bounds"];
479
+
480
+ const currentStatus = statusPriority.indexOf(existing.status);
481
+ const nextStatus = statusPriority.indexOf(next.status);
482
+ const currentOwnership = ownershipPriority.indexOf(existing.ownership_class);
483
+ const nextOwnership = ownershipPriority.indexOf(next.ownership_class);
484
+
485
+ return {
486
+ ...existing,
487
+ kind: existing.kind || next.kind,
488
+ seam_family_id: existing.seam_family_id || next.seam_family_id || null,
489
+ seam_family_label: existing.seam_family_label || next.seam_family_label || null,
490
+ status: nextStatus > currentStatus ? next.status : existing.status,
491
+ ownership_class: nextOwnership > currentOwnership ? next.ownership_class : existing.ownership_class,
492
+ maintained_modules: stableSortedStrings([...(existing.maintained_modules || []), ...(next.maintained_modules || [])]),
493
+ emitted_dependencies: stableSortedStrings([...(existing.emitted_dependencies || []), ...(next.emitted_dependencies || [])]),
494
+ human_owned_aspects: stableSortedStrings([...(existing.human_owned_aspects || []), ...(next.human_owned_aspects || [])]),
495
+ allowed_change_classes: stableSortedStrings([...(existing.allowed_change_classes || []), ...(next.allowed_change_classes || [])]),
496
+ drift_signals: stableSortedStrings([...(existing.drift_signals || []), ...(next.drift_signals || [])]),
497
+ proof_stories: stableSortedStrings([
498
+ ...(existing.proof_stories || []).map(/** @param {any} item */ (item) => JSON.stringify(item)),
499
+ ...(next.proof_stories || []).map(/** @param {any} item */ (item) => JSON.stringify(item))
500
+ ]).map(/** @param {any} item */ (item) => JSON.parse(item))
501
+ };
502
+ }
503
+
504
+ /**
505
+ * @param {import("./types.d.ts").MaintainedProofStory[]} proofStories
506
+ * @returns {any}
507
+ */
508
+ export function buildMaintainedSeams(proofStories = []) {
509
+ const seams = new Map();
510
+
511
+ for (const story of proofStories || []) {
512
+ for (const seamLabel of story.humanOwnedSeams || story.human_owned_seams || []) {
513
+ const output = maintainedOutputDescriptor(story.maintainedFiles || story.maintained_files || []);
514
+ const seam = {
515
+ seam_id: `seam_${seamIdHint(seamLabel)}`,
516
+ seam_family_id: story.seamFamilyId || story.seam_family_id || null,
517
+ seam_family_label: story.seamFamilyLabel || story.seam_family_label || null,
518
+ output_id: output.output_id,
519
+ label: seamLabel,
520
+ kind: maintainedSeamKind(seamLabel),
521
+ ownership_class: maintainedSeamOwnershipClass(story.classification),
522
+ status: maintainedSeamStatus(story.reviewBoundary || story.review_boundary),
523
+ maintained_modules: story.maintainedFiles || story.maintained_files || [],
524
+ emitted_dependencies: story.emittedDependencies || story.emitted_dependencies || [],
525
+ human_owned_aspects: [seamLabel],
526
+ allowed_change_classes: maintainedSeamAllowedChangeClasses(story.classification),
527
+ drift_signals: maintainedSeamDriftSignals(story.emittedDependencies || story.emitted_dependencies || []),
528
+ proof_stories: [
529
+ {
530
+ classification: story.classification || null,
531
+ relativePath: story.relativePath || story.relative_path || null,
532
+ review_boundary: story.reviewBoundary || story.review_boundary || null
533
+ }
534
+ ]
535
+ };
536
+ seams.set(seam.seam_id, mergeMaintainedSeam(seams.get(seam.seam_id), seam));
537
+ }
538
+ }
539
+
540
+ return [...seams.values()].sort(/** @param {any} a @param {any} b */ (a, b) => a.seam_id.localeCompare(b.seam_id));
541
+ }
542
+
543
+ /**
544
+ * @param {import("./types.d.ts").MaintainedBoundaryOptions} arg1
545
+ * @returns {any}
546
+ */
547
+ export function buildMaintainedOutputs(arg1 = {}) {
548
+ const {
549
+ seams = [],
550
+ proofStories = [],
551
+ ownershipBoundary = ownershipBoundaryForMaintainedSurface(),
552
+ verificationTargets = null,
553
+ graph = null
554
+ } = arg1;
555
+ const outputs = new Map();
556
+
557
+ for (const seam of seams || []) {
558
+ const descriptor = maintainedOutputDescriptor(seam.maintained_modules || []);
559
+ const outputId = seam.output_id || descriptor.output_id;
560
+ const existing = outputs.get(outputId) || /** @type {any} */ ({
561
+ output_id: outputId,
562
+ label: descriptor.label,
563
+ kind: descriptor.kind,
564
+ root_paths: descriptor.root_paths,
565
+ ownership_boundary: ownershipBoundary,
566
+ verification_targets: verificationTargets || null,
567
+ maintained_files_in_scope: [],
568
+ human_owned_seams: [],
569
+ seams: [],
570
+ proof_stories: []
571
+ });
572
+
573
+ existing.maintained_files_in_scope = stableSortedStrings([
574
+ ...existing.maintained_files_in_scope,
575
+ ...(seam.maintained_modules || [])
576
+ ]);
577
+ existing.human_owned_seams = stableSortedStrings([
578
+ ...existing.human_owned_seams,
579
+ seam.label
580
+ ]);
581
+ existing.seams.push({
582
+ ...seam,
583
+ output_id: outputId
584
+ });
585
+ outputs.set(outputId, existing);
586
+ }
587
+
588
+ for (const story of proofStories || []) {
589
+ const descriptor = maintainedOutputDescriptor(story.maintainedFiles || story.maintained_files || []);
590
+ const outputId = descriptor.output_id;
591
+ const existing = outputs.get(outputId) || /** @type {any} */ ({
592
+ output_id: outputId,
593
+ label: descriptor.label,
594
+ kind: descriptor.kind,
595
+ root_paths: descriptor.root_paths,
596
+ ownership_boundary: ownershipBoundary,
597
+ verification_targets: verificationTargets || null,
598
+ maintained_files_in_scope: [],
599
+ human_owned_seams: [],
600
+ seams: [],
601
+ proof_stories: []
602
+ });
603
+
604
+ existing.maintained_files_in_scope = stableSortedStrings([
605
+ ...existing.maintained_files_in_scope,
606
+ ...(story.maintainedFiles || story.maintained_files || [])
607
+ ]);
608
+ existing.human_owned_seams = stableSortedStrings([
609
+ ...existing.human_owned_seams,
610
+ ...(story.humanOwnedSeams || story.human_owned_seams || [])
611
+ ]);
612
+ existing.proof_stories.push(story);
613
+ outputs.set(outputId, existing);
614
+ }
615
+
616
+ const verificationTargetsForOutput = /** @param {import("./types.d.ts").MaintainedOutput} output @returns {any} */ (output) => {
617
+ if (!graph) {
618
+ return output.verification_targets || verificationTargets || null;
619
+ }
620
+
621
+ const emittedDependencies = stableSortedStrings([
622
+ ...output.seams.flatMap(/** @param {import("./types.d.ts").MaintainedSeam} seam */ (seam) => seam.emitted_dependencies || []),
623
+ ...output.proof_stories.flatMap(/** @param {any} story */ (story) => story.emittedDependencies || story.emitted_dependencies || [])
624
+ ]);
625
+ const verificationIds = stableSortedStrings(
626
+ emittedDependencies.filter(/** @param {any} id */ (id) => String(id).startsWith("ver_"))
627
+ );
628
+ const generatedDependencyTargets = emittedDependencies.filter(/** @param {any} id */ (id) => !String(id).startsWith("ver_"));
629
+ const targetIds = stableSortedStrings([...verificationIds, ...generatedDependencyTargets]);
630
+ const includeMaintainedApp = output.kind === "maintained_runtime" || output.kind === "web_app" || output.kind === "mobile_app";
631
+
632
+ const routedTargets = /** @type {any} */ (recommendedVerificationTargets(graph, targetIds, {
633
+ includeMaintainedApp,
634
+ rationale: `${output.label || output.output_id || "Maintained output"} should run the smallest verification set tied to its own emitted dependencies and maintained seams.`
635
+ }));
636
+
637
+ return {
638
+ ...routedTargets,
639
+ verification_ids: stableSortedStrings([
640
+ ...(routedTargets.verification_ids || []),
641
+ ...(verificationTargets?.verification_ids || []).filter(/** @param {any} id */ (id) => verificationIds.includes(id))
642
+ ]),
643
+ generated_checks: stableSortedStrings([
644
+ ...(routedTargets.generated_checks || []),
645
+ ...(verificationTargets?.generated_checks || []).filter(/** @param {any} check */ (check) => routedTargets.generated_checks?.includes(check))
646
+ ]),
647
+ maintained_app_checks: includeMaintainedApp
648
+ ? stableSortedStrings([
649
+ ...(routedTargets.maintained_app_checks || []),
650
+ ...(verificationTargets?.maintained_app_checks || [])
651
+ ])
652
+ : []
653
+ };
654
+ };
655
+
656
+ return [...outputs.values()]
657
+ .map(/** @param {import("./types.d.ts").MaintainedOutput} output */ (output) => ({
658
+ ...output,
659
+ verification_targets: verificationTargetsForOutput(output),
660
+ write_scope: graph ? buildMaintainedWriteScope(graph, output.maintained_files_in_scope) : null,
661
+ seams: [...output.seams].sort(/** @param {any} a @param {any} b */ (a, b) => String(a.seam_id || "").localeCompare(String(b.seam_id || ""))),
662
+ proof_stories: [...output.proof_stories]
663
+ }))
664
+ .sort(/** @param {any} a @param {any} b */ (a, b) => a.output_id.localeCompare(b.output_id));
665
+ }