harnery 0.34.0 → 0.35.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 (212) hide show
  1. package/dist/commander.d.ts.map +1 -1
  2. package/dist/commander.js +2 -0
  3. package/dist/commands/agents.d.ts +15 -4
  4. package/dist/commands/agents.d.ts.map +1 -1
  5. package/dist/commands/agents.js +91 -162
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +26 -2
  8. package/dist/commands/decision.d.ts.map +1 -1
  9. package/dist/commands/decision.js +2 -2
  10. package/dist/commands/events.d.ts.map +1 -1
  11. package/dist/commands/events.js +18 -1
  12. package/dist/commands/presence.d.ts.map +1 -1
  13. package/dist/commands/presence.js +2 -2
  14. package/dist/commands/semantic.d.ts +4 -0
  15. package/dist/commands/semantic.d.ts.map +1 -0
  16. package/dist/commands/semantic.js +147 -0
  17. package/dist/commands/web.d.ts.map +1 -1
  18. package/dist/commands/web.js +17 -0
  19. package/dist/core/agents/canonical-emit.d.ts +3 -0
  20. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  21. package/dist/core/agents/canonical-emit.js +12 -0
  22. package/dist/core/agents/claim-path.d.ts +11 -0
  23. package/dist/core/agents/claim-path.d.ts.map +1 -0
  24. package/dist/core/agents/claim-path.js +22 -0
  25. package/dist/core/agents/coord-client.d.ts +29 -3
  26. package/dist/core/agents/coord-client.d.ts.map +1 -1
  27. package/dist/core/agents/coord-client.js +88 -9
  28. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  29. package/dist/core/agents/live-authority-v3.js +1 -3
  30. package/dist/core/agents/live-lifecycle-v3.js +3 -3
  31. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  32. package/dist/core/agents/live-observation-v3.js +2 -2
  33. package/dist/core/agents/render/prompt-context.js +12 -10
  34. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  35. package/dist/core/agents/rules/stop-hook.js +23 -11
  36. package/dist/core/agents/session-name-display.d.ts +2 -1
  37. package/dist/core/agents/session-name-display.d.ts.map +1 -1
  38. package/dist/core/agents/session-name-display.js +10 -3
  39. package/dist/core/agents/state/heartbeat-reader.d.ts +46 -0
  40. package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -0
  41. package/dist/core/agents/state/heartbeat-reader.js +25 -0
  42. package/dist/core/agents/state/heartbeat-writer.d.ts +3 -48
  43. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  44. package/dist/core/agents/state/heartbeat-writer.js +16 -34
  45. package/dist/core/agents/state/live-coordination-view.d.ts +1 -1
  46. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  47. package/dist/core/agents/state/live-coordination-view.js +25 -1
  48. package/dist/core/agents/state/names.d.ts +9 -1
  49. package/dist/core/agents/state/names.d.ts.map +1 -1
  50. package/dist/core/agents/state/names.js +190 -182
  51. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  52. package/dist/core/agents/state/stale-sweep.js +23 -5
  53. package/dist/core/artifacts/constants.d.ts +5 -0
  54. package/dist/core/artifacts/constants.d.ts.map +1 -0
  55. package/dist/core/artifacts/constants.js +4 -0
  56. package/dist/core/artifacts/index.d.ts +3 -3
  57. package/dist/core/artifacts/index.d.ts.map +1 -1
  58. package/dist/core/artifacts/index.js +50 -7
  59. package/dist/core/events/v3/base-contract.d.ts +795 -0
  60. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  61. package/dist/core/events/v3/base-contract.js +33 -0
  62. package/dist/core/events/v3/capabilities.d.ts +11 -0
  63. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  64. package/dist/core/events/v3/capabilities.js +23 -0
  65. package/dist/core/events/v3/generated.d.ts +1 -1
  66. package/dist/core/events/v3/generated.js +1 -1
  67. package/dist/core/events/v3/index.d.ts +4 -3
  68. package/dist/core/events/v3/index.d.ts.map +1 -1
  69. package/dist/core/events/v3/index.js +4 -3
  70. package/dist/core/events/v3/latency.d.ts +31 -1
  71. package/dist/core/events/v3/latency.d.ts.map +1 -1
  72. package/dist/core/events/v3/latency.js +127 -3
  73. package/dist/core/events/v3/live-routing.d.ts +30 -0
  74. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  75. package/dist/core/events/v3/live-routing.js +109 -1
  76. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
  77. package/dist/core/events/v3/producers/command-recorder.js +10 -1
  78. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  79. package/dist/core/events/v3/producers/coordination-recorder.js +14 -3
  80. package/dist/core/events/v3/producers/hook-base.d.ts +17 -1
  81. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  82. package/dist/core/events/v3/producers/hook-base.js +82 -1
  83. package/dist/core/events/v3/producers/intake.d.ts +6 -0
  84. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  85. package/dist/core/events/v3/producers/intake.js +11 -0
  86. package/dist/core/events/v3/producers/recorder.d.ts +62 -0
  87. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  88. package/dist/core/events/v3/producers/recorder.js +654 -18
  89. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +51 -0
  90. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -0
  91. package/dist/core/events/v3/runtime-telemetry-capabilities.js +54 -0
  92. package/dist/core/events/v3/turn-telemetry.d.ts +9 -0
  93. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  94. package/dist/core/hooks/adapter/parse.d.ts +3 -0
  95. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  96. package/dist/core/hooks/adapter/parse.js +14 -0
  97. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +119 -0
  98. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -0
  99. package/dist/core/hooks/adapter/runtime-telemetry.js +568 -0
  100. package/dist/core/hooks/cli.js +114 -38
  101. package/dist/core/hooks/remediation-cap.d.ts +34 -0
  102. package/dist/core/hooks/remediation-cap.d.ts.map +1 -0
  103. package/dist/core/hooks/remediation-cap.js +71 -0
  104. package/dist/core/hooks/resolve/transcript.d.ts +25 -9
  105. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  106. package/dist/core/hooks/resolve/transcript.js +35 -17
  107. package/dist/core/semantic/adapters.d.ts +34 -0
  108. package/dist/core/semantic/adapters.d.ts.map +1 -0
  109. package/dist/core/semantic/adapters.js +222 -0
  110. package/dist/core/semantic/contract.d.ts +588 -0
  111. package/dist/core/semantic/contract.d.ts.map +1 -0
  112. package/dist/core/semantic/contract.js +230 -0
  113. package/dist/core/semantic/evidence.d.ts +11 -0
  114. package/dist/core/semantic/evidence.d.ts.map +1 -0
  115. package/dist/core/semantic/evidence.js +262 -0
  116. package/dist/core/semantic/index.d.ts +10 -0
  117. package/dist/core/semantic/index.d.ts.map +1 -0
  118. package/dist/core/semantic/index.js +9 -0
  119. package/dist/core/semantic/once.d.ts +33 -0
  120. package/dist/core/semantic/once.d.ts.map +1 -0
  121. package/dist/core/semantic/once.js +293 -0
  122. package/dist/core/semantic/prompt.d.ts +12 -0
  123. package/dist/core/semantic/prompt.d.ts.map +1 -0
  124. package/dist/core/semantic/prompt.js +70 -0
  125. package/dist/core/semantic/scheduler.d.ts +16 -0
  126. package/dist/core/semantic/scheduler.d.ts.map +1 -0
  127. package/dist/core/semantic/scheduler.js +67 -0
  128. package/dist/core/semantic/service-status.d.ts +31 -0
  129. package/dist/core/semantic/service-status.d.ts.map +1 -0
  130. package/dist/core/semantic/service-status.js +84 -0
  131. package/dist/core/semantic/service.d.ts +51 -0
  132. package/dist/core/semantic/service.d.ts.map +1 -0
  133. package/dist/core/semantic/service.js +470 -0
  134. package/dist/core/semantic/storage.d.ts +71 -0
  135. package/dist/core/semantic/storage.d.ts.map +1 -0
  136. package/dist/core/semantic/storage.js +179 -0
  137. package/dist/core/semantic/validate.d.ts +16 -0
  138. package/dist/core/semantic/validate.d.ts.map +1 -0
  139. package/dist/core/semantic/validate.js +174 -0
  140. package/dist/lib/browser/client.d.ts +11 -0
  141. package/dist/lib/browser/client.d.ts.map +1 -1
  142. package/dist/lib/browser/client.js +13 -0
  143. package/dist/lib/browser/index.d.ts +1 -0
  144. package/dist/lib/browser/index.d.ts.map +1 -1
  145. package/dist/lib/browser/standalone-html.d.ts +25 -0
  146. package/dist/lib/browser/standalone-html.d.ts.map +1 -0
  147. package/dist/lib/browser/standalone-html.js +284 -0
  148. package/dist/lib/instructions/apply.d.ts.map +1 -1
  149. package/dist/lib/instructions/apply.js +1 -0
  150. package/dist/lib/instructions/templates.d.ts +2 -0
  151. package/dist/lib/instructions/templates.d.ts.map +1 -1
  152. package/dist/lib/instructions/templates.js +144 -4
  153. package/package.json +6 -1
  154. package/schemas/event-v3.schema.json +2758 -478
  155. package/src/commander.ts +2 -0
  156. package/src/commands/agents.ts +104 -152
  157. package/src/commands/browse.ts +25 -2
  158. package/src/commands/decision.ts +8 -2
  159. package/src/commands/events.ts +21 -1
  160. package/src/commands/presence.ts +7 -2
  161. package/src/commands/semantic.ts +179 -0
  162. package/src/commands/web.ts +15 -0
  163. package/src/core/agents/canonical-emit.ts +15 -0
  164. package/src/core/agents/claim-path.ts +23 -0
  165. package/src/core/agents/coord-client.ts +92 -8
  166. package/src/core/agents/live-authority-v3.ts +1 -4
  167. package/src/core/agents/live-lifecycle-v3.ts +8 -3
  168. package/src/core/agents/live-observation-v3.ts +7 -2
  169. package/src/core/agents/render/prompt-context.ts +13 -10
  170. package/src/core/agents/rules/stop-hook.ts +24 -11
  171. package/src/core/agents/session-name-display.ts +11 -3
  172. package/src/core/agents/state/heartbeat-reader.ts +69 -0
  173. package/src/core/agents/state/heartbeat-writer.ts +20 -84
  174. package/src/core/agents/state/live-coordination-view.ts +26 -1
  175. package/src/core/agents/state/names.ts +190 -182
  176. package/src/core/agents/state/stale-sweep.ts +25 -5
  177. package/src/core/artifacts/constants.ts +4 -0
  178. package/src/core/artifacts/index.ts +49 -7
  179. package/src/core/events/v3/base-contract.ts +39 -0
  180. package/src/core/events/v3/capabilities.ts +34 -0
  181. package/src/core/events/v3/generated.ts +1 -1
  182. package/src/core/events/v3/index.ts +21 -0
  183. package/src/core/events/v3/latency.ts +213 -2
  184. package/src/core/events/v3/live-routing.ts +120 -1
  185. package/src/core/events/v3/producers/command-recorder.ts +10 -1
  186. package/src/core/events/v3/producers/coordination-recorder.ts +17 -5
  187. package/src/core/events/v3/producers/hook-base.ts +115 -1
  188. package/src/core/events/v3/producers/intake.ts +18 -0
  189. package/src/core/events/v3/producers/recorder.ts +856 -21
  190. package/src/core/events/v3/runtime-telemetry-capabilities.ts +137 -0
  191. package/src/core/events/v3/turn-telemetry.ts +10 -0
  192. package/src/core/hooks/adapter/parse.ts +16 -0
  193. package/src/core/hooks/adapter/runtime-telemetry.ts +805 -0
  194. package/src/core/hooks/cli.ts +126 -41
  195. package/src/core/hooks/remediation-cap.ts +77 -0
  196. package/src/core/hooks/resolve/transcript.ts +49 -17
  197. package/src/core/semantic/adapters.ts +293 -0
  198. package/src/core/semantic/contract.ts +298 -0
  199. package/src/core/semantic/evidence.ts +336 -0
  200. package/src/core/semantic/index.ts +127 -0
  201. package/src/core/semantic/once.ts +410 -0
  202. package/src/core/semantic/prompt.ts +84 -0
  203. package/src/core/semantic/scheduler.ts +107 -0
  204. package/src/core/semantic/service-status.ts +118 -0
  205. package/src/core/semantic/service.ts +580 -0
  206. package/src/core/semantic/storage.ts +286 -0
  207. package/src/core/semantic/validate.ts +212 -0
  208. package/src/lib/browser/client.ts +21 -0
  209. package/src/lib/browser/index.ts +4 -0
  210. package/src/lib/browser/standalone-html.ts +312 -0
  211. package/src/lib/instructions/apply.ts +1 -0
  212. package/src/lib/instructions/templates.ts +149 -4
@@ -5,6 +5,14 @@
5
5
  * Layout invariant: 260 entries (10 per starting letter A..Z). Counter N
6
6
  * picks COORD_NAMES[N % 260]; wraps to A at N=260.
7
7
  *
8
+ * Gender invariant: within each 26-name pass the names alternate female/male
9
+ * letter by letter, so every pass is 13 female and 13 male. Five passes start
10
+ * female at A (1, 3, 5, 7, 9) and five start male (2, 4, 6, 8, 10), which gives
11
+ * each letter exactly five names of each gender and the pool 130/130 overall.
12
+ * This exists so a fixed set of 13 female and 13 male portraits can dress one
13
+ * whole pass. Adding or reordering a name must preserve it; the expected
14
+ * pattern is pinned in tests/unit/names-pool.test.ts.
15
+ *
8
16
  * Durable persistence: `.harnery/.name-history` (JSONL, one row per assignment)
9
17
  * + `.harnery/.name-counter` (current counter, atomic temp+rename).
10
18
  *
@@ -24,274 +32,274 @@ import { dirname, join } from "node:path";
24
32
 
25
33
  /** All 260 names. */
26
34
  export const COORD_NAMES = [
27
- // Pass 1
35
+ // Pass 1 — female-first (A=female), alternating to Z
28
36
  "Anna",
29
37
  "Bob",
30
- "Carlos",
31
- "Dalia",
38
+ "Carmen",
39
+ "Dorian",
32
40
  "Erika",
33
41
  "Fred",
34
42
  "Gemma",
35
43
  "Hank",
36
44
  "Imelda",
37
45
  "Jerry",
38
- "Kirk",
39
- "Lee",
40
- "Milton",
46
+ "Karen",
47
+ "Lorenzo",
48
+ "Mindy",
41
49
  "Nate",
42
- "Oscar",
43
- "Patty",
44
- "Quentin",
50
+ "Odette",
51
+ "Peter",
52
+ "Quinn",
45
53
  "Rafael",
46
54
  "Sara",
47
55
  "Tony",
48
- "Ulrik",
49
- "Valerie",
56
+ "Ursula",
57
+ "Vinson",
50
58
  "Whitney",
51
59
  "Xander",
52
60
  "Yara",
53
- "Zara",
54
- // Pass 2
55
- "Adelaide",
61
+ "Zane",
62
+ // Pass 2 — male-first (A=male), alternating to Z
63
+ "Alex",
56
64
  "Bertha",
57
- "Carmen",
58
- "Dorian",
59
- "Edna",
65
+ "Carlos",
66
+ "Dalia",
67
+ "Ernesto",
60
68
  "Francine",
61
- "Greta",
69
+ "Gordon",
62
70
  "Helene",
63
- "Ines",
71
+ "Isaias",
64
72
  "Joyce",
65
- "Karen",
66
- "Lorenzo",
67
- "Mindy",
73
+ "Kirk",
74
+ "Lucia",
75
+ "Milton",
68
76
  "Nadine",
69
- "Odette",
70
- "Paulette",
71
- "Quinn",
77
+ "Oscar",
78
+ "Patty",
79
+ "Quentin",
72
80
  "Rebekah",
73
81
  "Sean",
74
82
  "Tammy",
75
- "Ursula",
76
- "Vinson",
83
+ "Ulrik",
84
+ "Valerie",
77
85
  "Wallace",
78
86
  "Xanthe",
79
87
  "Yusuf",
80
- "Zoe",
81
- // Pass 3
82
- "Alex",
88
+ "Zara",
89
+ // Pass 3 — female-first (A=female), alternating to Z
90
+ "Adelaide",
91
+ "Bruno",
92
+ "Cora",
93
+ "Damon",
94
+ "Edna",
95
+ "Felix",
96
+ "Greta",
97
+ "Hugo",
98
+ "Ines",
99
+ "Jasper",
100
+ "Kaia",
101
+ "Larry",
102
+ "Maxine",
103
+ "Nicholas",
104
+ "Olive",
105
+ "Paxton",
106
+ "Querida",
107
+ "Roman",
108
+ "Stella",
109
+ "Tobias",
110
+ "Una",
111
+ "Virgil",
112
+ "Willow",
113
+ "Xavier",
114
+ "Yolanda",
115
+ "Zephyr",
116
+ // Pass 4 — male-first (A=male), alternating to Z
117
+ "Aaron",
83
118
  "Beatrice",
84
119
  "Cyrus",
85
120
  "Delia",
86
- "Ernesto",
121
+ "Elias",
87
122
  "Florence",
88
- "Gordon",
123
+ "Galileo",
89
124
  "Hester",
90
- "Isaias",
125
+ "Ian",
91
126
  "Jenna",
92
127
  "Klaus",
93
- "Larry",
94
- "Maxine",
95
- "Nicholas",
128
+ "Linda",
129
+ "Marco",
130
+ "Nora",
96
131
  "Otto",
97
- "Peter",
132
+ "Paulette",
98
133
  "Quill",
99
134
  "Renee",
100
- "Stella",
135
+ "Sebastian",
101
136
  "Theresa",
102
137
  "Umberto",
103
- "Virgil",
104
- "Willow",
105
- "Xavier",
106
- "Yolanda",
107
- "Zane",
108
- // Pass 4
138
+ "Vera",
139
+ "Walter",
140
+ "Xena",
141
+ "Yves",
142
+ "Zoe",
143
+ // Pass 5 — female-first (A=female), alternating to Z
109
144
  "Anita",
110
- "Bruno",
111
- "Cora",
112
- "Damon",
145
+ "Beau",
146
+ "Celeste",
147
+ "Dexter",
113
148
  "Edith",
114
- "Felix",
149
+ "Fitz",
115
150
  "Gloria",
116
- "Holly",
151
+ "Hadley",
117
152
  "Iris",
118
- "Jasper",
119
- "Kaia",
120
- "Linda",
121
- "Marco",
122
- "Nora",
123
- "Olive",
124
- "Petra",
125
- "Querida",
126
- "Roman",
127
- "Sebastian",
128
- "Tobias",
129
- "Una",
130
- "Vera",
131
- "Walter",
132
- "Xena",
133
- "Yusra",
134
- "Zelda",
135
- // Pass 5
136
- "Aaron",
137
- "Bonnie",
138
- "Caleb",
139
- "Daphne",
140
- "Elias",
141
- "Fiona",
142
- "Galileo",
143
- "Hugo",
144
- "Ian",
145
153
  "Jude",
146
- "Knox",
154
+ "Kira",
147
155
  "Leo",
148
156
  "Maya",
149
157
  "Nash",
150
- "Owen",
151
- "Paxton",
158
+ "Olga",
159
+ "Phillip",
152
160
  "Quetzal",
153
- "Rosa",
161
+ "Royce",
154
162
  "Sage",
155
- "Talia",
156
- "Uri",
163
+ "Trent",
164
+ "Uma",
157
165
  "Vincent",
158
- "Wesley",
159
- "Ximena",
166
+ "Wynne",
167
+ "Xerxes",
160
168
  "Yvette",
161
- "Zephyr",
162
- // Pass 6
163
- "Astrid",
164
- "Beau",
165
- "Celeste",
166
- "Dexter",
169
+ "Zoltan",
170
+ // Pass 6 — male-first (A=male), alternating to Z
171
+ "Andre",
172
+ "Bonnie",
173
+ "Caleb",
174
+ "Daphne",
167
175
  "Ezra",
168
- "Fitz",
169
- "Genevieve",
170
- "Hadley",
171
- "Imogen",
172
- "Joaquin",
173
- "Kira",
176
+ "Fiona",
177
+ "Gibson",
178
+ "Holly",
179
+ "Ivan",
180
+ "Juno",
181
+ "Knox",
174
182
  "Lila",
175
183
  "Mason",
176
184
  "Nila",
177
- "Olga",
178
- "Pearl",
185
+ "Owen",
186
+ "Petra",
179
187
  "Quincy",
180
- "Royce",
188
+ "Rosa",
181
189
  "Sterling",
182
- "Trent",
183
- "Ulysses",
190
+ "Talia",
191
+ "Uri",
184
192
  "Violet",
185
- "Wynne",
186
- "Xerxes",
187
- "Yael",
188
- "Zinnia",
189
- // Pass 7
190
- "Amelia",
191
- "Bianca",
192
- "Cody",
193
- "Dahlia",
193
+ "Wesley",
194
+ "Ximena",
195
+ "Yuri",
196
+ "Zelda",
197
+ // Pass 7 — female-first (A=female), alternating to Z
198
+ "Astrid",
199
+ "Boris",
200
+ "Cassidy",
201
+ "Davis",
194
202
  "Esme",
195
- "Fern",
196
- "Greer",
197
- "Harriet",
198
- "Ivan",
199
- "Juno",
200
- "Kendrick",
203
+ "Forrest",
204
+ "Genevieve",
205
+ "Henry",
206
+ "Imogen",
207
+ "Joaquin",
208
+ "Kestrel",
201
209
  "Luther",
202
210
  "Margot",
203
211
  "Nigel",
204
- "Orion",
205
- "Phillip",
212
+ "Ophelia",
213
+ "Percy",
206
214
  "Quenby",
207
215
  "Reagan",
208
216
  "Sienna",
209
- "Tessa",
210
- "Uma",
211
- "Vesper",
212
- "Watson",
213
- "Xiomara",
214
- "Yuri",
215
- "Zoltan",
216
- // Pass 8
217
- "Andre",
218
- "Boris",
219
- "Cassidy",
220
- "Davis",
217
+ "Truman",
218
+ "Undine",
219
+ "Voss",
220
+ "Wren",
221
+ "Xan",
222
+ "Yael",
223
+ "Zia",
224
+ // Pass 8 — male-first (A=male), alternating to Z
225
+ "Arthur",
226
+ "Bianca",
227
+ "Cody",
228
+ "Dahlia",
221
229
  "Evander",
222
- "Forrest",
223
- "Gibson",
224
- "Henry",
225
- "Irene",
226
- "Justus",
227
- "Kasper",
230
+ "Fern",
231
+ "Gustavo",
232
+ "Harriet",
233
+ "Ira",
234
+ "Josephine",
235
+ "Kendrick",
228
236
  "Lainey",
229
237
  "Miles",
230
238
  "Naomi",
231
- "Ophelia",
232
- "Phoebe",
239
+ "Orion",
240
+ "Pearl",
233
241
  "Quark",
234
242
  "Rylie",
235
243
  "Saul",
236
- "Truman",
237
- "Ulrich",
238
- "Voss",
239
- "Winifred",
240
- "Xuxa",
241
- "Yvonne",
242
- "Zia",
243
- // Pass 9
244
- "Aria",
245
- "Brenda",
246
- "Crispin",
247
- "Dolores",
244
+ "Tessa",
245
+ "Ulysses",
246
+ "Vesper",
247
+ "Wyatt",
248
+ "Xiomara",
249
+ "Yancy",
250
+ "Zinnia",
251
+ // Pass 9 — female-first (A=female), alternating to Z
252
+ "Amelia",
253
+ "Barnaby",
254
+ "Calliope",
255
+ "Drake",
248
256
  "Estelle",
249
- "Felicity",
250
- "Goldie",
251
- "Hazel",
252
- "Ira",
253
- "Jovi",
254
- "Kestrel",
255
- "Lyric",
257
+ "Foster",
258
+ "Greer",
259
+ "Hollis",
260
+ "Irene",
261
+ "Jericho",
262
+ "Klara",
263
+ "Logan",
256
264
  "Mavis",
257
265
  "Nico",
258
- "Otis",
259
- "Percy",
260
- "Querubin",
266
+ "Oakley",
267
+ "Pascal",
268
+ "Quito",
261
269
  "Rhett",
262
270
  "Scout",
263
- "Tatum",
271
+ "Theron",
264
272
  "Unity",
265
- "Vivian",
266
- "Wyatt",
267
- "Xan",
268
- "Yancy",
273
+ "Vance",
274
+ "Winifred",
275
+ "Xola",
276
+ "Yvonne",
269
277
  "Zev",
270
- // Pass 10
278
+ // Pass 10 — male-first (A=male), alternating to Z
271
279
  "Atticus",
272
- "Barnaby",
273
- "Calliope",
274
- "Drake",
280
+ "Brenda",
281
+ "Crispin",
282
+ "Dolores",
275
283
  "Eustace",
276
- "Foster",
284
+ "Felicity",
277
285
  "Granger",
278
- "Hollis",
279
- "Indira",
280
- "Jericho",
281
- "Kaleb",
282
- "Logan",
286
+ "Hazel",
287
+ "Idris",
288
+ "Jovi",
289
+ "Kasper",
290
+ "Lyric",
283
291
  "Magnus",
284
292
  "Noor",
285
- "Oakley",
286
- "Posy",
287
- "Quito",
293
+ "Otis",
294
+ "Phoebe",
295
+ "Querubin",
288
296
  "Rosalind",
289
- "Sloane",
290
- "Theron",
297
+ "Silas",
298
+ "Tatum",
291
299
  "Upton",
292
- "Vance",
300
+ "Vivian",
293
301
  "Wendell",
294
- "Xola",
302
+ "Xuxa",
295
303
  "Yann",
296
304
  "Zora",
297
305
  ] as const;
@@ -13,6 +13,7 @@
13
13
  import { existsSync, readdirSync, readFileSync, statSync, unlinkSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { coordFreshnessSeconds } from "../../config.ts";
16
+ import { writeProducerDiagnosticV3 } from "../../events/v3/producers/intake.ts";
16
17
  import { recordLiveSweepObservationV3 } from "../live-lifecycle-v3.ts";
17
18
 
18
19
  /** platform → adapter, for the swept-event envelope (mirrors heartbeat-writer's adapterOf). */
@@ -22,7 +23,15 @@ function adapterFromPlatform(platform: unknown): "claude-code" | "cursor" | "cod
22
23
  return "claude-code";
23
24
  }
24
25
 
25
- /** Record the sweep before deleting authority state. V3 ambiguity fails closed. */
26
+ /**
27
+ * Record the sweep before deleting disposable cache state.
28
+ *
29
+ * A joinable generation owns the canonical provisional observation. Once that
30
+ * generation is terminal or unavailable, it must not be reopened merely to
31
+ * authorize cache housekeeping. Preserve the failed observation in the V3
32
+ * diagnostics spool instead. If neither durable record can be written, fail
33
+ * closed and keep the file.
34
+ */
26
35
  function emitSwept(
27
36
  coordRoot: string,
28
37
  instanceId: string,
@@ -46,8 +55,18 @@ function emitSwept(
46
55
  ageMs: Math.max(0, (ageSecs ?? 0) * 1_000),
47
56
  });
48
57
  return true;
49
- } catch {
50
- return false;
58
+ } catch (error) {
59
+ return Boolean(
60
+ writeProducerDiagnosticV3(coordRoot, "heartbeat_sweep_unrecorded", {
61
+ adapter,
62
+ instance_id: instanceId,
63
+ signal: "lifecycle.sweep_observed",
64
+ reason: error instanceof Error ? error.message : String(error),
65
+ state: "cache_cleanup_pending",
66
+ observation: reason,
67
+ age_ms: Math.max(0, (ageSecs ?? 0) * 1_000),
68
+ }),
69
+ );
51
70
  }
52
71
  }
53
72
 
@@ -85,8 +104,9 @@ export function staleSweep(coordRoot: string): {
85
104
  // a transient (mid-write / partial read), and deleting it would nuke a
86
105
  // LIVE agent's heartbeat, the worst possible outcome. So: never reap a
87
106
  // fresh file on a content failure.
88
- // Every deletion now emits health.heartbeat_swept so the lifecycle is
89
- // auditable (sweeps used to be silent; see the swept-event schema doc).
107
+ // Every deletion leaves durable audit evidence. A joinable generation gets
108
+ // lifecycle.sweep_observed; a terminal or unavailable generation gets a
109
+ // heartbeat_sweep_unrecorded producer diagnostic without being resurrected.
90
110
  const liveInstanceIds = new Set<string>();
91
111
  const d = join(coordRoot, ".harnery", "active");
92
112
  if (existsSync(d)) {
@@ -0,0 +1,4 @@
1
+ /** Read-only artifact layout constants safe for browser-side server modules. */
2
+ export const ARTIFACTS_DIR = ".harnery/artifacts";
3
+ export const ARTIFACT_MANIFEST = ".harnery-artifact.json";
4
+ export const ARTIFACT_SCHEMA_VERSION = 1 as const;
@@ -24,10 +24,9 @@ import {
24
24
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
25
25
  import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.ts";
26
26
  import { artifactDefaultRetentionDays } from "../config.ts";
27
+ import { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.ts";
27
28
 
28
- export const ARTIFACTS_DIR = join(".harnery", "artifacts");
29
- export const ARTIFACT_MANIFEST = ".harnery-artifact.json";
30
- export const ARTIFACT_SCHEMA_VERSION = 1 as const;
29
+ export { ARTIFACT_MANIFEST, ARTIFACT_SCHEMA_VERSION, ARTIFACTS_DIR } from "./constants.ts";
31
30
 
32
31
  export interface ArtifactActor {
33
32
  instance_id: string;
@@ -72,6 +71,7 @@ export interface ArtifactInventoryEntry {
72
71
  artifact_id: string | null;
73
72
  slug: string | null;
74
73
  created_at: string | null;
74
+ last_modified_at: string | null;
75
75
  expires_at: string | null;
76
76
  owner_instance_id: string | null;
77
77
  }
@@ -328,16 +328,22 @@ function classifyArtifactPath(
328
328
  }
329
329
  const manifest = parsed.manifest;
330
330
  const bytes = safeTreeSize(path);
331
+ const lastModifiedMs = safeTreeLastModified(path, now);
332
+ const retentionAnchorMs = Date.parse(manifest.retention.renewed_at ?? manifest.created_at);
333
+ const retentionWindowMs = Date.parse(manifest.retention.expires_at) - retentionAnchorMs;
334
+ const effectiveLastModifiedMs = Math.max(retentionAnchorMs, lastModifiedMs ?? 0);
335
+ const effectiveExpiresAt = new Date(effectiveLastModifiedMs + retentionWindowMs).toISOString();
331
336
  const base = rowFor(path, name, repoRoot, "managed-current", "retention has not expired", bytes);
332
337
  Object.assign(base, {
333
338
  artifact_id: manifest.artifact_id,
334
339
  slug: manifest.slug,
335
340
  created_at: manifest.created_at,
336
- expires_at: manifest.retention.expires_at,
341
+ last_modified_at: new Date(effectiveLastModifiedMs).toISOString(),
342
+ expires_at: effectiveExpiresAt,
337
343
  owner_instance_id: manifest.created_by?.instance_id ?? null,
338
344
  });
339
345
 
340
- if (base.bytes === null) {
346
+ if (base.bytes === null || lastModifiedMs === null) {
341
347
  return {
342
348
  ...base,
343
349
  classification: "unknown",
@@ -372,11 +378,11 @@ function classifyArtifactPath(
372
378
  };
373
379
  }
374
380
  }
375
- if (Date.parse(manifest.retention.expires_at) > now.getTime()) return base;
381
+ if (Date.parse(effectiveExpiresAt) > now.getTime()) return base;
376
382
  return {
377
383
  ...base,
378
384
  classification: "managed-expired",
379
- reason: `retention expired at ${manifest.retention.expires_at}`,
385
+ reason: `retention expired at ${effectiveExpiresAt}`,
380
386
  action: "would-delete",
381
387
  };
382
388
  }
@@ -410,6 +416,13 @@ function readManifest(path: string): ParsedManifest | ManifestError {
410
416
  if (!m.retention || typeof m.retention !== "object" || !validIso(m.retention.expires_at)) {
411
417
  return { ok: false, reason: "invalid retention.expires_at" };
412
418
  }
419
+ if (m.retention.renewed_at !== undefined && !validIso(m.retention.renewed_at)) {
420
+ return { ok: false, reason: "invalid retention.renewed_at" };
421
+ }
422
+ const retentionAnchor = Date.parse(m.retention.renewed_at ?? m.created_at);
423
+ if (Date.parse(m.retention.expires_at) <= retentionAnchor) {
424
+ return { ok: false, reason: "retention.expires_at must follow its retention anchor" };
425
+ }
413
426
  if (m.released_at !== undefined && !validIso(m.released_at)) {
414
427
  return { ok: false, reason: "invalid released_at" };
415
428
  }
@@ -478,6 +491,34 @@ function safeTreeSize(path: string): number | null {
478
491
  }
479
492
  }
480
493
 
494
+ /**
495
+ * Return the newest filesystem change in a managed tree without following
496
+ * symlinks. A small future tolerance protects a write racing the inventory
497
+ * scan; timestamps farther ahead are ignored as clock-skewed metadata.
498
+ */
499
+ function safeTreeLastModified(path: string, now: Date): number | null {
500
+ const nowMs = now.getTime();
501
+ const futureToleranceMs = 5 * 60 * 1000;
502
+ try {
503
+ const st = lstatSync(path);
504
+ let latest = 0;
505
+ for (const timestamp of [st.mtimeMs, st.ctimeMs]) {
506
+ if (Number.isFinite(timestamp) && timestamp <= nowMs + futureToleranceMs) {
507
+ latest = Math.max(latest, Math.min(timestamp, nowMs));
508
+ }
509
+ }
510
+ if (st.isSymbolicLink() || !st.isDirectory()) return latest;
511
+ for (const child of readdirSync(path)) {
512
+ const childLatest = safeTreeLastModified(join(path, child), now);
513
+ if (childLatest === null) return null;
514
+ latest = Math.max(latest, childLatest);
515
+ }
516
+ return latest;
517
+ } catch {
518
+ return null;
519
+ }
520
+ }
521
+
481
522
  function rowFor(
482
523
  path: string,
483
524
  name: string,
@@ -497,6 +538,7 @@ function rowFor(
497
538
  artifact_id: null,
498
539
  slug: null,
499
540
  created_at: null,
541
+ last_modified_at: null,
500
542
  expires_at: null,
501
543
  owner_instance_id: null,
502
544
  };