@rse/ase 1.0.6 → 2.0.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 (279) hide show
  1. package/dst/ase-agent-definition-api.d.ts +184 -0
  2. package/dst/ase-agent-definition-api.js +6 -0
  3. package/dst/ase-agent-definition-builtin/condenser.js +42 -0
  4. package/dst/ase-agent-definition-builtin/editor.js +45 -0
  5. package/dst/ase-agent-definition-builtin/estimator.js +98 -0
  6. package/dst/ase-agent-definition-builtin/implementer.js +121 -0
  7. package/dst/ase-agent-definition-builtin/integrator.js +56 -0
  8. package/dst/ase-agent-definition-builtin/qualifier.js +61 -0
  9. package/dst/ase-agent-definition-builtin/rebooter.js +41 -0
  10. package/dst/ase-agent-definition-builtin/researcher.js +77 -0
  11. package/dst/ase-agent-definition-core.js +827 -0
  12. package/dst/ase-agent-fleet.js +772 -0
  13. package/dst/ase-agent-process.js +232 -0
  14. package/dst/ase-agent-relay-client.js +509 -0
  15. package/dst/ase-agent-relay-core.js +213 -0
  16. package/dst/ase-agent-relay-server-bind.js +242 -0
  17. package/dst/ase-agent-relay-server-cli.js +50 -0
  18. package/dst/ase-agent-runtime-claim.js +189 -0
  19. package/dst/ase-agent-runtime-engine.js +1100 -0
  20. package/dst/ase-agent-runtime-exec.js +275 -0
  21. package/dst/ase-agent-runtime-phase.js +581 -0
  22. package/dst/ase-agent-runtime-request.js +272 -0
  23. package/dst/ase-agent-runtime-tool.js +207 -0
  24. package/dst/ase-agent-runtime.js +1316 -0
  25. package/dst/ase-agent.js +65 -0
  26. package/dst/ase-artifact.js +6 -5
  27. package/dst/ase-config-core.js +465 -0
  28. package/dst/ase-config-schema.js +351 -0
  29. package/dst/ase-config-scope.js +172 -0
  30. package/dst/ase-config.js +25 -585
  31. package/dst/ase-hook.js +230 -116
  32. package/dst/ase-lib-daemon-cli.js +130 -0
  33. package/dst/ase-lib-hash.js +20 -0
  34. package/dst/{ase-log.js → ase-lib-log.js} +40 -7
  35. package/dst/ase-lib-server-bind.js +115 -0
  36. package/dst/ase-lib-server-cli.js +474 -0
  37. package/dst/{ase-table.js → ase-lib-table.js} +1 -1
  38. package/dst/{ase-version.js → ase-lib-version.js} +3 -0
  39. package/dst/ase-man.js +96 -0
  40. package/dst/ase-mcp.js +166 -13
  41. package/dst/{ase-getopt.js → ase-service-getopt.js} +82 -80
  42. package/dst/{ase-markdown.js → ase-service-markdown.js} +18 -11
  43. package/dst/ase-service-otel.js +1246 -0
  44. package/dst/{ase-skills.js → ase-service-skills.js} +29 -64
  45. package/dst/ase-service-state.js +101 -0
  46. package/dst/ase-service.js +251 -76
  47. package/dst/ase-setup-common.js +141 -0
  48. package/dst/ase-setup-mcp.js +359 -0
  49. package/dst/ase-setup-settings.js +837 -0
  50. package/dst/ase-setup.js +113 -869
  51. package/dst/ase-spec.js +31 -19
  52. package/dst/ase-statusline.js +108 -43
  53. package/dst/ase-task-board-core.js +739 -0
  54. package/dst/ase-task-board-filter.js +127 -0
  55. package/dst/ase-task-board-flow.js +237 -0
  56. package/dst/ase-task-board-graph.js +497 -0
  57. package/dst/ase-task-board-stats.js +263 -0
  58. package/dst/ase-task-board-tui-control.js +775 -0
  59. package/dst/ase-task-board-tui-model.js +1008 -0
  60. package/dst/ase-task-board-tui-popup.js +626 -0
  61. package/dst/ase-task-board-tui-style.js +106 -0
  62. package/dst/ase-task-board-tui-view.js +847 -0
  63. package/dst/ase-task-board-tui.js +189 -0
  64. package/dst/ase-task-board-web-client.css +1 -0
  65. package/dst/ase-task-board-web-client.html +20 -0
  66. package/dst/ase-task-board-web-client.js +81 -0
  67. package/dst/ase-task-board-web-server.js +823 -0
  68. package/dst/ase-task-board.js +134 -0
  69. package/dst/ase-task-format.js +757 -0
  70. package/dst/ase-task-request.js +208 -0
  71. package/dst/ase-task-store-client.js +495 -0
  72. package/dst/ase-task-store-core.js +804 -0
  73. package/dst/ase-task-store-issues.js +237 -0
  74. package/dst/ase-task-store-plugin-api.js +6 -0
  75. package/dst/ase-task-store-plugin-ase.js +484 -0
  76. package/dst/ase-task-store-plugin-delegate.js +137 -0
  77. package/dst/ase-task-store-plugin-gitea.js +666 -0
  78. package/dst/ase-task-store-plugin-github.js +696 -0
  79. package/dst/ase-task-store-plugin-gitlab.js +668 -0
  80. package/dst/ase-task-store-server-bind.js +538 -0
  81. package/dst/ase-task-store-server-cli.js +154 -0
  82. package/dst/ase-task.js +1335 -357
  83. package/dst/{ase-compat.js → ase-util-compat.js} +2 -2
  84. package/dst/{ase-diagram.js → ase-util-diagram.js} +107 -32
  85. package/dst/{ase-meta.js → ase-util-meta.js} +2 -2
  86. package/dst/{ase-metric.js → ase-util-metric.js} +2 -2
  87. package/dst/{ase-mint.js → ase-util-mint.js} +19 -12
  88. package/dst/{ase-worktree.js → ase-util-worktree.js} +30 -19
  89. package/dst/ase-util.js +20 -0
  90. package/dst/ase.js +108 -32
  91. package/dst/man/ase-agent-adhoc.1 +515 -0
  92. package/dst/man/ase-agent-condenser.1 +193 -0
  93. package/dst/man/ase-agent-editor.1 +212 -0
  94. package/dst/man/ase-agent-estimator.1 +214 -0
  95. package/dst/man/ase-agent-fleet.1 +185 -0
  96. package/dst/man/ase-agent-implementer.1 +233 -0
  97. package/dst/man/ase-agent-integrator.1 +213 -0
  98. package/dst/man/ase-agent-qualifier.1 +214 -0
  99. package/dst/man/ase-agent-rebooter.1 +193 -0
  100. package/dst/man/ase-agent-relay.1 +128 -0
  101. package/dst/man/ase-agent-researcher.1 +217 -0
  102. package/dst/man/ase-agent.1 +264 -0
  103. package/dst/man/ase-artifact-list.1 +38 -0
  104. package/dst/man/ase-artifact-name.1 +39 -0
  105. package/dst/man/ase-artifact.1 +56 -0
  106. package/dst/man/ase-config-delete.1 +45 -0
  107. package/dst/man/ase-config-edit.1 +48 -0
  108. package/dst/man/ase-config-get.1 +46 -0
  109. package/dst/man/ase-config-init.1 +60 -0
  110. package/dst/man/ase-config-list.1 +42 -0
  111. package/dst/man/ase-config-set.1 +52 -0
  112. package/dst/man/ase-config.1 +225 -0
  113. package/dst/man/ase-hook-permission-request.1 +36 -0
  114. package/dst/man/ase-hook-pre-tool-use.1 +59 -0
  115. package/dst/man/ase-hook-session-end.1 +47 -0
  116. package/dst/man/ase-hook-session-persona.1 +37 -0
  117. package/dst/man/ase-hook-session-start.1 +81 -0
  118. package/dst/man/ase-hook-stop.1 +34 -0
  119. package/dst/man/ase-hook-user-prompt-submit.1 +34 -0
  120. package/dst/man/ase-hook.1 +51 -0
  121. package/dst/man/ase-man.1 +67 -0
  122. package/dst/man/ase-mcp.1 +61 -0
  123. package/dst/man/ase-service-log.1 +43 -0
  124. package/dst/man/ase-service-send.1 +47 -0
  125. package/dst/man/ase-service-start.1 +54 -0
  126. package/dst/man/ase-service-status.1 +46 -0
  127. package/dst/man/ase-service-stop.1 +37 -0
  128. package/dst/man/ase-service.1 +85 -0
  129. package/dst/man/ase-setup-disable.1 +44 -0
  130. package/dst/man/ase-setup-enable.1 +45 -0
  131. package/dst/man/ase-setup-install.1 +73 -0
  132. package/dst/man/ase-setup-mcp.1 +124 -0
  133. package/dst/man/ase-setup-status.1 +60 -0
  134. package/dst/man/ase-setup-statusline.1 +92 -0
  135. package/dst/man/ase-setup-telemetry.1 +92 -0
  136. package/dst/man/ase-setup-uninstall.1 +59 -0
  137. package/dst/man/ase-setup-update.1 +64 -0
  138. package/dst/man/ase-setup.1 +93 -0
  139. package/dst/man/ase-spec-export.1 +62 -0
  140. package/dst/man/ase-spec-lint.1 +40 -0
  141. package/dst/man/ase-spec-preview.1 +40 -0
  142. package/dst/man/ase-spec.1 +46 -0
  143. package/dst/man/ase-statusline.1 +189 -0
  144. package/dst/man/ase-task-assign.1 +71 -0
  145. package/dst/man/ase-task-board.1 +384 -0
  146. package/dst/man/ase-task-delete.1 +35 -0
  147. package/dst/man/ase-task-edit.1 +46 -0
  148. package/dst/man/ase-task-idscheme.1 +65 -0
  149. package/dst/man/ase-task-lifecycle.1 +57 -0
  150. package/dst/man/ase-task-list.1 +47 -0
  151. package/dst/man/ase-task-load.1 +36 -0
  152. package/dst/man/ase-task-newid.1 +61 -0
  153. package/dst/man/ase-task-purge.1 +37 -0
  154. package/dst/man/ase-task-rename.1 +44 -0
  155. package/dst/man/ase-task-request.1 +61 -0
  156. package/dst/man/ase-task-save.1 +48 -0
  157. package/dst/man/ase-task-status.1 +55 -0
  158. package/dst/man/ase-task-store.1 +194 -0
  159. package/dst/man/ase-task-view.1 +40 -0
  160. package/dst/man/ase-task.1 +160 -0
  161. package/dst/man/ase-util-compat.1 +25 -0
  162. package/dst/man/ase-util-diagram.1 +76 -0
  163. package/dst/man/ase-util-meta.1 +45 -0
  164. package/dst/man/ase-util-metric.1 +54 -0
  165. package/dst/man/ase-util-mint.1 +59 -0
  166. package/dst/man/ase-util-worktree.1 +72 -0
  167. package/dst/man/ase-util.1 +50 -0
  168. package/dst/man/ase.1 +124 -0
  169. package/package.json +79 -21
  170. package/plugin/.claude-plugin/plugin.json +1 -1
  171. package/plugin/.codex-plugin/plugin.json +1 -1
  172. package/plugin/.github/plugin/plugin.json +1 -1
  173. package/plugin/agents/ase-meta-diagram.md +12 -8
  174. package/plugin/agents/ase-repo-review.md +322 -0
  175. package/plugin/hooks/hooks-codex.json +5 -0
  176. package/plugin/hooks/hooks-copilot.json +5 -0
  177. package/plugin/hooks/hooks.json +8 -0
  178. package/plugin/meta/ase-common-approach.md +117 -0
  179. package/plugin/meta/ase-common-changeset.md +256 -0
  180. package/plugin/meta/ase-common-code.md +10 -173
  181. package/plugin/meta/ase-common-grill.md +317 -0
  182. package/plugin/meta/ase-common-resolve.md +305 -0
  183. package/plugin/meta/ase-common-task.md +83 -4
  184. package/plugin/meta/ase-constitution.md +0 -2
  185. package/plugin/meta/ase-format-specbook.md +208 -25
  186. package/plugin/meta/ase-format-specbook.yaml +242 -851
  187. package/plugin/meta/ase-format-task.md +669 -125
  188. package/plugin/meta/ase-persona.md +3 -4
  189. package/plugin/meta/ase-skill.md +9 -0
  190. package/plugin/mods/ase-mods.ts +409 -0
  191. package/plugin/mods/claude-code.d.ts +13417 -0
  192. package/plugin/skills/ase-arch-analyze/SKILL.md +1 -1
  193. package/plugin/skills/ase-arch-analyze/help.md +2 -2
  194. package/plugin/skills/ase-code-analyze/SKILL.md +59 -8
  195. package/plugin/skills/ase-code-analyze/help.md +29 -4
  196. package/plugin/skills/ase-code-edit/SKILL.md +107 -181
  197. package/plugin/skills/ase-code-edit/help.md +118 -31
  198. package/plugin/skills/ase-code-lint/SKILL.md +64 -13
  199. package/plugin/skills/ase-code-lint/help.md +32 -2
  200. package/plugin/skills/ase-docs-proofread/SKILL.md +4 -4
  201. package/plugin/skills/ase-docs-proofread/help.md +1 -1
  202. package/plugin/skills/ase-docs-refine/SKILL.md +4 -4
  203. package/plugin/skills/ase-docs-shorten/SKILL.md +4 -4
  204. package/plugin/skills/ase-help-intent/data.md +2164 -1087
  205. package/plugin/skills/ase-help-intent/help.md +1 -1
  206. package/plugin/skills/ase-help-skill/catalog.md +12 -9
  207. package/plugin/skills/ase-meta-brainstorm/SKILL.md +1 -1
  208. package/plugin/skills/ase-meta-config/SKILL.md +3 -4
  209. package/plugin/skills/ase-meta-config/help.md +31 -10
  210. package/plugin/skills/ase-meta-mint/SKILL.md +5 -5
  211. package/plugin/skills/ase-meta-mint/help.md +10 -5
  212. package/plugin/skills/ase-meta-why/help.md +1 -1
  213. package/plugin/skills/ase-meta-workflow/SKILL.md +7 -7
  214. package/plugin/skills/ase-meta-workflow/help.md +4 -4
  215. package/plugin/skills/ase-meta-workflow/sample.md +3 -3
  216. package/plugin/skills/ase-meta-workflow/workflow.txt +22 -18
  217. package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/SKILL.md +4 -3
  218. package/plugin/skills/{ase-meta-changelog → ase-repo-changelog}/help.md +5 -5
  219. package/plugin/skills/{ase-meta-commit → ase-repo-commit}/SKILL.md +6 -6
  220. package/plugin/skills/{ase-meta-commit → ase-repo-commit}/help.md +5 -5
  221. package/plugin/skills/{ase-meta-diff → ase-repo-diff}/SKILL.md +6 -6
  222. package/plugin/skills/{ase-meta-diff → ase-repo-diff}/help.md +8 -8
  223. package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/SKILL.md +19 -19
  224. package/plugin/skills/{ase-code-dissect → ase-repo-dissect}/help.md +10 -12
  225. package/plugin/skills/ase-repo-merge/SKILL.md +346 -0
  226. package/plugin/skills/ase-repo-merge/help.md +107 -0
  227. package/plugin/skills/ase-repo-resolve/SKILL.md +158 -0
  228. package/plugin/skills/ase-repo-resolve/help.md +102 -0
  229. package/plugin/skills/ase-repo-review/SKILL.md +406 -0
  230. package/plugin/skills/ase-repo-review/help.md +181 -0
  231. package/plugin/skills/ase-spec-edit/SKILL.md +117 -183
  232. package/plugin/skills/ase-spec-edit/help.md +107 -26
  233. package/plugin/skills/ase-sync-reconcile/help.md +1 -1
  234. package/plugin/skills/ase-task-assign/SKILL.md +111 -0
  235. package/plugin/skills/ase-task-assign/help.md +119 -0
  236. package/plugin/skills/ase-task-condense/SKILL.md +21 -21
  237. package/plugin/skills/ase-task-condense/help.md +12 -10
  238. package/plugin/skills/ase-task-delete/SKILL.md +1 -1
  239. package/plugin/skills/ase-task-dissect/SKILL.md +71 -48
  240. package/plugin/skills/ase-task-dissect/help.md +10 -9
  241. package/plugin/skills/ase-task-edit/SKILL.md +379 -94
  242. package/plugin/skills/ase-task-edit/help.md +95 -22
  243. package/plugin/skills/ase-task-estimate/SKILL.md +492 -0
  244. package/plugin/skills/ase-task-estimate/help.md +158 -0
  245. package/plugin/skills/ase-task-grill/SKILL.md +246 -138
  246. package/plugin/skills/ase-task-grill/help.md +129 -26
  247. package/plugin/skills/ase-task-id/SKILL.md +8 -1
  248. package/plugin/skills/ase-task-id/help.md +6 -3
  249. package/plugin/skills/ase-task-implement/SKILL.md +535 -145
  250. package/plugin/skills/ase-task-implement/help.md +138 -47
  251. package/plugin/skills/ase-task-integrate/SKILL.md +549 -0
  252. package/plugin/skills/ase-task-integrate/help.md +187 -0
  253. package/plugin/skills/ase-task-list/SKILL.md +55 -23
  254. package/plugin/skills/ase-task-list/help.md +45 -21
  255. package/plugin/skills/ase-task-reboot/SKILL.md +84 -43
  256. package/plugin/skills/ase-task-reboot/help.md +28 -8
  257. package/plugin/skills/ase-task-rename/SKILL.md +10 -2
  258. package/plugin/skills/ase-task-research/SKILL.md +386 -0
  259. package/plugin/skills/ase-task-research/help.md +102 -0
  260. package/plugin/skills/ase-task-status/SKILL.md +137 -0
  261. package/plugin/skills/ase-task-status/help.md +80 -0
  262. package/plugin/skills/ase-task-view/SKILL.md +49 -24
  263. package/plugin/skills/ase-task-view/help.md +19 -9
  264. package/plugin/agents/ase-meta-review.md +0 -187
  265. package/plugin/skills/ase-code-craft/SKILL.md +0 -264
  266. package/plugin/skills/ase-code-craft/help.md +0 -122
  267. package/plugin/skills/ase-code-refactor/SKILL.md +0 -232
  268. package/plugin/skills/ase-code-refactor/help.md +0 -109
  269. package/plugin/skills/ase-code-resolve/SKILL.md +0 -289
  270. package/plugin/skills/ase-code-resolve/help.md +0 -116
  271. package/plugin/skills/ase-meta-review/SKILL.md +0 -210
  272. package/plugin/skills/ase-meta-review/help.md +0 -96
  273. package/plugin/skills/ase-task-preflight/SKILL.md +0 -166
  274. package/plugin/skills/ase-task-preflight/help.md +0 -82
  275. /package/dst/{ase-ignore.js → ase-lib-ignore.js} +0 -0
  276. /package/dst/{ase-stdio.js → ase-lib-stdio.js} +0 -0
  277. /package/dst/{ase-kv.js → ase-service-kv.js} +0 -0
  278. /package/dst/{ase-sleep.js → ase-service-sleep.js} +0 -0
  279. /package/dst/{ase-timestamp.js → ase-service-timestamp.js} +0 -0
@@ -8,23 +8,55 @@
8
8
  `ase-task-edit`
9
9
  [`--help`|`-h`]
10
10
  [`--plan`|`-p` *option*]
11
- [`--dry`|`-d`]
11
+ [`--mode`|`-m` `auto`|`craft`|`refactor`|`resolve`|`specify`]
12
+ [`--approach`|`-a`]
13
+ [`--unverified`|`-u`]
12
14
  [`--next`|`-n` *option*[,...]]
13
- [*id* | *id*: *instruction* | *instruction*]
15
+ [*id* | *id*: *instruction* | *instruction* | *issue-id*]
14
16
 
15
17
  ## DESCRIPTION
16
18
 
17
19
  The `ase-task-edit` skill establishes and refines a *task plan* purely
18
20
  through a *chat-driven loop*. The user steers each round via an
19
21
  interactive dialog that offers continued refinement, finalization, or
20
- hand-off to implementation or preflight.
21
-
22
- When a refinement changes the plan text while an `IMPLEMENTATION
23
- DRAFT` section (produced by `ase-task-preflight`) exists, that section
24
- became *stale* and is *removed* -- together with the `preflighted`
25
- value of the `Properties:` frontmatter key -- and a hint is emitted
26
- that `ase-task-preflight` has to be run again to re-create the draft
27
- for the changed plan.
22
+ hand-off to implementation or draft. It covers the planning of all
23
+ kinds of change: crafting a new feature, refactoring the code base,
24
+ resolving a problem, and specifying.
25
+
26
+ A newly generated plan is grounded in the relevant specification
27
+ (`SPEC`), source code (`CODE`), and infrastructure (`INFR`) files of the
28
+ project: it names the actual files and symbols to change, the actual
29
+ build, lint, and test procedures, and a `CHANGELOG.md` entry if such a
30
+ file exists.
31
+
32
+ Before a new plan is generated, the skill determines its *kind of
33
+ change* (stored in the `Kind:` key of the plan) and internalizes the
34
+ corresponding tenets (for example KISS, YAGNI, and DRY for crafting,
35
+ or Surgical Changes and Origin Proximity for resolving). For a
36
+ resolution, it first reports the `PROBLEM CONTEXT` and `PROBLEM
37
+ DETAILS`. Under `--approach`, it then proposes one or more *approaches*
38
+ with pros and cons, recommends one of them, and lets the user pick the
39
+ preferred one via an interactive dialog, and the new plan is then
40
+ composed along the chosen approach.
41
+
42
+ If the current task is `default` and a new plan is generated from an
43
+ *instruction*, a new task id is allocated from the instruction
44
+ according to the task id scheme of the project, so the plan does not
45
+ end up under `default`.
46
+
47
+ Attachments in the plan's backmatter are never removed by a refinement.
48
+ A refinement which changes an attachment refreshes the attachment's
49
+ `Modified:` key; a refinement which changes the plan body refreshes the
50
+ `Modified:` key of the frontmatter (which tracks body changes only, so
51
+ a refinement of frontmatter keys alone leaves it untouched); both use
52
+ the same value. An implementation draft (an attachment block of type
53
+ `text/x-diff; charset=utf-8; kind="draft"`, produced by
54
+ `ase-task-implement --draft`) whose `Modified:` key is absent or older
55
+ than the frontmatter's is *stale*: it is reported with a warning after
56
+ each rendering of the plan, together with a hint that
57
+ `ase-task-implement --draft` has to be run again to re-create the
58
+ draft for the changed plan, as `ase-task-integrate --draft` refuses a
59
+ stale draft.
28
60
 
29
61
  ## OPTIONS
30
62
 
@@ -36,8 +68,27 @@ for the changed plan.
36
68
  *instruction*), or `PRESERVE` (preserve the existing plan by
37
69
  ignoring *instruction* and stopping skill processing).
38
70
 
39
- - `--dry`|`-d`:
40
- Generate any *new* plan *without* the `## VERIFICATION` section.
71
+ - `--mode`|`-m` `auto`|`craft`|`refactor`|`resolve`|`specify`:
72
+ Select the kind of change of the plan: `craft` (`CRAFTING`),
73
+ `refactor` (`REFACTORING`), `resolve` (`RESOLVING`), or `specify`
74
+ (`SPECIFYING`). It selects the tenets internalized when the plan is
75
+ generated or refined and sets the `Kind:` key of the plan, also on
76
+ a refinement. The default `auto` infers the kind of a new plan from
77
+ the *instruction*, uses `RESOLVING` for an *issue-id* (also on a
78
+ refinement), and otherwise leaves the `Kind:` key of an existing
79
+ plan as it is and honors its tenets.
80
+
81
+ - `--approach`|`-a`:
82
+ Before a new plan is composed, propose one or more crafting,
83
+ refactoring, resolution, or specification approaches with pros and
84
+ cons, recommend one of them, and let the user pick the preferred one
85
+ via an interactive dialog (or, under the `black` project boxing or
86
+ in headless mode, automatically pick the recommended one). The new
87
+ plan is then composed along the chosen approach. Without
88
+ `--approach`, no approaches are determined at all.
89
+
90
+ - `--unverified`|`-u`:
91
+ Generate any *new* plan *without* the `## VERIFICATION (WHEN)` section.
41
92
  Applies only to freshly generated plans, not to existing plans
42
93
  loaded from disk. When `ase-task-implement` later applies such
43
94
  a plan, it strictly skips the entire verification phase (no
@@ -49,28 +100,36 @@ for the changed plan.
49
100
  of this skill). *option* is a single token or a *comma-separated
50
101
  chronological list* of tokens; each iteration of the planning
51
102
  loop consumes the *first* token of the list, and on hand-off
52
- (`IMPLEMENT` / `PREFLIGHT`) any remaining tokens are *forwarded*
103
+ (`IMPLEMENT` / `DRAFT`) any remaining tokens are *forwarded*
53
104
  (via `--next`) to the downstream skill so an entire pipeline can
54
105
  be pre-scripted in one shot. Recognized tokens at this skill:
55
106
  `none` (default, interactive answer required), `DONE` (no next
56
- step), `GRILL` (hand-over to `ase-task-grill`), `PREFLIGHT`
57
- (hand-over to `ase-task-preflight`), or `IMPLEMENT` (hand-over to
107
+ step), `GRILL` (hand-over to `ase-task-grill`), `DRAFT`
108
+ (hand-over to `ase-task-implement --draft`), or `IMPLEMENT` (hand-over to
58
109
  `ase-task-implement`). Example: `--next GRILL,DONE` hands the plan
59
110
  off to grilling and forwards `DONE` so grilling exits without asking.
60
111
 
61
112
  ## ARGUMENTS
62
113
 
63
- - *id* | *id*: *instruction* | *instruction*:
64
- Edit the task with the unique identifier *id* (default: `default`).
65
- Optionally, *instruction* either gives instructions for creating a
66
- new task or gives instructions for refining an existing task.
114
+ - *id* | *id*: *instruction* | *instruction* | *issue-id*:
115
+ Edit the task with the unique identifier *id* (default: the current
116
+ task). Optionally, *instruction* either gives instructions for
117
+ creating a new task or gives instructions for refining an existing
118
+ task. Instead, a bare *issue-id* (like `P1`, `T1`, or
119
+ `<prefix>-P1`), previously reported by `ase-code-analyze` or
120
+ `ase-arch-analyze`, uses the description of this issue as the
121
+ *instruction* (also as *id*: *issue-id*), and the issue is removed
122
+ once the plan is saved. If no such issue exists, *issue-id* is
123
+ treated as a task *id* resp. as an *instruction*.
67
124
 
68
125
  ## SCENARIOS
69
126
 
70
127
  - You want a task planned through chat-driven refinement
71
128
  - You want a plan created or refined round by round
72
- - You want a plan iterated on before implementing it
73
- - You want plan refinement with hand-off to preflight or implementation
129
+ - You want approaches with pros and cons before a plan is composed
130
+ - You want a plan to craft a feature, refactor code, or resolve a problem
131
+ - You want an analyzer issue like `P1` turned into a plan
132
+ - You want plan refinement with hand-off to draft or implementation
74
133
 
75
134
  ## EXAMPLES
76
135
 
@@ -94,7 +153,21 @@ Further refine the task under id `hello`:
94
153
  ❯ /ase-task-edit hello: change the color to red.
95
154
  ```
96
155
 
156
+ Plan the resolution of the analyzer issue `P1` along an interactively
157
+ chosen approach, and directly hand off to implementation:
158
+
159
+ ```text
160
+ ❯ /ase-task-edit --approach --next IMPLEMENT P1
161
+ ```
162
+
163
+ Plan a refactoring under the id `cleanup`:
164
+
165
+ ```text
166
+ ❯ /ase-task-edit -m refactor cleanup: extract HTTP client into its own class
167
+ ```
168
+
97
169
  ## SEE ALSO
98
170
 
99
- [`ase-task-reboot`](../ase-task-reboot/help.md), [`ase-task-preflight`](../ase-task-preflight/help.md), [`ase-task-implement`](../ase-task-implement/help.md),
171
+ [`ase-code-edit`](../ase-code-edit/help.md), [`ase-spec-edit`](../ase-spec-edit/help.md), [`ase-task-grill`](../ase-task-grill/help.md),
172
+ [`ase-task-reboot`](../ase-task-reboot/help.md), [`ase-task-implement`](../ase-task-implement/help.md),
100
173
  [`ase-task-view`](../ase-task-view/help.md), [`ase-task-list`](../ase-task-list/help.md), [`ase-task-rename`](../ase-task-rename/help.md), [`ase-task-delete`](../ase-task-delete/help.md).
@@ -0,0 +1,492 @@
1
+ ---
2
+ name: ase-task-estimate
3
+ argument-hint: "[--help|-h] [--force|-f] [--dry-run|-d] [--all|-a] [--calibrate|-c [--save|-s]] [<id> ...]"
4
+ description: >
5
+ Estimate the effort of the current, given, or all unestimated task
6
+ plans as T-shirt sizes (XS, S, M, L, XL) of expected human time, and
7
+ store it in the "Effort:" frontmatter key, or calibrate the estimation
8
+ against the actual human time of the finished tasks. Use when the user
9
+ wants to "estimate", "size", or "gauge the effort" of a "task" or
10
+ "plan", or to "calibrate" the effort estimation.
11
+ user-invocable: true
12
+ disable-model-invocation: false
13
+ effort: high
14
+ ---
15
+
16
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-control.md
17
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-skill.md
18
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-getopt.md
19
+
20
+ <purpose name="ase-task-estimate">
21
+ Estimate the Effort of a Task Plan
22
+ </purpose>
23
+
24
+ <expand name="getopt"
25
+ arg1="ase-task-estimate"
26
+ arg2="--force|-f --dry-run|-d --all|-a --calibrate|-c --save|-s">
27
+ $ARGUMENTS
28
+ </expand>
29
+
30
+ <objective>
31
+ *Estimate* the effort of task plans as T-shirt sizes of expected human time.
32
+ </objective>
33
+
34
+ @${CLAUDE_SKILL_DIR}/../../meta/ase-format-task.md
35
+
36
+ Procedure
37
+ ---------
38
+
39
+ <define name="effort-scores">
40
+
41
+ Derive the *scores* of the plan <plan/> (the body only, never the
42
+ frontmatter or backmatter), skipping every bullet-point in the *inert*
43
+ checkbox states `[-]` and `[>]` entirely, while all other checkbox
44
+ states (including `[x]`, as the effort covers the *entire* lifecycle of
45
+ the task) count alike. A bullet-point *without* a type (like in a
46
+ legacy plan) counts with the types following from its section: `DOM`
47
+ or `IFC` for a context or specification section (but *nothing* for a
48
+ pure rationale like a *why*), `ARC` or `IMP` for a changes or design
49
+ section, and `REG` or `CON` for a verification section. Do not output
50
+ anything.
51
+
52
+ 1. *Attention score*: set <attention/> to the sum of the weights of all
53
+ counted bullet-points, with the weights `DOM` 5.0, `IFC` 4.0, `ARC`
54
+ 3.0, `IMP` 1.0, `REG` 0.5, and `CON` 1.0, each *multiplied* by the
55
+ *item count* of the bullet-point: the number of *distinct*
56
+ requirements, behaviors, or changes it states (at least `1`), like
57
+ one per independent statement or per enumerated element, so a dense
58
+ bullet-point stating ten key bindings counts ten times, while a
59
+ bullet-point stating a single fact counts once. Set
60
+ <minutes-attention/> to <attention/> times <factor/>.
61
+
62
+ 2. *Volume score*: *predict* the code impact of the counted `ARC` and
63
+ `IMP` bullet-points *strictly read-only* from the plan and the code
64
+ base (never change, stage, or commit anything), *disregarding* any
65
+ already existing change set of the task (its uncommitted changes,
66
+ its branch, or its change set attachment): *never* measure the
67
+ volume from such a change set, so estimations before and after the
68
+ implementation stay comparable. Set <files/> to the number of files
69
+ they touch (or create) -- the files named by the bullet-points
70
+ *plus* the files following from them, like call sites,
71
+ documentation, manual pages, and generated catalogs -- and <lines/>
72
+ to the estimated number of changed lines, sizing new files after
73
+ comparable existing ones and changes after the code they touch, and
74
+ <new-lines/> to the part of <lines/> in newly created files. Set
75
+ <minutes-volume/> to <files/> times <file-minutes/> plus <lines/>
76
+ plus twice <new-lines/> times <line-minutes/>, so a newly written
77
+ line weighs *three* times a changed one. As a plan describes the
78
+ straightforward path only, while the edge cases, the error
79
+ handling, and the polishing of the realization regularly multiply
80
+ its size, <line-minutes/> already covers this growth, hence do
81
+ *not* inflate the predicted lines themselves.
82
+
83
+ 3. *Base size*: set <minutes/> to <minutes-attention/> plus
84
+ <minutes-volume/>, and set <size/> to the *smallest* size of `XS`,
85
+ `S`, `M`, and `L` whose upper band bound in <scale/> is greater than
86
+ or equal to <minutes/>, or to `XL` if <minutes/> exceeds all bounds.
87
+
88
+ </define>
89
+
90
+ 1. **Determine Operation:**
91
+
92
+ 1. Set <ids/> to the whitespace-separated tokens of
93
+ <getopt-arguments/>, each with a trailing `:` removed. Inherit
94
+ the always existing <ase-task-id/>, <ase-session-id/>,
95
+ <ase-project-task-lifecycle/>, and <ase-project-boxing/> from the
96
+ current context. Do not output anything.
97
+
98
+ 2. Validate the arguments and options:
99
+
100
+ - If a token <token/> of <ids/> does *not* match the regexp
101
+ `^[a-zA-Z0-9#][a-zA-Z0-9#_-]*$`, only output the following
102
+ <template/> and then immediately *STOP* processing the entire
103
+ current skill:
104
+
105
+ <template>
106
+ ⧉ **ASE**: ☻ skill: **ase-task-estimate**, ▶ ERROR: invalid task id: **<token/>**
107
+ </template>
108
+
109
+ - If <getopt-option-all/> is `true` and <ids/> is *not* empty,
110
+ only output the following <template/> and then immediately
111
+ *STOP* processing the entire current skill:
112
+
113
+ <template>
114
+ ⧉ **ASE**: ☻ skill: **ase-task-estimate**, ▶ ERROR: option `--all` takes no task ids
115
+ </template>
116
+
117
+ - If <getopt-option-calibrate/> is `true` and <ids/> is *not*
118
+ empty or any of <getopt-option-all/>, <getopt-option-force/>,
119
+ and <getopt-option-dry-run/> is `true`, only output the
120
+ following <template/> and then immediately *STOP* processing
121
+ the entire current skill:
122
+
123
+ <template>
124
+ ⧉ **ASE**: ☻ skill: **ase-task-estimate**, ▶ ERROR: option `--calibrate` takes no task ids and excludes `--all`, `--force`, and `--dry-run`
125
+ </template>
126
+
127
+ - If <getopt-option-save/> is `true` and
128
+ <getopt-option-calibrate/> is *not* `true`, only output the
129
+ following <template/> and then immediately *STOP* processing
130
+ the entire current skill:
131
+
132
+ <template>
133
+ ⧉ **ASE**: ☻ skill: **ase-task-estimate**, ▶ ERROR: option `--save` requires `--calibrate`
134
+ </template>
135
+
136
+ 3. Determine the *estimation configuration*: for each of the keys
137
+ `project.task.effort.scale`, `project.task.effort.factor`,
138
+ `project.task.effort.file`, `project.task.effort.line`, and
139
+ `project.task.effort.iteration`, call the `ase_config_get(key:
140
+ "<key/>", scope: "project")` tool of the `ase` MCP server and
141
+ JSON-decode its `text` output field. Set <scale/> to the four
142
+ comma-separated upper band bounds of `XS` to `L` (default:
143
+ `15,60,240,960`), <factor/> to the human minutes per
144
+ attention-score point (default: `1`), <file-minutes/> to the
145
+ human review minutes per touched file (default: `1`),
146
+ <line-minutes/> to the human minutes per predicted changed line
147
+ (default: `0.025`), and <iteration-factor/> to the iteration
148
+ multiplier of interactive user interfaces (default: `2.5`), each
149
+ falling back to its default if empty or malformed. Do not
150
+ output anything.
151
+
152
+ 4. Determine the *finished states* <finished-states/> and the
153
+ *successful finished state* <success-state/> of the task lifecycle
154
+ model <ase-project-task-lifecycle/>: `CLOSED` and `CANCELLED`
155
+ resp. `CLOSED` for `solo` (or absent), `IMPLEMENTED` and
156
+ `CANCELLED` resp. `IMPLEMENTED` for `team`, and `INTEGRATED` and
157
+ `CANCELLED` resp. `INTEGRATED` for `enterprise`. Do not output
158
+ anything.
159
+
160
+ 5. <if condition="<getopt-option-calibrate/> is `true`">
161
+ Skip step 2 and continue with step 3.
162
+ </if>
163
+
164
+ 2. **Estimate Task Plans:**
165
+
166
+ 1. Determine the tasks <tasks/> to estimate:
167
+
168
+ - If <getopt-option-all/> is `true`: call the
169
+ `ase_task_list(verbose: true)` tool of the `ase` MCP server and
170
+ set <tasks/> to the `id` of every entry of its `tasks` array
171
+ whose `status` is *not* in <finished-states/> and -- unless
172
+ <getopt-option-force/> is `true` -- whose `effort` is empty.
173
+
174
+ - Else, if <ids/> is not empty: set <tasks><ids/></tasks>.
175
+
176
+ - Else: set <tasks><ase-task-id/></tasks>.
177
+
178
+ <if condition="<tasks/> is empty">
179
+ Only output the following <template/> and then *STOP* processing
180
+ the entire current skill:
181
+
182
+ <template>
183
+ ⧉ **ASE**: ◉ tasks: *(none)*, ▶ status: **nothing to estimate**
184
+ </template>
185
+ </if>
186
+
187
+ 2. Set <analogues/> to the *analogues* for cross-checking: call the
188
+ `ase_task_list(verbose: true)` tool of the `ase` MCP server (or
189
+ reuse its result of sub-step 1), take every entry whose `status`
190
+ is <success-state/> and whose `effort` is *not* empty, and pick
191
+ up to *five* of them whose title is most similar to the tasks of
192
+ <tasks/>. For each picked one, call the `ase_task_attachment(id:
193
+ "<id/>", type: "application/yaml; kind=\"usage\"")` tool of the
194
+ `ase` MCP server, and keep it only if it carries a usage
195
+ attachment (a `WARNING:` response means none), whose YAML payload
196
+ `time: { ai, hr, real }` carries a `hr` of at least `5` minutes, together
197
+ with its `effort` size and the size whose band covers its
198
+ `time.hr` (its *actual* size). Do not output anything.
199
+
200
+ 3. For each task id <id/> of <tasks/>, perform the following
201
+ *per-task workflow*, where a failing task never stops the
202
+ processing of the remaining tasks:
203
+
204
+ 1. *Load*: call the `ase_task_load(id: "<id/>", tag: true)` tool
205
+ of the `ase` MCP server -- with the `variant` argument
206
+ defaulting to `source` and the `attachments` argument
207
+ defaulting to `elided` -- and set <plan/> to its `text`
208
+ output field without the trailing `<task-plan-tag>`
209
+ delimiter line, and <tag/> to the content of that line.
210
+
211
+ - If <plan/> is empty, set <status>skipped: no plan</status>
212
+ and continue with sub-step 5.
213
+
214
+ - If the `Group:` frontmatter key of <plan/> equals its
215
+ `Id:` key (an *explicit epic*), set <status>skipped:
216
+ epic</status> and continue with sub-step 5.
217
+
218
+ - If <plan/> carries an `Effort:` frontmatter key (which the
219
+ task store only delivers if it is *valid*) and
220
+ <getopt-option-force/> is *not* `true`, set <size/> to its
221
+ size and <status>skipped: already estimated</status> and
222
+ continue with sub-step 5.
223
+
224
+ 2. *Score*: derive the scores of <plan/>:
225
+
226
+ <expand name="effort-scores"></expand>
227
+
228
+ 3. *Adjust*:
229
+
230
+ - *Risk surcharge*: determine which of the risks `dependency`
231
+ (a new or upgraded third-party dependency or external
232
+ service), `ambiguity` (bullet-points in state `[?]` or
233
+ vague, underspecified wording), `untested` (changed code
234
+ without an automated test procedure covering it),
235
+ `concurrency` (parallelism, locking, or race conditions),
236
+ `security` (authentication, authorization, secrets, or
237
+ untrusted input), and `persistence` (data formats,
238
+ migrations, or stored state) apply to <plan/>. There is
239
+ *no* `architecture` risk, as the `ARC` weight already
240
+ covers it, and a risk applying to virtually *every* task
241
+ of the project (like `untested` in a project without any
242
+ automated test procedure) does *not* count, as the
243
+ calibrated rates already absorb it. Set <surcharge/> to
244
+ `20` percent per applying risk, but at most `40` percent
245
+ in total, and raise <minutes/> by <surcharge/> percent.
246
+
247
+ - *Iteration multiplier*: if the *main* deliverable of
248
+ <plan/> is an *interactive* or *visual* user interface
249
+ (like a terminal UI, a web UI, a layout, or a rendering
250
+ with key or pointer handling) which is built or
251
+ substantially reworked, set <iteration/> to
252
+ <iteration-factor/>, as
253
+ such work regularly needs many rounds of post-adjustment
254
+ which no plan foresees; else set <iteration/> to `1`. A
255
+ mere display detail of an existing interface (like an
256
+ additional badge or column) does *not* count. Multiply
257
+ <minutes/> by <iteration/> -- *outside* the cap of the
258
+ risk surcharge -- and re-determine <size/> from the
259
+ resulting <minutes/> like the base size.
260
+
261
+ - *Plausibility*: if the code base already contains a
262
+ *comparable* realization of the planned functionality
263
+ (but *never* the change set of the task itself, see the
264
+ volume score), set <reference/> to its size in lines and
265
+ consider the prediction *implausible* if <lines/> and
266
+ <reference/> differ by a factor of at least `2`. A
267
+ reference *never* changes <size/> itself.
268
+
269
+ - *Confidence*: set <confidence/> to `HIGH`. Lower it by
270
+ one level (`HIGH` to `MEDIUM` to `LOW`) if the `ambiguity`
271
+ risk applies, by one level if the prediction is
272
+ implausible, and by one level if <analogues/> is empty or
273
+ if the analogues of comparable scope disagree with <size/>
274
+ (their actual size differs from <size/> by at least one
275
+ band), and by two levels if they disagree by at least two
276
+ bands, but never below `LOW`. The analogues *never*
277
+ change <size/> itself.
278
+
279
+ - *Drivers*: set <drivers/> to the 2-4 main drivers of the
280
+ estimation (like the dominant bullet-point types, the
281
+ code volume, the applying risks, the iteration
282
+ multiplier, an implausible prediction, or the analogues),
283
+ each as an ultra brief phrase.
284
+
285
+ 4. *Persist*: <if condition="<getopt-option-dry-run/> is `true`">
286
+ set <status>estimated (dry-run, not stored)</status>.
287
+ </if>
288
+ <else>
289
+ Set the `Effort:` frontmatter key of <plan/> to *just*
290
+ <size/> -- *without* any content hash, as the task store
291
+ stamps it on save -- replacing an already present `Effort:`
292
+ key, or *creating* it at its position in the key order of the
293
+ plan <format/> (directly after `Kind:` resp. before `Tags:`).
294
+ Change *nothing else* of <plan/>: especially, do *not*
295
+ refresh the `Modified:` key (an effort is no body change), do
296
+ *not* change the `Status:` key, and pass the entire
297
+ backmatter through *verbatim* (with its elided `Data`
298
+ markers). Call the `ase_task_save(id: "<id/>", text:
299
+ "<plan/>", base: "<tag/>")` tool of the `ase` MCP server, so
300
+ the save is refused if the plan was changed meanwhile by
301
+ anybody else. This `ase_task_save` MCP tool call is the
302
+ *only* permitted way to persist the plan -- *NEVER* write the
303
+ plan file via `Write`/`Edit` or by executing a shell command.
304
+
305
+ - On success, set <status>effort estimated</status>.
306
+
307
+ - If the save is refused because the plan was *changed*
308
+ meanwhile, *reload* and *re-estimate* the task by
309
+ restarting the per-task workflow at sub-step 1, at most
310
+ *three* times in total, and afterwards set <status>failed:
311
+ plan changed concurrently</status>.
312
+
313
+ - On any other error <info/>, set <status>failed:
314
+ <info/></status>.
315
+ </else>
316
+
317
+ 5. *Report*: <if condition="<status/> starts with `skipped` or `failed`">
318
+ only output the following <template/>:
319
+
320
+ <template>
321
+ ⧉ **ASE**: ◉ task: **<id/>**, ▶ status: **<status/>**
322
+ </template>
323
+ </if>
324
+ <else>
325
+ only output the following <template/>, where every driver of
326
+ <drivers/> is rendered as its own `○` line -- but *without*
327
+ any driver lines if <ase-project-boxing/> is `black`, and
328
+ with an additional first `○` line `attention <attention/>
329
+ (<minutes-attention/> min), volume <files/> files / <lines/>
330
+ lines (<minutes-volume/> min), risk +<surcharge/>%, iteration
331
+ x<iteration/> (<minutes/> min)` if <ase-project-boxing/> is
332
+ `white`:
333
+
334
+ <template>
335
+ ⧉ **ASE**: ◉ task: **<id/>**, ⚖ effort: **<size/>** (confidence: **<confidence/>**), ▶ status: **<status/>**
336
+ ○ [...]
337
+ </template>
338
+
339
+ <if condition="<size/> is `XL`">
340
+ Directly *after* this <template/>, only output the following
341
+ <template/>:
342
+
343
+ <template>
344
+ ⧉ **ASE**: ◉ task: **<id/>**, ▶ WARNING: effort **XL** is open-ended -- consider splitting the task via `/ase-task-dissect <id/>`
345
+ </template>
346
+ </if>
347
+ </else>
348
+
349
+ 4. <if condition="<tasks/> contains more than one task">
350
+ Only output the following <template/>, where <n-estimated/>,
351
+ <n-skipped/>, and <n-failed/> are the numbers of tasks whose
352
+ <status/> was an estimation, a skip, resp. a failure:
353
+
354
+ <template>
355
+ ⧉ **ASE**: ⚖ estimated: **<n-estimated/>**, skipped: **<n-skipped/>**, failed: **<n-failed/>**
356
+ </template>
357
+ </if>
358
+
359
+ 5. Finally, give the closing hint by expanding the following (which,
360
+ depending on the configured <ase-guidance-level/>, may expand
361
+ into nothing and hence emit no output at all), and then *STOP*
362
+ processing the entire current skill:
363
+
364
+ <if condition="<getopt-option-dry-run/> is `true`">
365
+ <ase-tpl-hint level="normal">
366
+ Run `/ase-task-estimate` again without `--dry-run` to store the estimated effort in the `Effort:` key.
367
+ </ase-tpl-hint>
368
+ </if>
369
+ <elseif condition="a task was skipped as already estimated">
370
+ <ase-tpl-hint level="verbose">
371
+ Use `/ase-task-estimate --force` to re-estimate tasks already carrying a valid effort.
372
+ </ase-tpl-hint>
373
+ </elseif>
374
+
375
+ 3. **Calibrate Estimation:**
376
+
377
+ 1. Call the `ase_task_list(verbose: true)` tool of the `ase` MCP
378
+ server and take every entry whose `status` is <success-state/>
379
+ (a task which reached its intended outcome, unlike a cancelled
380
+ one) and whose `effort` is *not* empty. For each of them, call the
381
+ `ase_task_attachment(id: "<id/>", type: "application/yaml;
382
+ kind=\"usage\"")` tool of the `ase` MCP server and keep the task
383
+ as a *sample* only if it carries a usage attachment (a `WARNING:`
384
+ response means none), whose YAML payload `time: { ai, hr, real }`
385
+ carries a `hr` (the `time.hr`) of at least `5` minutes, as agent-driven tasks book
386
+ little human time. For each sample, set its *actual* size to the
387
+ size whose band in <scale/> covers its `time.hr`. Do not output
388
+ anything.
389
+
390
+ Then *re-score* every sample with the *current* rates, as its
391
+ stored `effort` was estimated with the rates in effect *at that
392
+ time* (which nothing records), so calibrating against it would
393
+ apply an already applied correction again on every repeated
394
+ calibration: call the `ase_task_load(id: "<id/>")` tool of the
395
+ `ase` MCP server, set <plan/> to its `text` output field, and --
396
+ skipping the sample if <plan/> is empty or starts with `ERROR:`
397
+ or `WARNING:` -- derive the scores of <plan/>:
398
+
399
+ <expand name="effort-scores"></expand>
400
+
401
+ Here, predict the volume as of *before* the realization of the
402
+ task, i.e. *never* measure it from the realized code in the code
403
+ base. Then apply the *risk surcharge* and the *iteration
404
+ multiplier* of sub-step 2.3.3 (but not its plausibility,
405
+ confidence, and drivers), and set the *re-scored minutes* of the
406
+ sample to the resulting <minutes/> and its *estimated* size to
407
+ the resulting <size/>. Do not output anything.
408
+
409
+ 2. <if condition="there are fewer than *three* samples">
410
+ Only output the following <template/> and then *STOP* processing
411
+ the entire current skill, leaving the configuration *untouched*:
412
+
413
+ <template>
414
+ ⧉ **ASE**: ⚖ calibration: **<n/>** samples, ▶ WARNING: insufficient data (at least 3 finished tasks with an effort and at least 5 human minutes required)
415
+ </template>
416
+ </if>
417
+
418
+ 3. Determine the calibration figures:
419
+
420
+ - *Band matrix*: the number of samples per pair of estimated
421
+ size (rows `XS` to `XL`) and actual size (columns `XS` to
422
+ `XL`).
423
+
424
+ - *Hit rate*: the percentage of samples whose estimated size
425
+ equals their actual size.
426
+
427
+ - *Bias*: the mean of the band differences (estimated minus
428
+ actual, in bands), where a positive value means
429
+ *overestimation* and a negative one *underestimation*.
430
+
431
+ - *Correction*: <correction/> is the median of `time.hr`
432
+ divided by the re-scored minutes over all samples.
433
+
434
+ - *Fitted rates*: <fitted-factor/>, <fitted-file/>, and
435
+ <fitted-line/> are <factor/>, <file-minutes/>, resp.
436
+ <line-minutes/>, each multiplied by <correction/> and rounded
437
+ to two significant digits, as the best-fitting rates, which
438
+ scale the *entire* estimation (attention and volume)
439
+ proportionally. As the samples are re-scored with the current
440
+ rates, a repeated calibration right after saving the fitted
441
+ rates yields a <correction/> of about `1` and hence
442
+ *converges* instead of compounding.
443
+
444
+ - *Suggested scale*: the bounds of <scale/>, each multiplied by
445
+ <correction/>, rounded to integers -- an *alternative* to the
446
+ fitted rates and a *suggestion* only, which is never stored.
447
+
448
+ Do not output anything.
449
+
450
+ 4. Only output the following <template/>, with the band matrix
451
+ rendered as a Markdown table with aligned column edges:
452
+
453
+ <template>
454
+ <ase-tpl-head title="EFFORT CALIBRATION" subtitle="<n/> samples"/>
455
+
456
+ **Band Matrix** (rows: estimated, columns: actual):
457
+
458
+ | *Est.* | *XS* | *S* | *M* | *L* | *XL* |
459
+ | ------ | ----- | ----- | ----- | ----- | ----- |
460
+ | **XS** | [...] | [...] | [...] | [...] | [...] |
461
+ | [...] | [...] | [...] | [...] | [...] | [...] |
462
+
463
+ ● **Hit Rate**: <hit-rate/>%
464
+ ● **Bias**: <bias/> bands
465
+ ● **Rates**: factor <factor/>, file <file-minutes/>, line <line-minutes/> (current) → factor **<fitted-factor/>**, file **<fitted-file/>**, line **<fitted-line/>** (fitted)
466
+ ● **Scale**: `<scale/>` (current) → `<suggested-scale/>` (suggested alternative)
467
+
468
+ <ase-tpl-foot title="EFFORT CALIBRATION" subtitle="<n/> samples"/>
469
+ </template>
470
+
471
+ 5. <if condition="<getopt-option-save/> is `true`">
472
+ Call the `ase_config_set(key: "<key/>", val: "<val/>", scope:
473
+ "project")` tool of the `ase` MCP server for the <key/>/<val/>
474
+ pairs `project.task.effort.factor`/<fitted-factor/>,
475
+ `project.task.effort.file`/<fitted-file/>, and
476
+ `project.task.effort.line`/<fitted-line/>, and then only output
477
+ the following <template/>:
478
+
479
+ <template>
480
+ ⧉ **ASE**: ⚙ config: `project.task.effort.{factor,file,line}` (scope: `project`): **<fitted-factor/>**, **<fitted-file/>**, **<fitted-line/>**, ▶ status: **rates saved**
481
+ </template>
482
+ </if>
483
+ <else>
484
+ Give the closing hint by expanding the following (which,
485
+ depending on the configured <ase-guidance-level/>, may expand
486
+ into nothing and hence emit no output at all):
487
+
488
+ <ase-tpl-hint level="normal">
489
+ Use `/ase-task-estimate --calibrate --save` to store the fitted rates, or alternatively `/ase-meta-config --scope project set project.task.effort.scale <bounds>` to adopt the suggested scale.
490
+ </ase-tpl-hint>
491
+ </else>
492
+