@intentius/chant 0.91.0 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/dist/cli/commands/build.d.ts.map +1 -1
  2. package/dist/cli/commands/lint.d.ts.map +1 -1
  3. package/dist/cli/handlers/graph.d.ts.map +1 -1
  4. package/dist/cli/handlers/operator.d.ts +6 -0
  5. package/dist/cli/handlers/operator.d.ts.map +1 -1
  6. package/dist/cli/handlers/run.d.ts.map +1 -1
  7. package/dist/cli/main.d.ts.map +1 -1
  8. package/dist/cli/mcp/workspace-plugins.d.ts +6 -6
  9. package/dist/cli/mcp/workspace-tools.d.ts +2 -1
  10. package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
  11. package/dist/cli/plugins.d.ts.map +1 -1
  12. package/dist/cli/registry.d.ts +12 -2
  13. package/dist/cli/registry.d.ts.map +1 -1
  14. package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
  15. package/dist/config.d.ts +22 -0
  16. package/dist/config.d.ts.map +1 -1
  17. package/dist/lexicon-module.d.ts +22 -0
  18. package/dist/lexicon-module.d.ts.map +1 -1
  19. package/dist/lifecycle/converge-ledger.d.ts +19 -0
  20. package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
  21. package/dist/lifecycle/run-ledger.d.ts +2 -0
  22. package/dist/lifecycle/run-ledger.d.ts.map +1 -1
  23. package/dist/lifecycle/symptoms.d.ts +51 -0
  24. package/dist/lifecycle/symptoms.d.ts.map +1 -1
  25. package/dist/lint/rules/index.d.ts +4 -2
  26. package/dist/lint/rules/index.d.ts.map +1 -1
  27. package/dist/lint/rules/op/index.d.ts +14 -3
  28. package/dist/lint/rules/op/index.d.ts.map +1 -1
  29. package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -1
  30. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts +29 -0
  31. package/dist/lint/rules/op/sys010-key-over-plain-http.d.ts.map +1 -0
  32. package/dist/lint/rules/sys001-no-literal-key.d.ts +3 -0
  33. package/dist/lint/rules/sys001-no-literal-key.d.ts.map +1 -0
  34. package/dist/op/__fixtures__/decide-stub-backend.d.ts +53 -0
  35. package/dist/op/__fixtures__/decide-stub-backend.d.ts.map +1 -0
  36. package/dist/op/activities/activity-contracts.d.ts +201 -0
  37. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  38. package/dist/op/activities/apply.d.ts.map +1 -1
  39. package/dist/op/activities/change-coverage.d.ts +44 -0
  40. package/dist/op/activities/change-coverage.d.ts.map +1 -0
  41. package/dist/op/activities/converge.d.ts +24 -1
  42. package/dist/op/activities/converge.d.ts.map +1 -1
  43. package/dist/op/activities/decide.d.ts +107 -0
  44. package/dist/op/activities/decide.d.ts.map +1 -0
  45. package/dist/op/activities/index.d.ts +10 -0
  46. package/dist/op/activities/index.d.ts.map +1 -1
  47. package/dist/op/activities/shell.d.ts +32 -0
  48. package/dist/op/activities/shell.d.ts.map +1 -1
  49. package/dist/op/activities/source-release.d.ts +86 -0
  50. package/dist/op/activities/source-release.d.ts.map +1 -0
  51. package/dist/op/activities/source-rollback.d.ts +100 -0
  52. package/dist/op/activities/source-rollback.d.ts.map +1 -0
  53. package/dist/op/activities/work-evidence.d.ts +42 -0
  54. package/dist/op/activities/work-evidence.d.ts.map +1 -0
  55. package/dist/op/activity-contract.d.ts +1 -0
  56. package/dist/op/activity-contract.d.ts.map +1 -1
  57. package/dist/op/activity-profiles.d.ts +16 -0
  58. package/dist/op/activity-profiles.d.ts.map +1 -1
  59. package/dist/op/builders.d.ts +84 -2
  60. package/dist/op/builders.d.ts.map +1 -1
  61. package/dist/op/composites/converge-op.d.ts +31 -4
  62. package/dist/op/composites/converge-op.d.ts.map +1 -1
  63. package/dist/op/decide-backend.d.ts +116 -0
  64. package/dist/op/decide-backend.d.ts.map +1 -0
  65. package/dist/op/decide-config.d.ts +120 -0
  66. package/dist/op/decide-config.d.ts.map +1 -0
  67. package/dist/op/decide-read-inputs.d.ts +40 -0
  68. package/dist/op/decide-read-inputs.d.ts.map +1 -0
  69. package/dist/op/gate-wait.d.ts +43 -0
  70. package/dist/op/gate-wait.d.ts.map +1 -0
  71. package/dist/op/gate.d.ts +5 -2
  72. package/dist/op/gate.d.ts.map +1 -1
  73. package/dist/op/index.d.ts +11 -4
  74. package/dist/op/index.d.ts.map +1 -1
  75. package/dist/op/local-executor.d.ts +29 -4
  76. package/dist/op/local-executor.d.ts.map +1 -1
  77. package/dist/op/local-output.d.ts +2 -0
  78. package/dist/op/local-output.d.ts.map +1 -1
  79. package/dist/op/op-ir.d.ts +2 -0
  80. package/dist/op/op-ir.d.ts.map +1 -1
  81. package/dist/op/op-verb-class.d.ts.map +1 -1
  82. package/dist/op/operator.d.ts +97 -1
  83. package/dist/op/operator.d.ts.map +1 -1
  84. package/dist/op/runtime.d.ts +37 -5
  85. package/dist/op/runtime.d.ts.map +1 -1
  86. package/dist/op/runtimes/local.d.ts.map +1 -1
  87. package/dist/op/source-archive.d.ts +63 -0
  88. package/dist/op/source-archive.d.ts.map +1 -0
  89. package/dist/op/steward-points.d.ts +136 -0
  90. package/dist/op/steward-points.d.ts.map +1 -0
  91. package/dist/op/steward-turn.d.ts +53 -0
  92. package/dist/op/steward-turn.d.ts.map +1 -0
  93. package/dist/op/steward.d.ts +22 -1
  94. package/dist/op/steward.d.ts.map +1 -1
  95. package/dist/op/types.d.ts +7 -0
  96. package/dist/op/types.d.ts.map +1 -1
  97. package/dist/op/work-lease-run.d.ts +1 -1
  98. package/dist/op/work-lease-run.d.ts.map +1 -1
  99. package/dist/workspace/__fixtures__/decide-workspace.d.ts +100 -0
  100. package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -0
  101. package/dist/workspace/answers-ledger.d.ts +76 -0
  102. package/dist/workspace/answers-ledger.d.ts.map +1 -0
  103. package/dist/workspace/box-intent.d.ts +85 -0
  104. package/dist/workspace/box-intent.d.ts.map +1 -0
  105. package/dist/workspace/changes-cli.d.ts +16 -0
  106. package/dist/workspace/changes-cli.d.ts.map +1 -0
  107. package/dist/workspace/changes.d.ts +200 -0
  108. package/dist/workspace/changes.d.ts.map +1 -0
  109. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts +59 -0
  110. package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.d.ts.map +1 -0
  111. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts +51 -0
  112. package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.d.ts.map +1 -0
  113. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts +26 -0
  114. package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.d.ts.map +1 -0
  115. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts +59 -0
  116. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.d.ts.map +1 -0
  117. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts +22 -0
  118. package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.d.ts.map +1 -0
  119. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts +71 -0
  120. package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -0
  121. package/dist/workspace/chant-migrations.d.ts +104 -0
  122. package/dist/workspace/chant-migrations.d.ts.map +1 -0
  123. package/dist/workspace/checks/boxes.d.ts +47 -1
  124. package/dist/workspace/checks/boxes.d.ts.map +1 -1
  125. package/dist/workspace/checks/diagrams.d.ts +31 -0
  126. package/dist/workspace/checks/diagrams.d.ts.map +1 -0
  127. package/dist/workspace/checks/records.d.ts +7 -0
  128. package/dist/workspace/checks/records.d.ts.map +1 -1
  129. package/dist/workspace/checks.d.ts +7 -0
  130. package/dist/workspace/checks.d.ts.map +1 -1
  131. package/dist/workspace/compose-graph.d.ts +2 -0
  132. package/dist/workspace/compose-graph.d.ts.map +1 -1
  133. package/dist/workspace/conformance/index.d.ts.map +1 -1
  134. package/dist/workspace/decide.d.ts +49 -4
  135. package/dist/workspace/decide.d.ts.map +1 -1
  136. package/dist/workspace/decision-points.schema.json +3 -3
  137. package/dist/workspace/declaration.d.ts +58 -0
  138. package/dist/workspace/declaration.d.ts.map +1 -1
  139. package/dist/workspace/declaration.schema.json +119 -1
  140. package/dist/workspace/declared-kinds.d.ts +20 -0
  141. package/dist/workspace/declared-kinds.d.ts.map +1 -1
  142. package/dist/workspace/generated-files.d.ts +7 -0
  143. package/dist/workspace/generated-files.d.ts.map +1 -1
  144. package/dist/workspace/intent-joins.d.ts +5 -5
  145. package/dist/workspace/intent.d.ts.map +1 -1
  146. package/dist/workspace/lineage-check.d.ts +3 -0
  147. package/dist/workspace/lineage-check.d.ts.map +1 -1
  148. package/dist/workspace/lineage-upgrade.d.ts +6 -1
  149. package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
  150. package/dist/workspace/ls.d.ts +39 -1
  151. package/dist/workspace/ls.d.ts.map +1 -1
  152. package/dist/workspace/point-answer.schema.json +95 -0
  153. package/dist/workspace/points-cli.d.ts +2 -0
  154. package/dist/workspace/points-cli.d.ts.map +1 -1
  155. package/dist/workspace/points.d.ts +4 -6
  156. package/dist/workspace/points.d.ts.map +1 -1
  157. package/dist/workspace/reason-codes.d.ts +16 -2
  158. package/dist/workspace/reason-codes.d.ts.map +1 -1
  159. package/dist/workspace/records-cli.d.ts +11 -1
  160. package/dist/workspace/records-cli.d.ts.map +1 -1
  161. package/dist/workspace/records-close.d.ts +1 -1
  162. package/dist/workspace/records-close.d.ts.map +1 -1
  163. package/dist/workspace/records-write.d.ts +11 -5
  164. package/dist/workspace/records-write.d.ts.map +1 -1
  165. package/dist/workspace/records.d.ts +34 -4
  166. package/dist/workspace/records.d.ts.map +1 -1
  167. package/dist/workspace/status-gates.d.ts +7 -2
  168. package/dist/workspace/status-gates.d.ts.map +1 -1
  169. package/dist/workspace/status-stewards.d.ts +65 -1
  170. package/dist/workspace/status-stewards.d.ts.map +1 -1
  171. package/dist/workspace/status.d.ts +24 -0
  172. package/dist/workspace/status.d.ts.map +1 -1
  173. package/dist/workspace/work-cli.d.ts +113 -2
  174. package/dist/workspace/work-cli.d.ts.map +1 -1
  175. package/dist/workspace/work-evidence.d.ts +74 -0
  176. package/dist/workspace/work-evidence.d.ts.map +1 -0
  177. package/dist/workspace/work.d.ts +43 -1
  178. package/dist/workspace/work.d.ts.map +1 -1
  179. package/package.json +1 -1
  180. package/src/cli/commands/audit.test.ts +9 -1
  181. package/src/cli/commands/build.ts +3 -2
  182. package/src/cli/commands/lint.ts +7 -1
  183. package/src/cli/handlers/graph.test.ts +20 -0
  184. package/src/cli/handlers/graph.ts +16 -2
  185. package/src/cli/handlers/operator.ts +34 -2
  186. package/src/cli/handlers/run.test.ts +154 -2
  187. package/src/cli/handlers/run.ts +121 -2
  188. package/src/cli/main.test.ts +10 -0
  189. package/src/cli/main.ts +23 -3
  190. package/src/cli/mcp/workspace-plugins.ts +6 -6
  191. package/src/cli/mcp/workspace-tools.test.ts +35 -19
  192. package/src/cli/mcp/workspace-tools.ts +62 -4
  193. package/src/cli/plugins.ts +11 -3
  194. package/src/cli/registry.ts +12 -2
  195. package/src/cli/serve-mcp-workspace.test.ts +6 -6
  196. package/src/codegen/pinned-upgrade.ts +2 -1
  197. package/src/codegen/release-wiring.test.ts +49 -2
  198. package/src/components/capability-plugin-loader.ts +3 -3
  199. package/src/components/cli-support.ts +2 -2
  200. package/src/config.ts +11 -0
  201. package/src/lexicon-module.ts +56 -1
  202. package/src/lexicon-package.test.ts +96 -0
  203. package/src/lifecycle/converge-ledger.ts +20 -0
  204. package/src/lifecycle/run-ledger.ts +6 -0
  205. package/src/lifecycle/symptoms.ts +95 -0
  206. package/src/lint/rules/index.ts +6 -2
  207. package/src/lint/rules/op/index.ts +17 -4
  208. package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +23 -1
  209. package/src/lint/rules/op/ops014-converge-rule-refusals.ts +10 -6
  210. package/src/lint/rules/op/sys010-key-over-plain-http.test.ts +52 -0
  211. package/src/lint/rules/op/sys010-key-over-plain-http.ts +100 -0
  212. package/src/lint/rules/sys001-no-literal-key.test.ts +31 -0
  213. package/src/lint/rules/sys001-no-literal-key.ts +67 -0
  214. package/src/op/__fixtures__/decide-stub-backend.ts +143 -0
  215. package/src/op/activities/activity-contracts.ts +190 -1
  216. package/src/op/activities/apply.ts +7 -6
  217. package/src/op/activities/change-coverage.ts +60 -0
  218. package/src/op/activities/converge.test.ts +55 -1
  219. package/src/op/activities/converge.ts +208 -29
  220. package/src/op/activities/decide.live.test.ts +78 -0
  221. package/src/op/activities/decide.test.ts +308 -0
  222. package/src/op/activities/decide.ts +267 -0
  223. package/src/op/activities/index.ts +21 -0
  224. package/src/op/activities/shell.test.ts +91 -1
  225. package/src/op/activities/shell.ts +91 -2
  226. package/src/op/activities/source-release.test.ts +118 -0
  227. package/src/op/activities/source-release.ts +168 -0
  228. package/src/op/activities/source-rollback.test.ts +131 -0
  229. package/src/op/activities/source-rollback.ts +239 -0
  230. package/src/op/activities/work-evidence.ts +62 -0
  231. package/src/op/activity-contract-registry.test.ts +2 -0
  232. package/src/op/activity-contract-registry.ts +2 -2
  233. package/src/op/activity-contract.test.ts +12 -0
  234. package/src/op/activity-contract.ts +6 -1
  235. package/src/op/activity-profiles.ts +29 -0
  236. package/src/op/activity-registry.test.ts +1 -1
  237. package/src/op/activity-registry.ts +2 -2
  238. package/src/op/builders.ts +119 -5
  239. package/src/op/command-gate.test.ts +192 -0
  240. package/src/op/composites/converge-op.test.ts +27 -1
  241. package/src/op/composites/converge-op.ts +69 -15
  242. package/src/op/decide-backend.test.ts +44 -0
  243. package/src/op/decide-backend.ts +212 -0
  244. package/src/op/decide-config.test.ts +52 -0
  245. package/src/op/decide-config.ts +80 -0
  246. package/src/op/decide-read-inputs.ts +117 -0
  247. package/src/op/gate-approval.ts +2 -2
  248. package/src/op/gate-wait.ts +57 -0
  249. package/src/op/gate.ts +8 -3
  250. package/src/op/generate-pipeline.ts +2 -2
  251. package/src/op/index.ts +18 -3
  252. package/src/op/local-executor.ts +151 -15
  253. package/src/op/local-output.test.ts +33 -0
  254. package/src/op/local-output.ts +20 -2
  255. package/src/op/op-ir.test.ts +10 -0
  256. package/src/op/op-ir.ts +4 -0
  257. package/src/op/op-verb-class.ts +1 -0
  258. package/src/op/operator.ts +290 -11
  259. package/src/op/runtime.ts +31 -8
  260. package/src/op/runtimes/local.ts +3 -1
  261. package/src/op/source-archive.ts +161 -0
  262. package/src/op/steward-points.test.ts +364 -0
  263. package/src/op/steward-points.ts +194 -0
  264. package/src/op/steward-turn.ts +79 -0
  265. package/src/op/steward.test.ts +87 -3
  266. package/src/op/steward.ts +25 -1
  267. package/src/op/types.ts +7 -0
  268. package/src/op/work-lease-run.test.ts +20 -1
  269. package/src/op/work-lease-run.ts +2 -2
  270. package/src/workspace/__fixtures__/decide-workspace.ts +129 -0
  271. package/src/workspace/__fixtures__/studio-template-84c8b21.json +67 -0
  272. package/src/workspace/answers-ledger.ts +118 -0
  273. package/src/workspace/box-intent.test.ts +205 -0
  274. package/src/workspace/box-intent.ts +159 -0
  275. package/src/workspace/changes-cli.ts +56 -0
  276. package/src/workspace/changes.schema.json +472 -0
  277. package/src/workspace/changes.test.ts +315 -0
  278. package/src/workspace/changes.ts +512 -0
  279. package/src/workspace/chant-migrations/chud-lexicon-exit-fly-site.ts +234 -0
  280. package/src/workspace/chant-migrations/chud-lexicon-exit-live-names.ts +164 -0
  281. package/src/workspace/chant-migrations/chud-lexicon-exit-rollback.ts +223 -0
  282. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.ts +195 -0
  283. package/src/workspace/chant-migrations/chud-lexicon-exit-ship-policy.ts +108 -0
  284. package/src/workspace/chant-migrations/chud-lexicon-exit.ts +882 -0
  285. package/src/workspace/chant-migrations.e2e.test.ts +1089 -0
  286. package/src/workspace/chant-migrations.ts +169 -0
  287. package/src/workspace/check-contract.test.ts +4 -2
  288. package/src/workspace/check.schema.json +19 -5
  289. package/src/workspace/checks/boxes.test.ts +82 -2
  290. package/src/workspace/checks/boxes.ts +202 -1
  291. package/src/workspace/checks/diagrams.test.ts +134 -0
  292. package/src/workspace/checks/diagrams.ts +108 -0
  293. package/src/workspace/checks/records.ts +47 -0
  294. package/src/workspace/checks.ts +20 -2
  295. package/src/workspace/compose-graph.ts +2 -0
  296. package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +10 -0
  297. package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +26 -0
  298. package/src/workspace/conformance/index.ts +5 -0
  299. package/src/workspace/decide.test.ts +1 -1
  300. package/src/workspace/decide.ts +156 -23
  301. package/src/workspace/decision-points.schema.json +3 -3
  302. package/src/workspace/declaration.schema.json +119 -1
  303. package/src/workspace/declaration.test.ts +58 -0
  304. package/src/workspace/declaration.ts +112 -0
  305. package/src/workspace/declared-kinds.test.ts +31 -5
  306. package/src/workspace/declared-kinds.ts +46 -1
  307. package/src/workspace/generated-files.ts +14 -0
  308. package/src/workspace/graph-cli.ts +1 -1
  309. package/src/workspace/graph.schema.json +9 -1
  310. package/src/workspace/intent-joins.test.ts +5 -5
  311. package/src/workspace/intent-joins.ts +5 -5
  312. package/src/workspace/intent.schema.json +8 -2
  313. package/src/workspace/intent.ts +3 -10
  314. package/src/workspace/lineage-check.ts +16 -1
  315. package/src/workspace/lineage-upgrade-cli.ts +1 -1
  316. package/src/workspace/lineage-upgrade.test.ts +70 -0
  317. package/src/workspace/lineage-upgrade.ts +81 -10
  318. package/src/workspace/ls-contract.test.ts +57 -0
  319. package/src/workspace/ls.schema.json +46 -1
  320. package/src/workspace/ls.ts +62 -3
  321. package/src/workspace/points-cli.ts +17 -3
  322. package/src/workspace/points-write.schema.json +11 -1
  323. package/src/workspace/points.schema.json +51 -0
  324. package/src/workspace/points.test.ts +16 -15
  325. package/src/workspace/points.ts +5 -17
  326. package/src/workspace/read-contract.test.ts +9 -1
  327. package/src/workspace/reason-codes.test.ts +18 -8
  328. package/src/workspace/reason-codes.ts +21 -2
  329. package/src/workspace/records-amend.schema.json +2 -0
  330. package/src/workspace/records-cli.ts +27 -4
  331. package/src/workspace/records-close.schema.json +2 -0
  332. package/src/workspace/records-formats.test.ts +15 -15
  333. package/src/workspace/records-new.schema.json +2 -0
  334. package/src/workspace/records-review.schema.json +2 -0
  335. package/src/workspace/records-sessions-write.e2e.test.ts +77 -0
  336. package/src/workspace/records-sessions-write.test.ts +2 -34
  337. package/src/workspace/records-since.test.ts +8 -7
  338. package/src/workspace/records-write.e2e.test.ts +108 -0
  339. package/src/workspace/records-write.test.ts +32 -41
  340. package/src/workspace/records-write.ts +33 -15
  341. package/src/workspace/records.schema.json +36 -2
  342. package/src/workspace/records.test.ts +49 -4
  343. package/src/workspace/records.ts +109 -3
  344. package/src/workspace/status-contract.test.ts +14 -8
  345. package/src/workspace/status-gates.ts +9 -4
  346. package/src/workspace/status-stewards.ts +155 -5
  347. package/src/workspace/status.schema.json +129 -8
  348. package/src/workspace/status.ts +46 -1
  349. package/src/workspace/work-acceptance.test.ts +274 -0
  350. package/src/workspace/{work-cli.test.ts → work-cli.e2e.test.ts} +1 -1
  351. package/src/workspace/work-cli.ts +193 -10
  352. package/src/workspace/work-evidence.schema.json +212 -0
  353. package/src/workspace/work-evidence.ts +169 -0
  354. package/src/workspace/work-history.schema.json +349 -0
  355. package/src/workspace/work-history.test.ts +156 -0
  356. package/src/workspace/{work-readiness-chud.test.ts → work-readiness.test.ts} +30 -32
  357. package/src/workspace/work.test.ts +20 -2
  358. package/src/workspace/work.ts +100 -1
  359. /package/src/cli/{discovery-skip.test.ts → discovery-skip.e2e.test.ts} +0 -0
  360. /package/src/workspace/conformance/{conformance.test.ts → conformance.e2e.test.ts} +0 -0
  361. /package/src/workspace/{which-chant.test.ts → which-chant.e2e.test.ts} +0 -0
@@ -25,10 +25,14 @@ import { resolveActivity, type ActivityFn, type ActivityProfile } from "./activi
25
25
  import type { ReceiptReadResult } from "./receipt-store";
26
26
  import { isStepOutputRef } from "./step-output-ref";
27
27
  import { parseDuration } from "./duration";
28
+ import { stepTimeoutProblem } from "./activity-profiles";
28
29
  import { describeGateMismatch, evaluateGate, gitGateLedgerPort, type GateCheck, type GateLedgerPort } from "./gate";
29
30
  import { gateName } from "./gate-name";
30
31
  import type { ResolvedGateApproval } from "./gate-approval";
31
32
  import type { PendingGateRecord } from "../lifecycle/gate-ledger";
33
+ import { isPointWait, type WaitingPoint } from "./steward-points";
34
+ import { isGateWait } from "./gate-wait";
35
+ import { currentStewardTurn, enterStewardTurn } from "./steward-turn";
32
36
  import { appendRunRecord, buildRunRecord } from "../lifecycle/run-ledger";
33
37
  import type { OpRunRecord } from "./runtime";
34
38
  import { randomUUID } from "node:crypto";
@@ -78,6 +82,18 @@ export interface StepRecord {
78
82
  * was applied.
79
83
  */
80
84
  refusal?: string;
85
+ /**
86
+ * Set on an activity step that asked a decision point still open (#2749):
87
+ * the question the run now waits on. The step's status is `skipped` and the
88
+ * run's is `waiting`: nothing broke, and a person answers the question.
89
+ */
90
+ point?: WaitingPoint;
91
+ /**
92
+ * Set on an activity step whose command stopped at a gate of its own
93
+ * (#2779): the op the gate is recorded under and its name, what `chant
94
+ * approve` takes. The step's status is `skipped` and the run's is `gated`.
95
+ */
96
+ gate?: { op: string; gate: string };
81
97
  }
82
98
 
83
99
  export interface OpRunResult {
@@ -91,11 +107,17 @@ export interface OpRunResult {
91
107
  *
92
108
  * Written to the run ledger as the record's own `status` (#2118).
93
109
  */
94
- status: "ok" | "fail" | "gated";
110
+ status: "ok" | "fail" | "gated" | "waiting";
95
111
  /** ISO-8601 start of this run. */
96
112
  startedAt: string;
97
113
  /** Present when `status === "gated"`: the pending fact the run ended on. */
98
114
  gate?: PendingGateRecord;
115
+ /**
116
+ * Present when `status === "waiting"` (#2749): the open decision point the
117
+ * run stopped on. Like a gate, it is a fact and not a wait: a person answers
118
+ * the question, and the next run reads the answer.
119
+ */
120
+ point?: WaitingPoint;
99
121
  /**
100
122
  * Present when `status === "gated"` and this run's own append tried to push:
101
123
  * whether it reached the remote (#2310). Absent when the run stopped on a
@@ -173,6 +195,18 @@ class GateStop extends Error {
173
195
  }
174
196
  }
175
197
 
198
+ /** Internal: a step asked a decision point that is still open (#2749). Not a failure — no compensation follows it. */
199
+ class PointStop extends Error {
200
+ constructor(
201
+ public readonly records: StepRecord[],
202
+ public readonly question: WaitingPoint,
203
+ public readonly phase: string,
204
+ ) {
205
+ super(`waiting on decision point ${question.id}`);
206
+ this.name = "PointStop";
207
+ }
208
+ }
209
+
176
210
  /**
177
211
  * Internal: a step boundary found the run can't go on under its work lease
178
212
  * (#2748). `lost` false is a claim that found nothing to claim: not a
@@ -312,6 +346,8 @@ async function callWithTimeout(
312
346
  interface RanStep {
313
347
  record: StepRecord;
314
348
  result?: unknown;
349
+ /** The pending fact a step's command stopped at (#2779), when it threw {@link GateWait}. */
350
+ pending?: PendingGateRecord;
315
351
  }
316
352
 
317
353
  /**
@@ -341,9 +377,16 @@ async function runStep(
341
377
  }
342
378
 
343
379
  const profile = profiles[step.profile ?? DEFAULT_PROFILE] ?? {};
344
- const timeoutMs = profile.timeout
345
- ? parseDuration(profile.timeout)
346
- : FALLBACK_TIMEOUT_MS;
380
+ // A step's own timeout (#2787) replaces the profile's and keeps its retries.
381
+ if (step.timeout !== undefined) {
382
+ const problem = stepTimeoutProblem(step.timeout);
383
+ if (problem) return { record: { ...base, status: "fail", durationMs: 0, error: problem } };
384
+ }
385
+ const timeoutMs = step.timeout !== undefined
386
+ ? parseDuration(step.timeout)
387
+ : profile.timeout
388
+ ? parseDuration(profile.timeout)
389
+ : FALLBACK_TIMEOUT_MS;
347
390
  const maxAttempts =
348
391
  profile.retry?.maximumAttempts && profile.retry.maximumAttempts > 0
349
392
  ? profile.retry.maximumAttempts
@@ -368,6 +411,17 @@ async function runStep(
368
411
  }
369
412
  return { record, result };
370
413
  } catch (err) {
414
+ // An open decision point (#2749) is not a failure and not worth a retry:
415
+ // the answer comes from a person, on a later run.
416
+ if (isPointWait(err)) {
417
+ return { record: { ...base, status: "skipped", durationMs: Date.now() - start, point: err.question } };
418
+ }
419
+ // Nor is a command that stopped at a gate of its own (#2779): the run
420
+ // ends `gated` there, and the next run asks the command again.
421
+ if (isGateWait(err)) {
422
+ const gate = { op: err.pending.op, gate: err.pending.gate };
423
+ return { record: { ...base, status: "skipped", durationMs: Date.now() - start, gate }, pending: err.pending };
424
+ }
371
425
  lastErr = err;
372
426
  // Stop retrying on abort (Ctrl-C / timeout cascade) or a non-retryable error.
373
427
  const fatal =
@@ -640,6 +694,7 @@ async function runEffectStep(
640
694
  pending?: PendingGateRecord;
641
695
  pushed?: boolean;
642
696
  pushWarning?: string;
697
+ point?: WaitingPoint;
643
698
  }> {
644
699
  const records: StepRecord[] = [];
645
700
 
@@ -705,6 +760,18 @@ async function runEffectStep(
705
760
  }
706
761
  const ran = await runStep(nested, phaseName, activities, profiles, resultsById, signal);
707
762
  pushRecord(records, gates, ran.record);
763
+ if (ran.pending) {
764
+ // A command's own gate (#2779): the receipt is left untouched, as for a
765
+ // pending gate step.
766
+ skipRest(i + 1);
767
+ return { records, failed: false, pending: ran.pending };
768
+ }
769
+ if (ran.record.point) {
770
+ // Receipt left untouched, as for a pending gate: the next run re-proposes
771
+ // the effect and asks the point again, and finds the answer by then.
772
+ skipRest(i + 1);
773
+ return { records, failed: false, point: ran.record.point };
774
+ }
708
775
  if (ran.record.status === "fail") {
709
776
  // Receipt left untouched (stale) — the next run re-proposes the effect.
710
777
  skipRest(i + 1);
@@ -779,12 +846,19 @@ async function runPhase(
779
846
  }
780
847
  }
781
848
  const steps = phase.steps.filter(isActivity);
782
- const ran = (
783
- await Promise.all(steps.map((s) => runStep(s, phase.name, activities, profiles, resultsById, signal)))
784
- ).map((r) => r.record);
849
+ const settled = await Promise.all(steps.map((s) => runStep(s, phase.name, activities, profiles, resultsById, signal)));
850
+ const ran = settled.map((r) => r.record);
785
851
  for (const r of ran) gates.onRecord?.(r);
786
852
  const records = gateRecords.concat(ran);
787
853
  if (records.some((r) => r.status === "fail")) throw new PhaseFailure(records);
854
+ // A step whose command stopped at its own gate (#2779) stops the run at
855
+ // this phase, as a gate step would, once its siblings have finished.
856
+ const gated = settled.find((r) => r.pending)?.pending;
857
+ if (gated) throw new GateStop(records, gated, phase.name);
858
+ // The fan-out has already run, so the siblings of an open decision point
859
+ // finished; the run still stops at this phase (#2749).
860
+ const waiting = ran.find((r) => r.point);
861
+ if (waiting?.point) throw new PointStop(records, waiting.point, phase.name);
788
862
  return records;
789
863
  }
790
864
 
@@ -828,10 +902,14 @@ async function runPhase(
828
902
  continue;
829
903
  }
830
904
  if (isEffect(step)) {
831
- const { records: effRecords, failed, pending, pushed, pushWarning } = await runEffectStep(
905
+ const { records: effRecords, failed, pending, pushed, pushWarning, point } = await runEffectStep(
832
906
  step, phase.name, activities, profiles, resultsById, gates, signal,
833
907
  );
834
908
  records.push(...effRecords); // already emitted by runEffectStep
909
+ if (point) {
910
+ skipRemaining(i + 1);
911
+ throw new PointStop(records, point, phase.name);
912
+ }
835
913
  if (pending) {
836
914
  skipRemaining(i + 1);
837
915
  throw new GateStop(records, pending, phase.name, pushed, pushWarning);
@@ -842,8 +920,19 @@ async function runPhase(
842
920
  }
843
921
  continue;
844
922
  }
845
- const { record } = await runStep(step, phase.name, activities, profiles, resultsById, signal);
923
+ const { record, pending } = await runStep(step, phase.name, activities, profiles, resultsById, signal);
846
924
  pushRecord(records, gates, record);
925
+ if (pending) {
926
+ // The step's command stopped at its own gate (#2779): the run ends
927
+ // `gated` there, as at a pending gate step.
928
+ skipRemaining(i + 1);
929
+ throw new GateStop(records, pending, phase.name);
930
+ }
931
+ if (record.point) {
932
+ // An open decision point (#2749) ends the run as a pending gate does.
933
+ skipRemaining(i + 1);
934
+ throw new PointStop(records, record.point, phase.name);
935
+ }
847
936
  if (record.status === "fail") {
848
937
  // Mark the remaining steps in this phase as skipped, then abort.
849
938
  skipRemaining(i + 1);
@@ -890,6 +979,8 @@ export interface RunOpOptions {
890
979
  * never promoted into a run failure.
891
980
  */
892
981
  onLedgerError?: (err: unknown) => void;
982
+ /** The steward whose turn this run is (#2749), recorded on its ledger record. */
983
+ steward?: string;
893
984
  /**
894
985
  * For an Op that declares `workLease` (#2748): the item this run is for
895
986
  * (`chant run <op> --work <id>`), which takes the place of the Op's own, and
@@ -907,9 +998,10 @@ export interface RunOpOptions {
907
998
  * Resolves with the run result when every phase succeeds (`status: "ok"`), and
908
999
  * also when the run stopped at an unapproved gate (`status: "gated"`, with the
909
1000
  * pending fact on `result.gate`) — a gate is a fact, not an error, so it is not
910
- * thrown. Rejects with `OpRunFailure` (carrying the partial result) on terminal
911
- * failure, after running any `onFailure` phases in reverse order; a gated run
912
- * runs no `onFailure` phase, because nothing failed and nothing was left
1001
+ * thrown. So does an activity's open decision point (`status: "waiting"`, with
1002
+ * the question on `result.point`, #2749). Rejects with `OpRunFailure` (carrying the partial result) on terminal
1003
+ * failure, after running any `onFailure` phases in reverse order; a gated or
1004
+ * waiting run runs no `onFailure` phase, because nothing failed and nothing was left
913
1005
  * half-applied to compensate for.
914
1006
  *
915
1007
  * Whichever of the three ways it settles, the run carries an
@@ -928,6 +1020,27 @@ export async function runOpLocally(
928
1020
  // The run id is the gate ledger's and the run ledger's alike: a pending gate
929
1021
  // fact and the record naming that gate carry the same string.
930
1022
  const runId = options.runId ?? randomUUID();
1023
+ // In a steward's turn (#2749: `chant operator --steward`, or `chant acp
1024
+ // --steward` on Fountain) the run is the steward's: its record names the
1025
+ // steward, and a decision point asked during it names this run.
1026
+ const turn = currentStewardTurn();
1027
+ const steward = options.steward ?? turn?.steward;
1028
+ const restore = turn && turn.run !== runId ? enterStewardTurn({ ...turn, run: runId }) : undefined;
1029
+ try {
1030
+ return await runOpInTurn(config, activities, profiles, signal, { ...options, runId, ...(steward ? { steward } : {}) });
1031
+ } finally {
1032
+ restore?.();
1033
+ }
1034
+ }
1035
+
1036
+ async function runOpInTurn(
1037
+ config: OpConfig,
1038
+ activities: Map<string, ActivityFn>,
1039
+ profiles: Record<string, ActivityProfile>,
1040
+ signal: AbortSignal | undefined,
1041
+ options: RunOpOptions & { runId: string },
1042
+ ): Promise<OpRunResult> {
1043
+ const runId = options.runId;
931
1044
 
932
1045
  const gates: GateContext = {
933
1046
  op: config.name,
@@ -1023,13 +1136,18 @@ export async function runOpLocally(
1023
1136
  settled: StepRecord[],
1024
1137
  status: OpRunResult["status"],
1025
1138
  gate?: PendingGateRecord,
1139
+ point?: WaitingPoint,
1026
1140
  ): Promise<OpRunRecord> => {
1141
+ const ended = options.now ?? new Date().toISOString();
1027
1142
  const input = buildRunRecord(config, settled, {
1028
1143
  started: startedAt,
1029
- ended: options.now ?? new Date().toISOString(),
1144
+ ended,
1030
1145
  status,
1031
1146
  id: runId,
1032
- ...(gate ? { gate: { name: gate.gate, since: gate.timestamp } } : {}),
1147
+ // A gate recorded under another op (#2779: a command's own gate) names it.
1148
+ ...(gate ? { gate: { name: gate.gate, since: gate.timestamp, ...(gate.op !== config.name ? { op: gate.op } : {}) } } : {}),
1149
+ ...(point ? { point: { ...point, since: ended } } : {}),
1150
+ ...(options.steward ? { steward: options.steward } : {}),
1033
1151
  });
1034
1152
  const record: OpRunRecord = { version: 1, ...input, id: runId };
1035
1153
  if (!options.ledger) return record;
@@ -1072,6 +1190,24 @@ export async function runOpLocally(
1072
1190
  };
1073
1191
  }
1074
1192
 
1193
+ // An open decision point ends the run the way a pending gate does (#2749):
1194
+ // no later phase and no compensation, and the run is `waiting`.
1195
+ if (err instanceof PointStop) {
1196
+ records.push(...err.records);
1197
+ skipLaterPhases(err.phase);
1198
+ const record = await settle(records, "waiting", undefined, err.question);
1199
+ return {
1200
+ op: config.name,
1201
+ records,
1202
+ totalMs: Date.now() - start,
1203
+ status: "waiting",
1204
+ startedAt,
1205
+ point: err.question,
1206
+ record,
1207
+ ...(await finishWork("waiting")),
1208
+ };
1209
+ }
1210
+
1075
1211
  // A pending gate ends the run where it stands: no later phase, and no
1076
1212
  // `onFailure` compensation — nothing failed, so there is nothing to undo.
1077
1213
  if (err instanceof GateStop) {
@@ -1135,7 +1271,7 @@ export async function runOpLocally(
1135
1271
  try {
1136
1272
  records.push(...(await runPhase(phase, activities, profiles, resultsById, compensation, signal)));
1137
1273
  } catch (compErr) {
1138
- if (compErr instanceof PhaseFailure || compErr instanceof GateStop) {
1274
+ if (compErr instanceof PhaseFailure || compErr instanceof GateStop || compErr instanceof PointStop) {
1139
1275
  records.push(...compErr.records);
1140
1276
  } else {
1141
1277
  // The same swallow, one level down (#2301): a compensation phase
@@ -75,6 +75,23 @@ const GATED: OpRunResult = withRecord({
75
75
  ],
76
76
  });
77
77
 
78
+ /** A gate bound to a plan (#2300), for the --plan tests (#2832). */
79
+ const GATED_WITH_PLAN: OpRunResult = withRecord({
80
+ op: "prod-apply",
81
+ totalMs: 300,
82
+ status: "gated",
83
+ startedAt: "2026-09-05T12:00:00.000Z",
84
+ gate: {
85
+ version: 1, kind: "pending", op: "prod-apply", gate: "rollout-gate",
86
+ timestamp: "2026-09-05T12:00:00.000Z",
87
+ expiresAt: "2026-09-07T12:00:00.000Z",
88
+ planDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
89
+ },
90
+ records: [
91
+ { phase: "Apply", fn: "gate:rollout-gate", args: {}, status: "skipped", durationMs: 0 },
92
+ ],
93
+ });
94
+
78
95
  describe("renderHuman — gated (#2119)", () => {
79
96
  test("names the gate, the approve line and the expiry, and points at no other runtime", () => {
80
97
  const lines: string[] = [];
@@ -88,6 +105,14 @@ describe("renderHuman — gated (#2119)", () => {
88
105
  expect(out).not.toContain("--on");
89
106
  });
90
107
 
108
+ test("a gate bound to a plan (#2300) carries --plan on the approve line (#2832)", () => {
109
+ const lines: string[] = [];
110
+ renderHuman(GATED_WITH_PLAN, (l) => lines.push(l));
111
+ const out = lines.join("\n");
112
+ expect(out).toContain(`plan : ${GATED_WITH_PLAN.gate!.planDigest}`);
113
+ expect(out).toContain(`approve : chant approve prod-apply rollout-gate --plan ${GATED_WITH_PLAN.gate!.planDigest}`);
114
+ });
115
+
91
116
  test("shows the approver on a gate that passed", () => {
92
117
  const lines: string[] = [];
93
118
  renderHuman(withRecord({
@@ -157,6 +182,14 @@ describe("renderJson", () => {
157
182
  expect(parsed.approve).toBe("chant approve prod-apply rollout-gate");
158
183
  });
159
184
 
185
+ test("a gate bound to a plan (#2300) carries --plan on the approve line (#2832)", () => {
186
+ const lines: string[] = [];
187
+ renderJson(GATED_WITH_PLAN, (l) => lines.push(l));
188
+ const parsed = JSON.parse(lines[0]) as OpRunRecord & { approve: string };
189
+ expect(parsed.status).toBe("gated");
190
+ expect(parsed.approve).toBe(`chant approve prod-apply rollout-gate --plan ${GATED_WITH_PLAN.gate!.planDigest}`);
191
+ });
192
+
160
193
  // #2310: a JSON consumer (CI tooling reading `chant run --json`) needs the
161
194
  // same fact the human render shows — not just a silent success.
162
195
  test("a gated record whose push failed carries pushed:false and why", () => {
@@ -50,6 +50,9 @@ export function renderHuman(result: OpRunResult, write: Writer = stderr): void {
50
50
  if (record.refusal) {
51
51
  write(` [refused] ${record.refusal}`);
52
52
  }
53
+ if (record.point) {
54
+ write(` [waiting] decision point ${record.point.point}: ${record.point.id} is ${record.point.state}`);
55
+ }
53
56
  if (record.error) {
54
57
  write(` ${record.error}`);
55
58
  }
@@ -73,6 +76,16 @@ export function renderHuman(result: OpRunResult, write: Writer = stderr): void {
73
76
  write(`Op "${result.op}" completed in ${total}`);
74
77
  return;
75
78
  }
79
+ if (result.status === "waiting" && result.point) {
80
+ // An open decision point (#2749): a fact like a gate. A person answers the
81
+ // question, through hud or at a shell, and the next run reads the answer.
82
+ const { point } = result;
83
+ write(`Op "${result.op}" is waiting on decision point "${point.point}" after ${total}`);
84
+ write(` question: ${point.id} (${point.state}) at ${point.path}`);
85
+ if (point.subject) write(` subject : ${point.subject}`);
86
+ write(` answer : ${pointAnswerCommand(point.id)}`);
87
+ return;
88
+ }
76
89
  if (result.status === "fail" || !result.gate) {
77
90
  write(`Op "${result.op}" failed after ${total}`);
78
91
  return;
@@ -87,7 +100,7 @@ export function renderHuman(result: OpRunResult, write: Writer = stderr): void {
87
100
  // #2300: the plan the approval will be bound to. Printed before the
88
101
  // command, because it is what the command approves.
89
102
  if (gate.planDigest) write(` plan : ${gate.planDigest}`);
90
- write(` approve : ${approveCommand(gate.op, gate.gate)}`);
103
+ write(` approve : ${approveCommand(gate.op, gate.gate, undefined, gate.planDigest)}`);
91
104
  if (gate.url) write(` approve at: ${gate.url}`);
92
105
  write(` expires : ${gate.expiresAt}`);
93
106
  // #2310: this run's own append reached only the local chant/lifecycle
@@ -115,7 +128,7 @@ export function renderHuman(result: OpRunResult, write: Writer = stderr): void {
115
128
  * the gate doesn't have to reassemble it from the op and gate names.
116
129
  */
117
130
  export function renderJson(result: OpRunResult, write: Writer = stdout): void {
118
- const approve = result.gate ? { approve: approveCommand(result.gate.op, result.gate.gate) } : {};
131
+ const approve = result.gate ? { approve: approveCommand(result.gate.op, result.gate.gate, undefined, result.gate.planDigest) } : {};
119
132
  // #2310: whether this run's own append reached the remote — not part of
120
133
  // the persisted ledger record (a replay has nothing new to report), but a
121
134
  // live run's JSON consumer needs it exactly where the human render shows it.
@@ -126,3 +139,8 @@ export function renderJson(result: OpRunResult, write: Writer = stdout): void {
126
139
  }
127
140
 
128
141
  export type { OpRunResult, StepRecord };
142
+
143
+ /** The command a person answers an open decision point with (#2749). */
144
+ export function pointAnswerCommand(id: string): string {
145
+ return `chant workspace points answer ${id} --answer <answer> --by <your name>`;
146
+ }
@@ -112,6 +112,16 @@ describe("op.json IR", () => {
112
112
  expect(serializeOpIR(reconstructed)).toBe(text);
113
113
  });
114
114
 
115
+ it("carries a step's own timeout, and round-trips it (#2787)", () => {
116
+ const original: OpConfig = { name: "dispatch", overview: "o", phases: [phase("Build", [shell("./build.sh", { timeout: "45m" }), shell("echo hi")])] };
117
+ const ir = buildOpIR(original);
118
+ const steps = ir.phases[0].steps as { profile: string; timeout?: string }[];
119
+ expect(steps[0]).toMatchObject({ profile: "atMostOnce", timeout: "45m" });
120
+ expect(steps[1]).not.toHaveProperty("timeout");
121
+ const text = serializeOpIR(original);
122
+ expect(serializeOpIR(opConfigFromIR(JSON.parse(text) as OpIR))).toBe(text);
123
+ });
124
+
115
125
  it("two serializations of the same config are byte-identical (determinism)", () => {
116
126
  const config = representativeOp();
117
127
  expect(serializeOpIR(config)).toBe(serializeOpIR(config));
package/src/op/op-ir.ts CHANGED
@@ -118,6 +118,8 @@ export interface OpIRActivityStep {
118
118
  args: Record<string, unknown>;
119
119
  /** Resolved to its effective value — `ActivityStep.profile ?? "fastIdempotent"`. */
120
120
  profile: string;
121
+ /** The step's own timeout, replacing its profile's (#2787). Absent when the profile's applies. */
122
+ timeout?: string;
121
123
  /**
122
124
  * What this step's effect touches in the estate (#2022): the string values
123
125
  * of the args its contract declares as entity-identifying
@@ -240,6 +242,7 @@ function irActivityStep(step: ActivityStep, contracts: ReadonlyMap<string, Activ
240
242
  fn: step.fn,
241
243
  args: step.args ?? {},
242
244
  profile: effectiveProfile(step),
245
+ ...(step.timeout !== undefined ? { timeout: step.timeout } : {}),
243
246
  ...(entities ? { entities } : {}),
244
247
  ...(step.outcomeAttribute ? { outcomeAttribute: step.outcomeAttribute } : {}),
245
248
  };
@@ -394,6 +397,7 @@ function opStepFromIR(step: OpIRStep): StepDefinition {
394
397
  fn: step.fn,
395
398
  args: step.args,
396
399
  profile: step.profile as ActivityStep["profile"],
400
+ ...(step.timeout !== undefined ? { timeout: step.timeout } : {}),
397
401
  ...(step.outcomeAttribute ? { outcomeAttribute: step.outcomeAttribute } : {}),
398
402
  };
399
403
  }
@@ -51,6 +51,7 @@ const READ_ONLY_ACTIVITY_FNS: ReadonlySet<string> = new Set([
51
51
  "spriteServiceGet",
52
52
  "spriteServiceList",
53
53
  "spriteServiceLogs",
54
+ "spriteServicesObserve",
54
55
  ]);
55
56
 
56
57
  /** Activity function names that always delete/destroy, regardless of args. */