@astrosheep/keiyaku 4.6.3 → 4.6.6

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 (193) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +47 -11
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +8 -9
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +37 -25
  6. package/build/src/akuma/akuma-observe.d.ts +18 -15
  7. package/build/src/akuma/akuma-observe.js +75 -16
  8. package/build/src/akuma/akuma-wait.d.ts +4 -3
  9. package/build/src/akuma/akuma-wait.js +75 -53
  10. package/build/src/akuma/akuma.d.ts +6 -4
  11. package/build/src/akuma/akuma.js +4 -0
  12. package/build/src/akuma/call-initial-tell.d.ts +2 -2
  13. package/build/src/akuma/call-initial-tell.js +1 -1
  14. package/build/src/akuma/call-request.d.ts +2 -2
  15. package/build/src/akuma/heart/index.d.ts +7 -2
  16. package/build/src/akuma/heart/index.js +50 -5
  17. package/build/src/akuma/heart/tells.d.ts +33 -2
  18. package/build/src/akuma/heart/tells.js +24 -18
  19. package/build/src/akuma/heart/timeline.d.ts +23 -1
  20. package/build/src/akuma/heart/timeline.js +28 -21
  21. package/build/src/akuma/projection.d.ts +10 -10
  22. package/build/src/akuma/providers/pi/index.js +72 -39
  23. package/build/src/akuma/selection-observation.d.ts +20 -20
  24. package/build/src/akuma-body.js +1 -0
  25. package/build/src/alias/index.d.ts +0 -1
  26. package/build/src/alias/index.js +0 -4
  27. package/build/src/body/amend.d.ts +0 -4
  28. package/build/src/body/amend.js +0 -3
  29. package/build/src/body/region.d.ts +0 -1
  30. package/build/src/body/region.js +0 -3
  31. package/build/src/body/verification.d.ts +0 -1
  32. package/build/src/cli/commands/akuma-grammar.js +23 -66
  33. package/build/src/cli/commands/akuma.js +17 -30
  34. package/build/src/cli/commands/contract-grammar.d.ts +14 -1
  35. package/build/src/cli/commands/contract-grammar.js +54 -21
  36. package/build/src/cli/commands/contract-help.d.ts +9 -8
  37. package/build/src/cli/commands/contract-help.js +14 -7
  38. package/build/src/cli/commands/contract.js +57 -117
  39. package/build/src/cli/commands/install.d.ts +5 -5
  40. package/build/src/cli/commands/install.js +1 -4
  41. package/build/src/cli/commands/task-grammar.js +10 -66
  42. package/build/src/cli/commands/task.d.ts +0 -1
  43. package/build/src/cli/commands/task.js +34 -53
  44. package/build/src/cli/coordinates.d.ts +1 -2
  45. package/build/src/cli/coordinates.js +1 -4
  46. package/build/src/cli/parse.d.ts +2 -3
  47. package/build/src/cli/parse.js +24 -66
  48. package/build/src/cli/render/akuma.d.ts +3 -16
  49. package/build/src/cli/render/akuma.js +1 -13
  50. package/build/src/cli/render/audit.js +1 -1
  51. package/build/src/cli/render/contract.js +34 -32
  52. package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
  53. package/build/src/cli/render/kanshi-akuma.js +14 -7
  54. package/build/src/cli/render/kanshi.d.ts +3 -1
  55. package/build/src/cli/render/kanshi.js +44 -32
  56. package/build/src/cli/render/receipt.js +6 -1
  57. package/build/src/cli/render/task.d.ts +1 -1
  58. package/build/src/cli/render/task.js +3 -27
  59. package/build/src/cli/render/terminal.d.ts +6 -2
  60. package/build/src/cli/render/terminal.js +8 -2
  61. package/build/src/cli/runtime.js +3 -16
  62. package/build/src/cli/scan.d.ts +26 -0
  63. package/build/src/cli/scan.js +82 -0
  64. package/build/src/cli/streams.d.ts +5 -0
  65. package/build/src/cli/streams.js +11 -0
  66. package/build/src/contract-worktree.js +38 -21
  67. package/build/src/core/facts/codec.d.ts +1 -2
  68. package/build/src/core/facts/codec.js +5 -11
  69. package/build/src/core/facts/types.d.ts +16 -2
  70. package/build/src/core/facts/types.js +15 -0
  71. package/build/src/core/verbs/abandon.js +3 -9
  72. package/build/src/core/verbs/amend.js +2 -9
  73. package/build/src/core/verbs/arc.js +6 -13
  74. package/build/src/core/verbs/attestation.js +2 -9
  75. package/build/src/core/verbs/bind.js +2 -9
  76. package/build/src/core/verbs/deliver.js +2 -9
  77. package/build/src/core/verbs/placement.d.ts +1 -1
  78. package/build/src/core/verbs/placement.js +2 -9
  79. package/build/src/core/verbs/reintegrate.d.ts +1 -1
  80. package/build/src/core/verbs/reintegrate.js +2 -9
  81. package/build/src/dispatch/index.d.ts +2 -2
  82. package/build/src/dispatch/index.js +33 -11
  83. package/build/src/git/hooks.d.ts +2 -4
  84. package/build/src/git/hooks.js +0 -12
  85. package/build/src/git/integration.d.ts +5 -3
  86. package/build/src/git/integration.js +36 -25
  87. package/build/src/git/nuke.js +4 -4
  88. package/build/src/git/observe.d.ts +4 -4
  89. package/build/src/git/observe.js +5 -5
  90. package/build/src/git/process.d.ts +1 -4
  91. package/build/src/git/process.js +1 -11
  92. package/build/src/git/read-observation.js +1 -1
  93. package/build/src/git/reconcile.d.ts +1 -1
  94. package/build/src/git/reconcile.js +15 -13
  95. package/build/src/git/repository.d.ts +2 -6
  96. package/build/src/git/repository.js +18 -31
  97. package/build/src/git/scratch.d.ts +6 -6
  98. package/build/src/git/scratch.js +110 -46
  99. package/build/src/git/target-placement.d.ts +5 -5
  100. package/build/src/git/target-placement.js +18 -33
  101. package/build/src/git/tender.d.ts +6 -2
  102. package/build/src/git/tender.js +19 -12
  103. package/build/src/git/terminal-reconcile.js +24 -13
  104. package/build/src/git/terminal-seal.d.ts +2 -5
  105. package/build/src/git/terminal-seal.js +5 -3
  106. package/build/src/git/workspace.d.ts +17 -13
  107. package/build/src/git/workspace.js +58 -41
  108. package/build/src/kanshi/index.d.ts +2 -2
  109. package/build/src/kanshi/index.js +1 -1
  110. package/build/src/kanshi/read.d.ts +8 -1
  111. package/build/src/kanshi/read.js +72 -7
  112. package/build/src/kanshi/report.d.ts +12 -0
  113. package/build/src/library/akuma-creation.d.ts +4 -4
  114. package/build/src/library/bind.d.ts +1 -63
  115. package/build/src/library/bind.js +3 -9
  116. package/build/src/library/contract-creation.js +2 -30
  117. package/build/src/library/contract-execution.d.ts +0 -1
  118. package/build/src/library/contract-execution.js +9 -34
  119. package/build/src/library/contract-operations.d.ts +5 -1
  120. package/build/src/library/contract-operations.js +7 -3
  121. package/build/src/library/contract-types.d.ts +1 -1
  122. package/build/src/library/delivery.d.ts +91 -93
  123. package/build/src/library/delivery.js +2 -1
  124. package/build/src/library/input.d.ts +0 -2
  125. package/build/src/library/input.js +0 -4
  126. package/build/src/library/invocation.d.ts +0 -1
  127. package/build/src/library/invocation.js +3 -25
  128. package/build/src/library/outcome.d.ts +651 -602
  129. package/build/src/library/outcome.js +4 -4
  130. package/build/src/library/reconcile.d.ts +6 -0
  131. package/build/src/library/reconcile.js +31 -1
  132. package/build/src/library/repo.d.ts +0 -1
  133. package/build/src/library/selection.d.ts +1 -10
  134. package/build/src/library/selection.js +14 -15
  135. package/build/src/protocol/abandon.d.ts +1 -1
  136. package/build/src/protocol/abandon.js +3 -10
  137. package/build/src/protocol/amend.js +2 -5
  138. package/build/src/protocol/arc.d.ts +1 -1
  139. package/build/src/protocol/arc.js +2 -9
  140. package/build/src/protocol/attempt.d.ts +3 -20
  141. package/build/src/protocol/attempt.js +6 -5
  142. package/build/src/protocol/audit.d.ts +1 -0
  143. package/build/src/protocol/audit.js +10 -11
  144. package/build/src/protocol/completion.d.ts +129 -55
  145. package/build/src/protocol/completion.js +62 -73
  146. package/build/src/protocol/deliver.d.ts +7 -5
  147. package/build/src/protocol/deliver.js +74 -44
  148. package/build/src/protocol/execution-observation.d.ts +2 -4
  149. package/build/src/protocol/execution-observation.js +3 -7
  150. package/build/src/protocol/intent.d.ts +1 -1
  151. package/build/src/protocol/intent.js +1 -0
  152. package/build/src/protocol/operations.d.ts +24 -12
  153. package/build/src/protocol/operations.js +36 -15
  154. package/build/src/protocol/placement.d.ts +2 -1
  155. package/build/src/protocol/placement.js +21 -5
  156. package/build/src/protocol/progress.d.ts +1 -1
  157. package/build/src/protocol/read/status.js +58 -41
  158. package/build/src/protocol/reintegrate.d.ts +1 -1
  159. package/build/src/protocol/reintegrate.js +10 -19
  160. package/build/src/protocol/review.d.ts +3 -28
  161. package/build/src/protocol/review.js +10 -37
  162. package/build/src/protocol/run.d.ts +19 -7
  163. package/build/src/protocol/run.js +19 -9
  164. package/build/src/runtime/proc/windows-launch.exe +0 -0
  165. package/build/src/settlement/holder.d.ts +2 -4
  166. package/build/src/settlement/holder.js +3 -6
  167. package/build/src/task/board.d.ts +6 -0
  168. package/build/src/task/board.js +30 -1
  169. package/build/src/task/catalog.js +1 -4
  170. package/build/src/task/compose.d.ts +0 -1
  171. package/build/src/task/compose.js +0 -1
  172. package/build/src/task/context.d.ts +0 -1
  173. package/build/src/task/context.js +0 -3
  174. package/build/src/task/created-observation.d.ts +5 -1
  175. package/build/src/task/created-observation.js +12 -5
  176. package/build/src/task/index.d.ts +1 -1
  177. package/build/src/task/index.js +7 -6
  178. package/build/src/task/input.d.ts +0 -6
  179. package/build/src/task/input.js +2 -14
  180. package/build/src/task/mutation.d.ts +3 -4
  181. package/build/src/task/mutation.js +11 -39
  182. package/build/src/task/operations.d.ts +2 -7
  183. package/build/src/task/operations.js +37 -49
  184. package/build/src/task/query.d.ts +0 -1
  185. package/build/src/task/query.js +1 -4
  186. package/build/src/task/store.d.ts +0 -2
  187. package/build/src/task/store.js +27 -11
  188. package/build/src/verification/declaration.js +3 -2
  189. package/build/src/verification/execution.d.ts +3 -2
  190. package/build/src/verification/execution.js +10 -6
  191. package/build/src/workspace-place.d.ts +0 -1
  192. package/build/src/workspace-place.js +0 -11
  193. package/package.json +7 -3
@@ -1,8 +1,9 @@
1
1
  ---
2
2
  name: keiyaku-akuma
3
3
  description: >-
4
- Calling an Akuma: delegate work to a new or existing worker, then observe,
5
- guide, and collect the result.
4
+ Use when the work involves Akuma or Aku, or when you want other hands on
5
+ it: delegating a job, or fanning out research, checks, or other parallel
6
+ work.
6
7
  ---
7
8
 
8
9
  # Keiyaku Akuma
@@ -15,6 +16,12 @@ shorter, world-local name.
15
16
 
16
17
  ## Call a new Akuma
17
18
 
19
+ ```bash
20
+ keiyaku call worker "Summarize the recent changes in src/cli"
21
+ keiyaku call worker --alias @reviewer --wait 10m - < brief.md
22
+ keiyaku call worker
23
+ ```
24
+
18
25
  The prompt is optional for prompt-free birth. Otherwise it is the new Akuma's
19
26
  first prompt: give it as one argument, or use `-` to read stdin, never both.
20
27
  Calls are detached by default: they return the new identity after birth without
@@ -22,7 +29,7 @@ waiting for the first answer. Use explicit `--wait <duration>` when this
22
29
  invocation should block while observing that initial work. `--wait` only bounds
23
30
  this command; it never stops the Akuma. Read `call --help` for flag syntax,
24
31
  defaults, and action vocabulary.
25
- For seat grants see `keiyaku-workflow`'s table; Reviewers need `--allowed contract.review`.
32
+ To hand a Contract role to an Akuma, use the grant table in `keiyaku-workflow`.
26
33
 
27
34
  The selected Akuma name is a reusable worker configuration, not an individual.
28
35
  Calling it again creates an independent Akuma. Use different names for
@@ -33,34 +40,57 @@ capabilities, not merely for parallelism.
33
40
  `--contract` only records the association. It does not tell the Akuma the
34
41
  Contract or worktree. Put them in the prompt explicitly:
35
42
 
36
- ```text
37
- Contract: <kei/...>
38
- Worktree: <exact path>
39
- This Arc: <what to do>
43
+ ```bash
44
+ keiyaku call worker --contract kei/add-rate-limit-a1b2 --workdir /path/to/worktree - <<'EOF'
45
+ Contract: kei/add-rate-limit-a1b2
46
+ Worktree: /path/to/worktree
47
+ This Arc: implement the limiter and its tests
48
+ EOF
40
49
  ```
41
50
 
42
51
  `--contract` does not choose a worktree. Use `--workdir <path>` when needed.
43
52
 
44
53
  ## Tell or ask an existing Akuma
45
54
 
55
+ ```bash
56
+ keiyaku tell @reviewer "The candidate moved; re-examine the worktree"
57
+ keiyaku tell @reviewer --interrupt - < new-priority.md
58
+ keiyaku ask @reviewer --wait 10m "What is your verdict?"
59
+ keiyaku ask @reviewer --schema verdict.schema.json - < question.md
60
+ ```
61
+
46
62
  `tell` admits the next instruction and returns its admission receipt; it does
47
63
  not await an answer. `ask` admits a Tell and observes that exact answer,
48
64
  unbounded unless `--wait` limits observation. Both require a prompt and accept
49
65
  `--interrupt` to put down current work before admitting the new Tell. Schema
50
66
  belongs only to `ask`; `tell --schema` and `tell --wait` refuse and point to
51
67
  `ask`. A deadline never withdraws an admitted Tell. Read `tell --help` and
52
- `ask --help` for invocation syntax.
68
+ `ask --help` for the complete flag grammar.
53
69
 
54
70
  ## Observe work
55
71
 
72
+ ```bash
73
+ keiyaku wait @deliverer @reviewer
74
+ keiyaku wait --all --timeout 30m @deliverer @reviewer
75
+ ```
76
+
56
77
  Use `wait` for one or more existing Akumas. The default is `--any`; use
57
78
  `--all` for every selected Akuma. `--timeout` limits observation and does not
58
79
  stop workers. A completed Akuma already counts, so repeating a wait can return
59
- immediately. See `wait --help` for syntax. Unlike `ask`, `wait` observes
60
- existing Akuma-wide work, not the answer to a newly admitted Tell.
80
+ immediately. See `wait --help` for the complete grammar. Unlike `ask`, `wait`
81
+ observes existing Akuma-wide work, not the answer to a newly admitted Tell.
61
82
 
62
83
  ## Inspect and retrieve results
63
84
 
85
+ ```bash
86
+ keiyaku status
87
+ keiyaku status @reviewer
88
+ keiyaku ls aku/
89
+ keiyaku ls "aku/*/*"
90
+ keiyaku history @reviewer --last
91
+ keiyaku history @reviewer --id turn/3
92
+ ```
93
+
64
94
  `status` shows the roster or one Akuma's workdir and effective actions.
65
95
  `ls aku/` shows callable names; `ls "aku/*/*"` shows born workers.
66
96
  `history --last` reads the latest complete answer; `history --id` reads an
@@ -69,10 +99,16 @@ move; see `history --help` for paging.
69
99
 
70
100
  ## Stop and branch
71
101
 
102
+ ```bash
103
+ keiyaku kill @reviewer
104
+ keiyaku fork @reviewer --at turn/3
105
+ ```
106
+
72
107
  `kill` stops current work without admitting a Tell, deleting the Akuma, or
73
108
  removing its history. `fork` creates a new Akuma from one exact retained
74
109
  answered history point; the source is unchanged, and providers that cannot
75
- fork report that refusal. See the `kill --help` and `fork --help` syntax.
110
+ fork report that refusal. See `kill --help` and `fork --help` for the
111
+ complete grammar.
76
112
 
77
113
  ## JavaScript automation
78
114
 
@@ -46,8 +46,8 @@ skeptics to break the finalists, and generate replacements only for the
46
46
  identified weaknesses. Bound rounds and cost; "keep improving" is not a useful
47
47
  stop condition.
48
48
 
49
- Independent judgment needs independent contexts. Create separate Akuma for
50
- blind comparisons or adversarial verification. Reuse an identity for follow-up
49
+ Blind comparisons and adversarial checks need separate contexts. Create
50
+ separate Akuma for them. Reuse an identity for follow-up
51
51
  investigation, not as a supposedly fresh judge of its own earlier answer.
52
52
 
53
53
  ## Public Entry And A Single Structured Turn
@@ -52,7 +52,7 @@ does not move without you.
52
52
  | Observed shape | First response |
53
53
  | --- | --- |
54
54
  | Silent wedge: initial answer empty and worktree clean | Inspect status and history, then send one steering `tell`. If the worker remains unresponsive, `kill` and call a new Akuma; an empty answer alone is not proof the Contract failed. |
55
- | Verdict record refused with `not-allowed` | Read the worker's analysis in history; call a new Reviewer with the grant from `keiyaku-workflow`, then have it inspect current work and record a fresh verdict. The refused request wrote no Contract testimony. |
55
+ | Verdict record refused with `not-allowed` | Read the worker's analysis in history. Record the verdict yourself if you did not deliver the candidate, or call a new Reviewer with the grant from `keiyaku-workflow` and have it inspect current work and record a fresh verdict. The refused request wrote no Contract testimony. |
56
56
  | Review stale after changed candidate tender | Normal content-currentness result. Give the same Reviewer the changed diff and current terms with `tell`; have it re-examine and record current testimony. A target move alone does not stale review. |
57
57
  | Target moved under the appointed worktree | Have the Deliverer inspect target movement and merge the target branch (main when selected) in that worktree when required; resolve conflicts there, then audit again. Do not resolve against a stale integration preview. |
58
58
  | Typed refusal names its rule | Fix the named input or physical condition, then retry from a fresh observation. Do not repeat the same request blindly. |
@@ -154,14 +154,13 @@ fence containing commands runnable as written. Use separate fences when checks
154
154
  need different timeouts or results. Use an explicit timeout for bounded
155
155
  commands; `5m` is the normal baseline.
156
156
 
157
- Verification runs against the exact integration snapshot in a clean disposable
158
- worktree for that attempt. It does not run in the author's worktree or the
159
- target checkout. If the Contract declares Verification, `deliver` runs it when
160
- no current `verified` attestation exists and otherwise reuses the current
161
- attestation. A newly run unsatisfied result stops that delivery. `audit` runs
162
- Verification for a prospective candidate. `--gates reviewed` requires review
163
- evidence; it does not select or suppress Verification. Selected gates are
164
- checked at placement.
157
+ Verification runs only when the Contract selects the `verified` gate, against
158
+ the exact integration snapshot in a clean disposable worktree for that attempt.
159
+ `deliver` reuses current satisfied evidence or runs the declarations; unsatisfied
160
+ results and runtime stops prevent placement. `audit` runs declarations for a
161
+ prospective candidate. Without `verified`, no verb runs Verification and the
162
+ section is inert document text. `reviewed` independently requires review
163
+ evidence. Selected gates are checked at placement.
165
164
 
166
165
  For an existing Task with real scheduling or dependency value:
167
166
 
@@ -205,7 +204,7 @@ waiting, the stated prerequisites remain; do not bind a duplicate Contract.
205
204
 
206
205
  The holder now owns the lifecycle:
207
206
 
208
- 1. Start the work directly or delegate Tasks, Arc chapters, Akumas, or seats.
207
+ 1. Start the work directly or delegate Tasks, Arc chapters, Akumas, or Contract roles.
209
208
  2. Run independent work in parallel and let it converge on the one acceptance
210
209
  boundary.
211
210
  3. Prepare and deliver the candidate.
@@ -38,13 +38,26 @@ to create parallel work.
38
38
  Use `after` only when one `kei` requires another to be accepted first. Ordinary
39
39
  overlap is not a dependency.
40
40
 
41
- ## 3. Hold the `kei`
41
+ ## 3. Roles
42
42
 
43
- Every `kei` has exactly one holder. The holder coordinates the work and owns
44
- acceptance until the Contract is accepted or abandoned. Delegation does not
45
- transfer that responsibility. An Akuma holding the whole loop needs the `kei`, current Arc
46
- when one exists, appointed worktree, holder duties, and actions its commission
47
- will perform. Birth freezes permissions; Contract association grants none.
43
+ A `kei` has three roles. They are responsibilities, not people, and one agent
44
+ may fill more than one of them, with one exception below.
45
+
46
+ - **Holder:** exactly one per `kei`. Owns the fulfillment loop and acceptance
47
+ until the Contract is accepted or abandoned. Handing work to others never
48
+ transfers this responsibility.
49
+ - **Deliverer:** produces the candidate in the appointed worktree and tenders
50
+ it with `deliver`.
51
+ - **Reviewer:** judges the complete Contract against its acceptance conditions
52
+ and records the verdict with `review`.
53
+
54
+ Review is independent when the Reviewer did not deliver the candidate under
55
+ review. That is the whole requirement. The holder may review its own `kei`; a
56
+ fresh Akuma is not what makes review independent. Keiyaku does not check who
57
+ reviews, so keeping the Reviewer apart from the Deliverer is the holder's duty.
58
+
59
+ Any role may be filled directly or handed to an Akuma. Hand one over when other
60
+ hands help the work, not to make review count.
48
61
 
49
62
  ## 4. Lifecycle
50
63
 
@@ -59,9 +72,9 @@ Each act changes a different part of the world:
59
72
  audit; when it matters, merge the target branch (main when selected) in the
60
73
  worktree and resolve conflicts there before auditing.
61
74
  - **Audit:** Previews the candidate and target without tendering or claiming.
62
- Declared Verification can record a `verified` attestation for the captured
63
- subject; current evidence is reused. No declaration or a stopped run records
64
- no new verdict.
75
+ With `verified` selected, Verification runs for the captured subject and can
76
+ record an attestation. Without that gate, the section is inert text and no
77
+ verb runs Verification. A stopped run records no new verdict.
65
78
  - **Deliver:** Captures a tender and integration against the observed target;
66
79
  journal gains a delivered candidate. Ready prerequisites and gates trigger
67
80
  placement and claim in this invocation; otherwise the candidate waits.
@@ -78,31 +91,30 @@ Placement judges declared gates, not the producer's identity. Review does not
78
91
  replace Verification; audit never requests placement. Read the final receipt
79
92
  for stops and reconciliation lag after an admitted act.
80
93
 
81
- ## 5. Seats And Capabilities
94
+ ## 5. Handing A Role To An Akuma
82
95
 
83
96
  This is the one commissioning map. `call --help` owns the exact action
84
- vocabulary and default set. `--contract` records association, not authority.
97
+ vocabulary and default set. The flagship acting directly needs no grant.
98
+ Birth freezes an Akuma's actions; `--contract` records association, not
99
+ authority.
85
100
 
86
- | Seat | Grant and commission | Return |
101
+ | Role | Grant at birth | Return |
87
102
  | --- | --- | --- |
88
- | Holder | Direct flagship commands need no Akuma grant. A delegated holder gets only its birth-time actions; include review when the delegated loop records review. | Own the acceptance loop and inspect receipts. |
89
- | Deliverer | The ordinary baseline includes every Task mutation, Contract audit and delivery, and Akuma management. `keiyaku -C <repo> call worker --alias @deliverer --contract <kei/...> --workdir <appointed-path> -` | Produce and tender the candidate; return the receipt. |
90
- | Reviewer | Add `--allowed contract.review` at birth: `keiyaku -C <repo> call review-akuma --alias @reviewer --contract <kei/...> --workdir <appointed-path> --allowed contract.review -` | Record a verdict and return its receipt. Without the grant, `not-allowed` refuses the mutation; no Contract verdict is recorded. |
103
+ | Holder | The actions the delegated loop will perform; include `contract.review` when this holder will review. Commission with the `kei`, current Arc when one exists, appointed worktree, and holder duties. | Acceptance or abandonment, with receipts. |
104
+ | Deliverer | The ordinary baseline: every Task mutation, Contract audit and delivery, and Akuma management. `keiyaku -C <repo> call worker --alias @deliverer --contract <kei/...> --workdir <appointed-path> -` | The delivery receipt. |
105
+ | Reviewer | `--allowed contract.review`: `keiyaku -C <repo> call review-akuma --alias @reviewer --contract <kei/...> --workdir <appointed-path> --allowed contract.review -` | The verdict receipt. Without the grant, `not-allowed` refuses and no verdict is recorded. |
91
106
 
92
- An Archetype's explicit allowed set replaces the ordinary baseline. Check
107
+ An Archetype's explicit allowed set replaces the ordinary baseline; check
93
108
  `status` for effective actions. `tell` and `fork` cannot add a grant to a live
94
- Akuma; call a fresh one with the grant. Nested calls cannot exceed their direct
95
- parent's actions.
96
-
97
- ## 6. Delegate the Work
109
+ Akuma, so call a fresh one with the grant. Nested calls cannot exceed their
110
+ direct parent's actions.
98
111
 
99
112
  Commission with a clear objective, current Arc when one exists, appointed
100
- worktree, and expected result. A Deliverer produces the candidate. A Reviewer
101
- checks the complete Contract against its acceptance conditions and returns
102
- verdict evidence. Use `keiyaku-akuma` for invocation and observation, and
103
- command help for exact syntax.
113
+ worktree, and expected result. Never ask the Akuma that delivered a candidate
114
+ to review it. Use `keiyaku-akuma` for invocation and observation, and command
115
+ help for exact syntax.
104
116
 
105
- ## 7. Decide What Happens Next
117
+ ## 6. Decide What Happens Next
106
118
 
107
119
  The holder checks candidate, verification, review, prerequisites, and gates.
108
120
 
@@ -1,5 +1,5 @@
1
1
  import { type AkuId, type AkumaPaths } from "./identity.js";
2
- import { selectHistory, type ActivityHistory, type ActivityRow, type ActivitySnapshot } from "./projection.js";
2
+ import { selectHistory, selectSnapshot, type ActivityHistory, type ActivityRow, type ActivitySnapshot, type TurnLedger } from "./projection.js";
3
3
  import type { WorldRoot } from "../world.js";
4
4
  import type { AkumaAlias } from "../identity/selector.js";
5
5
  import type { AkumaListRow, AkumaStatus, UnbornAkumaListRow } from "./akuma.js";
@@ -16,24 +16,27 @@ type BudgetedStatusObservation = Readonly<{
16
16
  export type LiveStatusObservation = BudgetedStatusObservation & Readonly<{
17
17
  rows: readonly ActivityRow[];
18
18
  }>;
19
- /** Internal live companion for an observation loop; it is not a public result. */
20
- export declare function bornLiveStatus(paths: AkumaPaths, expected: AkuId, input: Readonly<{
21
- aperture: "monitoring" | "receipt";
22
- ordinaryBudget?: number;
23
- admittedTellId?: string;
24
- }>): Promise<LiveStatusObservation>;
25
- export declare function bornStatus(paths: AkumaPaths, expected: AkuId, input: Readonly<{
26
- aperture: "monitoring" | "receipt";
27
- ordinaryBudget?: number;
28
- admittedTellId?: string;
29
- }>): Promise<BudgetedStatusObservation>;
30
- export declare function readLiveStatus(worldPath: WorldRoot, id: AkuId, input: Readonly<{
19
+ type StatusObservationInput = Readonly<{
31
20
  aperture: "monitoring" | "receipt";
32
21
  ordinaryBudget?: number;
33
22
  admittedTellId?: string;
34
- }>): Promise<LiveStatusObservation>;
23
+ }>;
24
+ type StatusProjection = Readonly<{
25
+ ledger: TurnLedger;
26
+ selected: ReturnType<typeof selectSnapshot>;
27
+ }>;
28
+ /** Private to a live wait: retain only this member's current frontier and last selection. */
29
+ export declare function createLiveStatusReader(paths: AkumaPaths, expected: AkuId): {
30
+ clear: () => void;
31
+ read(input: StatusObservationInput, signal?: AbortSignal): Promise<LiveStatusObservation>;
32
+ };
33
+ /** Internal live companion for an observation loop; it is not a public result. */
34
+ export declare function bornLiveStatus(paths: AkumaPaths, expected: AkuId, input: StatusObservationInput, signal?: AbortSignal, readProjection?: () => Promise<StatusProjection>): Promise<LiveStatusObservation>;
35
+ export declare function bornStatus(paths: AkumaPaths, expected: AkuId, input: StatusObservationInput): Promise<BudgetedStatusObservation>;
36
+ export declare function readLiveStatus(worldPath: WorldRoot, id: AkuId, input: StatusObservationInput, signal?: AbortSignal): Promise<LiveStatusObservation>;
35
37
  export declare function defaultWaitComplete(status: AkumaStatus): boolean;
36
- export declare function readWaitComplete(worldPath: WorldRoot, id: AkuId): Promise<boolean>;
38
+ /** Probe completion only; returned statuses still come from a full observation. */
39
+ export declare function readWaitComplete(worldPath: WorldRoot, ids: readonly AkuId[], completion: "any" | "all", signal?: AbortSignal): Promise<boolean>;
37
40
  export type WaitReason = "completed" | "deadline";
38
41
  /**
39
42
  * The one deadline-aware observation loop for public Akuma waiting. It always
@@ -1,4 +1,4 @@
1
- import { readStatusFacts, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readSeal, readSoul, } from "./heart/index.js";
1
+ import { readStatusFacts, createStatusFactReader, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life, lifeAt, probeLeash, readHeart, readSeal, readSoul, } from "./heart/index.js";
2
2
  import { pathsForAkuId } from "./identity.js";
3
3
  import { ordinarySnapshotBudget, projectTurns, selectHistory, selectSnapshot, } from "./projection.js";
4
4
  import { resolveProviderExecution } from "./providers/index.js";
@@ -59,21 +59,56 @@ async function bornObservation(paths, expected, read, snapshot) {
59
59
  claim?.release();
60
60
  }
61
61
  }
62
+ function snapshotSelection(input) {
63
+ return {
64
+ aperture: input.aperture,
65
+ budget: ordinarySnapshotBudget(input.ordinaryBudget),
66
+ ...(input.admittedTellId === undefined ? {} : { admittedTellId: input.admittedTellId }),
67
+ };
68
+ }
69
+ /** Private to a live wait: retain only this member's current frontier and last selection. */
70
+ export function createLiveStatusReader(paths, expected) {
71
+ const reader = createStatusFactReader(paths);
72
+ let memo;
73
+ const clear = () => {
74
+ reader.clear();
75
+ memo = undefined;
76
+ };
77
+ return {
78
+ clear,
79
+ async read(input, signal) {
80
+ try {
81
+ return await bornLiveStatus(paths, expected, input, signal, async () => {
82
+ const facts = await reader.read(input, signal);
83
+ const ledger = memo?.facts === facts ? memo.ledger : projectTurns(facts);
84
+ const options = snapshotSelection(input);
85
+ const selected = memo?.ledger === ledger &&
86
+ memo.options.aperture === options.aperture &&
87
+ memo.options.admittedTellId === options.admittedTellId &&
88
+ memo.options.budget.tail === options.budget.tail &&
89
+ memo.options.budget.voice === options.budget.voice
90
+ ? memo.selected
91
+ : selectSnapshot(ledger, options);
92
+ memo = { facts, ledger, options, selected };
93
+ return { ledger, selected };
94
+ });
95
+ }
96
+ catch (error) {
97
+ clear();
98
+ throw error;
99
+ }
100
+ },
101
+ };
102
+ }
62
103
  /** Internal live companion for an observation loop; it is not a public result. */
63
- export async function bornLiveStatus(paths, expected, input) {
104
+ export async function bornLiveStatus(paths, expected, input, signal, readProjection) {
64
105
  if (input.ordinaryBudget !== undefined && (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0))
65
106
  throw new TypeError("ordinary budget must be a nonnegative safe integer");
66
- const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths));
107
+ const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths, signal));
67
108
  const resumeUnsupported = currentLife === "stranded" &&
68
109
  snapshot.latestSession?.provider === soul.provider.name &&
69
110
  (await resolveProviderExecution(soul.provider)).adapter.resume === undefined;
70
- const facts = await readStatusFacts(paths, input);
71
- const ledger = projectTurns(facts);
72
- const selected = selectSnapshot(ledger, {
73
- aperture: input.aperture,
74
- budget: ordinarySnapshotBudget(input.ordinaryBudget),
75
- ...(input.admittedTellId === undefined ? {} : { admittedTellId: input.admittedTellId }),
76
- });
111
+ const { ledger, selected } = readProjection === undefined ? await readStatusProjection(paths, input, signal) : await readProjection();
77
112
  return {
78
113
  status: {
79
114
  id: soul.id,
@@ -87,12 +122,20 @@ export async function bornLiveStatus(paths, expected, input) {
87
122
  rows: ledger.rows,
88
123
  };
89
124
  }
125
+ async function readStatusProjection(paths, input, signal) {
126
+ const facts = await readStatusFacts(paths, input, signal);
127
+ const ledger = projectTurns(facts);
128
+ return {
129
+ ledger,
130
+ selected: selectSnapshot(ledger, snapshotSelection(input)),
131
+ };
132
+ }
90
133
  export async function bornStatus(paths, expected, input) {
91
134
  const { rows: _rows, ...status } = await bornLiveStatus(paths, expected, input);
92
135
  return status;
93
136
  }
94
- export async function readLiveStatus(worldPath, id, input) {
95
- return await bornLiveStatus(pathsForAkuId(worldPath, id), id, input);
137
+ export async function readLiveStatus(worldPath, id, input, signal) {
138
+ return await bornLiveStatus(pathsForAkuId(worldPath, id), id, input, signal);
96
139
  }
97
140
  function complete(life, pending) {
98
141
  return life !== "running" && !pending;
@@ -100,10 +143,26 @@ function complete(life, pending) {
100
143
  export function defaultWaitComplete(status) {
101
144
  return complete(status.life, status.timeline.entries.some((entry) => entry.kind === "row" && entry.row.kind === "tell" && entry.row.state === "pending"));
102
145
  }
103
- export async function readWaitComplete(worldPath, id) {
104
- const paths = pathsForAkuId(worldPath, id);
105
- const observed = await bornObservation(paths, id, () => readLifeSnapshot(paths));
106
- return complete(observed.currentLife, observed.snapshot.hasPendingTell);
146
+ /** Probe completion only; returned statuses still come from a full observation. */
147
+ export async function readWaitComplete(worldPath, ids, completion, signal) {
148
+ let completed = 0;
149
+ for (const id of ids) {
150
+ signal?.throwIfAborted();
151
+ try {
152
+ const paths = pathsForAkuId(worldPath, id);
153
+ const observed = await bornObservation(paths, id, () => readLifeSnapshot(paths, signal));
154
+ if (complete(observed.currentLife, observed.snapshot.hasPendingTell)) {
155
+ if (completion === "any")
156
+ return true;
157
+ completed += 1;
158
+ }
159
+ }
160
+ catch (error) {
161
+ if (ids.length === 1 || error instanceof AkumaNotBornError)
162
+ throw error;
163
+ }
164
+ }
165
+ return ids.length > 0 && completed === ids.length;
107
166
  }
108
167
  const OBSERVATION_POLL_MS = 100;
109
168
  /**
@@ -53,9 +53,10 @@ export type NativeWaitResult = Readonly<{
53
53
  * The one lower set-observation owner for Akuma wait completion. It serves the
54
54
  * standalone one-ID association-free face and the plural any/all face with one
55
55
  * ordered round algorithm, one shared ordinary-detail budget, transient
56
- * unreadable peers, and an honest final deadline edge. The default completion
57
- * probe is used only without live row callbacks and never with a custom
58
- * predicate; a live viewer always observes rounds.
56
+ * unreadable peers, and an honest final deadline edge. A silent observation —
57
+ * no live row callback and no custom judge — decides which running rounds to
58
+ * skip with the owner's lightweight completion probe over the selected set; a
59
+ * live viewer or a custom judge always observes full rounds.
59
60
  */
60
61
  export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<NativeWaitResult>;
61
62
  export {};
@@ -1,10 +1,22 @@
1
1
  import { AkumaNotBornError } from "./akuma-errors.js";
2
- import { defaultWaitComplete, readLiveStatus, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
2
+ import { createLiveStatusReader, defaultWaitComplete, readLiveStatus, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
3
+ import { pathsForAkuId } from "./identity.js";
3
4
  const SHARED_ORDINARY_BUDGET = 30;
4
- async function observeWaitRound(path, ids, signal) {
5
+ async function observeWaitRound(path, ids, signal, readers) {
6
+ const read = async (id, ordinaryBudget) => {
7
+ const options = { aperture: "monitoring", ...(ordinaryBudget === undefined ? {} : { ordinaryBudget }) };
8
+ if (readers === undefined)
9
+ return await readLiveStatus(path, id, options, signal);
10
+ let reader = readers.get(id);
11
+ if (reader === undefined) {
12
+ reader = createLiveStatusReader(pathsForAkuId(path, id), id);
13
+ readers.set(id, reader);
14
+ }
15
+ return await reader.read(options, signal);
16
+ };
5
17
  signal?.throwIfAborted();
6
18
  if (ids.length <= 1) {
7
- const observations = await Promise.all(ids.map(async (id) => await readLiveStatus(path, id, { aperture: "monitoring" })));
19
+ const observations = await Promise.all(ids.map(async (id) => await read(id)));
8
20
  return { observations, unobserved: [] };
9
21
  }
10
22
  let remaining = SHARED_ORDINARY_BUDGET;
@@ -13,11 +25,13 @@ async function observeWaitRound(path, ids, signal) {
13
25
  for (const id of ids) {
14
26
  signal?.throwIfAborted();
15
27
  try {
16
- const observed = await readLiveStatus(path, id, { aperture: "monitoring", ordinaryBudget: remaining });
28
+ const observed = await read(id, remaining);
17
29
  observations.push(observed);
18
30
  remaining -= observed.ordinarySelected;
19
31
  }
20
32
  catch (error) {
33
+ readers?.get(id)?.clear();
34
+ readers?.delete(id);
21
35
  if (error instanceof AkumaNotBornError)
22
36
  throw error;
23
37
  unobserved.push({ id, diagnostic: diagnostic(error) });
@@ -54,59 +68,67 @@ function selectionOrderedIds(ids, order) {
54
68
  * The one lower set-observation owner for Akuma wait completion. It serves the
55
69
  * standalone one-ID association-free face and the plural any/all face with one
56
70
  * ordered round algorithm, one shared ordinary-detail budget, transient
57
- * unreadable peers, and an honest final deadline edge. The default completion
58
- * probe is used only without live row callbacks and never with a custom
59
- * predicate; a live viewer always observes rounds.
71
+ * unreadable peers, and an honest final deadline edge. A silent observation —
72
+ * no live row callback and no custom judge — decides which running rounds to
73
+ * skip with the owner's lightweight completion probe over the selected set; a
74
+ * live viewer or a custom judge always observes full rounds.
60
75
  */
61
76
  export async function executeWaitAkuma(input) {
62
- // Identity facts are read once per observed Akuma, not once per 100ms round.
63
- const facts = new Map();
64
- if (input.onSelected !== undefined) {
65
- for (const id of input.ids) {
66
- input.signal?.throwIfAborted();
67
- const known = input.identity === undefined ? undefined : await input.identity(id);
68
- facts.set(id, known ?? { contract: { kind: "none" } });
69
- }
70
- const ordered = input.selectionOrder === undefined ? input.ids : selectionOrderedIds(input.ids, input.selectionOrder);
71
- input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
72
- }
73
- const observeRound = async (round) => {
74
- if (input.observe === undefined)
75
- return;
76
- const observed = [];
77
- for (const observation of round.observations) {
78
- input.signal?.throwIfAborted();
79
- const { status, rows } = observation;
80
- let known = facts.get(status.id);
81
- if (known === undefined && input.identity !== undefined) {
82
- known = await input.identity(status.id);
83
- facts.set(status.id, known);
84
- }
85
- if (known === undefined) {
86
- observed.push({ status, rows, contract: { kind: "none" } });
87
- continue;
77
+ const readers = input.observe === undefined ? undefined : new Map();
78
+ try {
79
+ // Identity facts are read once per observed Akuma, not once per 100ms round.
80
+ const facts = new Map();
81
+ if (input.onSelected !== undefined) {
82
+ for (const id of input.ids) {
83
+ input.signal?.throwIfAborted();
84
+ const known = input.identity === undefined ? undefined : await input.identity(id);
85
+ facts.set(id, known ?? { contract: { kind: "none" } });
88
86
  }
89
- observed.push({ status, rows, ...known });
87
+ const ordered = input.selectionOrder === undefined ? input.ids : selectionOrderedIds(input.ids, input.selectionOrder);
88
+ input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
90
89
  }
91
- input.observe(observed);
92
- };
93
- const live = input.observe !== undefined;
94
- const waited = await waitForObservation({
95
- ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
96
- ...(input.signal === undefined ? {} : { signal: input.signal }),
97
- ...(input.predicate === undefined && !live && input.ids.length === 1
98
- ? { probe: async () => await readWaitComplete(input.path, input.ids[0]) }
99
- : {}),
100
- observe: async () => await observeWaitRound(input.path, input.ids, input.signal),
101
- complete: (round) => roundComplete(round, input.completion, input.predicate),
102
- onObserve: async (round) => await observeRound(round),
103
- });
104
- return {
105
- mode: input.completion,
106
- reason: waited.reason,
107
- observations: waited.value.observations.map((observation) => observation.status),
108
- unobserved: waited.value.unobserved,
109
- };
90
+ const observeRound = async (round) => {
91
+ if (input.observe === undefined)
92
+ return;
93
+ const observed = [];
94
+ for (const observation of round.observations) {
95
+ input.signal?.throwIfAborted();
96
+ const { status, rows } = observation;
97
+ let known = facts.get(status.id);
98
+ if (known === undefined && input.identity !== undefined) {
99
+ known = await input.identity(status.id);
100
+ facts.set(status.id, known);
101
+ }
102
+ if (known === undefined) {
103
+ observed.push({ status, rows, contract: { kind: "none" } });
104
+ continue;
105
+ }
106
+ observed.push({ status, rows, ...known });
107
+ }
108
+ input.observe(structuredClone(observed));
109
+ };
110
+ const waited = await waitForObservation({
111
+ ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
112
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
113
+ ...(input.predicate === undefined && input.observe === undefined
114
+ ? { probe: async () => await readWaitComplete(input.path, input.ids, input.completion, input.signal) }
115
+ : {}),
116
+ observe: async () => await observeWaitRound(input.path, input.ids, input.signal, readers),
117
+ complete: (round) => roundComplete(round, input.completion, input.predicate),
118
+ onObserve: async (round) => await observeRound(round),
119
+ });
120
+ return {
121
+ mode: input.completion,
122
+ reason: waited.reason,
123
+ observations: waited.value.observations.map((observation) => observation.status),
124
+ unobserved: waited.value.unobserved,
125
+ };
126
+ }
127
+ finally {
128
+ for (const reader of readers?.values() ?? [])
129
+ reader.clear();
130
+ readers?.clear();
131
+ }
110
132
  }
111
133
  function diagnostic(error) {
112
134
  return error instanceof Error ? error.message : String(error);