mercury-agent 0.24.3-beta.2 → 0.24.3-beta.5

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 (139) hide show
  1. package/container/Dockerfile +1 -0
  2. package/container/Dockerfile.base +1 -0
  3. package/docs/behavior-layers.md +15 -1
  4. package/docs/configuration.md +22 -12
  5. package/docs/goals/whatsapp-bot-hardening/open-threads.md +2 -0
  6. package/docs/pending-verification.md +107 -0
  7. package/docs/permissions.md +2 -1
  8. package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S7.md +2 -2
  9. package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/decisions.md +4 -4
  10. package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/plan.md +18 -44
  11. package/docs/plans/archive/2026-10-12-monitoring-1005/sessions/S12.md +47 -0
  12. package/docs/plans/archive/2026-10-12-monitoring-1005/sessions/S7.md +75 -0
  13. package/docs/plans/archive/2026-10-12-monitoring-1005/sessions/S8.md +66 -0
  14. package/docs/plans/archive/2026-10-12-monitoring-1005/sessions/S9.md +42 -0
  15. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/briefs/D1.md +64 -0
  16. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/briefs/S1.md +72 -0
  17. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/briefs/S2.md +63 -0
  18. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/briefs/S3.md +63 -0
  19. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/briefs/T1.md +33 -0
  20. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/decisions.md +7 -0
  21. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/plan.md +118 -0
  22. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/sessions/D1.md +59 -0
  23. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/sessions/S1.md +46 -0
  24. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/sessions/S2.md +56 -0
  25. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/sessions/S3.md +66 -0
  26. package/docs/plans/archive/2026-10-14-tagula-predeploy-1014/sessions/T1.md +7 -0
  27. package/docs/plans/general-0928/briefs/S3.md +1 -1
  28. package/docs/plans/general-0928/briefs/S4.md +1 -1
  29. package/docs/plans/general-0928/plan.md +5 -9
  30. package/docs/plans/tagula-client-1008/briefs/S1.md +78 -0
  31. package/docs/plans/tagula-client-1008/briefs/S10.md +77 -0
  32. package/docs/plans/tagula-client-1008/briefs/S2.md +78 -0
  33. package/docs/plans/tagula-client-1008/briefs/S3.md +77 -0
  34. package/docs/plans/tagula-client-1008/briefs/S4.md +77 -0
  35. package/docs/plans/tagula-client-1008/briefs/S5.md +78 -0
  36. package/docs/plans/tagula-client-1008/briefs/S6.md +77 -0
  37. package/docs/plans/tagula-client-1008/briefs/S7.md +76 -0
  38. package/docs/plans/tagula-client-1008/briefs/S8.md +77 -0
  39. package/docs/plans/tagula-client-1008/briefs/S9.md +77 -0
  40. package/docs/plans/tagula-client-1008/decisions.md +7 -0
  41. package/docs/plans/tagula-client-1008/plan.md +186 -0
  42. package/docs/plans/tagula-client-1008/sessions/S1.md +52 -0
  43. package/docs/plans/tagula-client-1008/sessions/S10.md +61 -0
  44. package/docs/plans/tagula-client-1008/sessions/S2.md +51 -0
  45. package/docs/plans/tagula-client-1008/sessions/S3.md +46 -0
  46. package/docs/plans/tagula-client-1008/sessions/S5.md +54 -0
  47. package/docs/plans/tagula-client-1008/sessions/S6.md +53 -0
  48. package/docs/plans/tagula-client-1008/sessions/S7.md +46 -0
  49. package/docs/plans/watchdog-1011/briefs/S1.md +75 -0
  50. package/docs/plans/watchdog-1011/decisions.md +8 -0
  51. package/docs/plans/watchdog-1011/plan.md +114 -0
  52. package/docs/profile-guide.md +21 -3
  53. package/docs/web-search.md +30 -7
  54. package/examples/extensions/archive/README.md +15 -2
  55. package/examples/extensions/archive/backends/drive.ts +34 -4
  56. package/examples/extensions/archive/gc.ts +57 -2
  57. package/examples/extensions/archive/index.ts +46 -8
  58. package/examples/extensions/gws/README.md +24 -4
  59. package/examples/extensions/gws/index.ts +171 -19
  60. package/examples/extensions/gws/skill/SKILL.md +33 -7
  61. package/examples/extensions/gws/skill/scripts/google-public-read.ts +384 -0
  62. package/examples/extensions/gws/token-mint.ts +206 -0
  63. package/examples/extensions/longview/summarize.ts +8 -4
  64. package/examples/extensions/napkin/index.ts +4 -2
  65. package/examples/extensions/office-365-mail/README.md +18 -2
  66. package/examples/extensions/office-365-mail/index.ts +7 -8
  67. package/examples/extensions/office-365-mail/lib/graph.ts +162 -17
  68. package/examples/extensions/office-365-mail/scripts/login.ts +5 -4
  69. package/examples/extensions/office-365-mail/skill/SKILL.md +18 -4
  70. package/examples/extensions/overview/actions.ts +4 -1
  71. package/examples/extensions/pinchtab/bin/pinchtab_ensure +52 -6
  72. package/examples/extensions/pinchtab/bin/pinchtab_nav +29 -3
  73. package/examples/extensions/web-search/capability.ts +630 -0
  74. package/examples/extensions/web-search/chain.ts +761 -0
  75. package/examples/extensions/web-search/index.ts +158 -49
  76. package/examples/extensions/web-search/ledger.ts +13 -0
  77. package/examples/extensions/web-search/providers/brave.ts +169 -0
  78. package/examples/extensions/web-search/providers/index.ts +91 -0
  79. package/examples/extensions/web-search/providers/tavily.ts +143 -0
  80. package/examples/extensions/web-search/providers/types.ts +191 -0
  81. package/examples/extensions/web-search/skill/SKILL.md +18 -13
  82. package/package.json +3 -3
  83. package/resources/pi-extensions/subagent/index.ts +8 -4
  84. package/resources/skills/permissions/SKILL.md +5 -1
  85. package/resources/skills/recall/SKILL.md +1 -1
  86. package/src/adapters/whatsapp-media.ts +38 -9
  87. package/src/adapters/whatsapp-offline.ts +141 -0
  88. package/src/adapters/whatsapp.ts +333 -63
  89. package/src/agent/container-entry.ts +49 -4
  90. package/src/agent/container-runner.ts +145 -37
  91. package/src/agent/image-contract.ts +1 -0
  92. package/src/bridges/whatsapp.ts +48 -9
  93. package/src/cli/mercury.ts +14 -0
  94. package/src/cli/service-unit.ts +18 -1
  95. package/src/config-file.ts +6 -1
  96. package/src/config.ts +13 -0
  97. package/src/core/api-types.ts +6 -0
  98. package/src/core/api.ts +13 -1
  99. package/src/core/caller-token.ts +13 -3
  100. package/src/core/data-dir-ownership.ts +53 -0
  101. package/src/core/direct-send.ts +3 -1
  102. package/src/core/exec.ts +5 -4
  103. package/src/core/operator-alerts.ts +78 -18
  104. package/src/core/permissions.ts +7 -0
  105. package/src/core/reply-language.ts +168 -0
  106. package/src/core/router.ts +6 -1
  107. package/src/core/routes/messages.ts +13 -4
  108. package/src/core/routes/send.ts +10 -0
  109. package/src/core/runtime.ts +78 -5
  110. package/src/core/systemd-watchdog.ts +381 -0
  111. package/src/core/task-scheduler.ts +32 -0
  112. package/src/core/task-sender.ts +100 -19
  113. package/src/extensions/image-builder.ts +3 -2
  114. package/src/main.ts +18 -2
  115. package/src/ops/shadow-snapshot.ts +20 -0
  116. package/src/preflight/binary-version.ts +3 -2
  117. package/src/preflight/checks/roundtrip.ts +2 -1
  118. package/src/server.ts +33 -4
  119. package/src/storage/db.ts +105 -6
  120. package/src/storage/pi-auth.ts +176 -17
  121. package/src/text/utf8-stream.ts +48 -0
  122. package/src/types.ts +33 -8
  123. package/docs/plans/general-0928/briefs/S5.md +0 -58
  124. package/docs/plans/monitoring-1005/briefs/S10.md +0 -72
  125. package/docs/plans/monitoring-1005/briefs/S11.md +0 -75
  126. package/docs/plans/monitoring-1005/briefs/S13.md +0 -77
  127. package/docs/plans/monitoring-1005/briefs/S5.md +0 -62
  128. package/docs/plans/monitoring-1005/briefs/S6.md +0 -67
  129. package/examples/extensions/web-search/brave.ts +0 -751
  130. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S1.md +0 -0
  131. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S12.md +0 -0
  132. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S2.md +0 -0
  133. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S3.md +0 -0
  134. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S4.md +0 -0
  135. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S8.md +0 -0
  136. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/briefs/S9.md +0 -0
  137. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/sessions/S2.md +0 -0
  138. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/sessions/S3.md +0 -0
  139. /package/docs/plans/{monitoring-1005 → archive/2026-10-12-monitoring-1005}/sessions/S4.md +0 -0
@@ -113,6 +113,7 @@ COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
113
113
  COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
114
114
  COPY src/extensions/bash-timeout.ts /app/src/extensions/bash-timeout.ts
115
115
  COPY src/text/sanitize-text.ts /app/src/text/sanitize-text.ts
116
+ COPY src/text/utf8-stream.ts /app/src/text/utf8-stream.ts
116
117
  COPY src/types.ts /app/src/types.ts
117
118
  COPY resources/ /app/resources/
118
119
  COPY examples/extensions/ /tmp/examples-extensions/
@@ -82,6 +82,7 @@ COPY src/extensions/reserved.ts /app/src/extensions/reserved.ts
82
82
  COPY src/extensions/permission-guard.ts /app/src/extensions/permission-guard.ts
83
83
  COPY src/extensions/bash-timeout.ts /app/src/extensions/bash-timeout.ts
84
84
  COPY src/text/sanitize-text.ts /app/src/text/sanitize-text.ts
85
+ COPY src/text/utf8-stream.ts /app/src/text/utf8-stream.ts
85
86
  COPY src/types.ts /app/src/types.ts
86
87
  COPY resources/ /app/resources/
87
88
  COPY examples/extensions/ /tmp/examples-extensions/
@@ -32,10 +32,18 @@ the repo, after a pi upgrade.
32
32
  ## Memory (MEMORY.md, <active_episodes>, <members>, member notes)
33
33
  ## Run budget (tools-capable models only)
34
34
  ## Destructive Operations — Confirmation Required
35
- ## Presenting tool results ("simple lists", "never show JSON/commands")
35
+ ## Presenting tool results ("simple lists", "never show JSON/commands",
36
+ "a bot-check page is a block, never a pass")
36
37
  ## Delivery ("[reply] … [/reply] — only the span inside is sent";
37
38
  pi-jsonl-parser.ts extractReplyEnvelope honours it,
38
39
  a reply with no markers is sent whole)
40
+ ## Staying silent ("asked not to reply → the whole reply is
41
+ NO_UPDATE; never explain the silence" — unconditional,
42
+ chat and scheduled runs; SILENCE_REPLY, pinned to the
43
+ host's NO_OUTPUT_SENTINEL by tests/mercury-additions.test.ts)
44
+ ## Reply language ("answer in the language of the message you are answering;
45
+ another only on request or when the space names one";
46
+ unconditional, explains the <reply_language> tag below)
39
47
  ## Character (heading + "Always follow it" + "only the owner can change it"
40
48
  — unconditional, it is the reader instruction for 3c;
41
49
  the mrctl character/prefs procedure under it
@@ -110,6 +118,9 @@ Built by `buildPrompt()` in `container-entry.ts`:
110
118
  <reply_anchor>…</reply_anchor> swipe-replies only
111
119
  <the prompt> chat message, or the task prompt, plus any
112
120
  before_container promptAppend (e.g. a digest)
121
+ <reply_language>he</reply_language> host-detected language of what the person wrote
122
+ (runtime.ts, src/core/reply-language.ts); only for
123
+ a non-Latin script it can name, never stored
113
124
  ```
114
125
 
115
126
  A scheduled task uses exactly the same assembly; its prompt row is "the
@@ -187,11 +198,14 @@ Everything else is opt-in by instruction.
187
198
  | Kind of rule | Put it in | Not in |
188
199
  |---|---|---|
189
200
  | Who the bot is in this space, register, what it covers, sourcing and accuracy standard, formats, when it stays silent | space `AGENTS.md` | preferences (500-char blocks in the user prompt, no structure, easy to contradict) |
201
+ | How the bot stays silent (the `NO_UPDATE` reply, and never explaining the silence) | the platform block (`## Staying silent`, layer 2) | space `AGENTS.md` (opt-in per space: the 26 spaces that never named it explained their silence to the group) |
190
202
  | A procedure: when it runs, what it produces, where it goes | the task prompt (`tasks/*.md` in a space profile) | `AGENTS.md` (a task prompt never repeats an editorial rule; `AGENTS.md` never describes a schedule) |
203
+ | Which language a reply is written in by default (the message's own) | the platform block (`## Reply language`, layer 2) + the host's `<reply_language>` tag | the Bot Character (left out of `persona.exclusive` spaces and absent on a deployment with none: 0 of 392 Tagula prompts carried it) |
191
204
  | A one-line behavioural setting a space admin may change from chat (`language`, `timezone`) | preference | `AGENTS.md` (would need a deploy to change) |
192
205
  | Voice that must hold across all spaces of one deployment | Bot Character | every space's `AGENTS.md` (drifts) |
193
206
  | Deterministic business logic, credentials, anything with numbers or dates | a capability / engine / extension, returning structured facts | prompt prose ("compute the day name yourself") |
194
207
  | What members may do | `role.member.permissions` / applicative `member_permissions` | prompt prose ("only admins may…") — the model is not the enforcement |
208
+ | A Google Docs/Sheets/Slides link someone sent: read it through its public export first (`google-public-read.ts`, no credentials, every caller), `gws` only for a private doc and only for a caller holding it; a private doc is "not shared publicly", never "no permission" | the `gws` extension skill (top section of `examples/extensions/gws/skill/SKILL.md`; the reader prints the fact — content, `NOT-PUBLIC`, and whether this caller holds `gws`) | the permission-guard text or the platform block (they stay a hard boundary for `gws`: the export read is not an "alternative means", because it reads only what Google serves without a login); granting `gws` to members (on a shared box it is one box-wide Google credential) |
195
209
  | Knobs an extension reads (`feed-watch.*`, `longview.*`) | `extension_config` in the space profile (repo-owned, drift-checked) | hand edits on the box |
196
210
  | A fact the bot keeps getting wrong | a file the bot reads each turn (`MEMORY.md`, a notebook under `knowledge/`), written with source and date | a longer rule |
197
211
 
@@ -24,7 +24,7 @@ These must be supplied via environment variables only; they are **not** read fro
24
24
  - `MERCURY_DISCORD_GATEWAY_SECRET`
25
25
  - `MERCURY_HEARTBEAT_URL` (see [Heartbeat](#heartbeat-mercury_heartbeat_url-mercury_heartbeat_tasks))
26
26
 
27
- Platform tokens, provider API keys, and extension keys (e.g. `MERCURY_TELEGRAM_BOT_TOKEN`, `MERCURY_BRAVE_API_KEY`) are also **env-only** today—they are not part of the YAML schema.
27
+ Platform tokens, provider API keys, and extension keys (e.g. `MERCURY_TELEGRAM_BOT_TOKEN`, `MERCURY_BRAVE_API_KEY`, `MERCURY_TAVILY_API_KEY`) are also **env-only** today—they are not part of the YAML schema.
28
28
 
29
29
  ## YAML layout
30
30
 
@@ -252,18 +252,28 @@ switch gates the missed-run reports described above.
252
252
  alerts:
253
253
  enabled: true # default: true
254
254
  cooldown_ms: 21600000 # 60000 – 604800000 (default: 6h)
255
+ recipients: # optional; extra audiences, in addition to the admins
256
+ - ops-team # a space id: every conversation linked to it
255
257
  ```
256
258
 
257
- Env equivalents: **`MERCURY_ALERTS_ENABLED`**, **`MERCURY_ALERTS_COOLDOWN_MS`**.
258
-
259
- - **Recipients** are the ids already listed in `permissions.admins` (`MERCURY_ADMINS`)
260
- and `dm_auto_space.admin_ids` (`MERCURY_DM_AUTO_SPACE_ADMIN_IDS`)
261
- — there is no separate alert-recipient key. An id is alerted only when it
262
- resolves to an existing space **with a linked conversation**, i.e. a chat
263
- Mercury can actually send into; an alert never creates a space. With no
264
- configured admin, or none that has ever messaged the bot, the alert has
265
- nowhere to go — Mercury logs that fact at ERROR and leaves the cooldown
266
- unclaimed, so the next failure tries again.
259
+ Env equivalents: **`MERCURY_ALERTS_ENABLED`**, **`MERCURY_ALERTS_COOLDOWN_MS`**,
260
+ **`MERCURY_ALERTS_RECIPIENTS`** (comma-separated).
261
+
262
+ - **Recipients** are the ids listed in `permissions.admins` (`MERCURY_ADMINS`)
263
+ and `dm_auto_space.admin_ids` (`MERCURY_DM_AUTO_SPACE_ADMIN_IDS`), plus every
264
+ entry of `alerts.recipients`. An `alerts.recipients` entry is a space id (the
265
+ alert goes to every conversation linked to that space, e.g. a staff group) or
266
+ a person id (resolved like an admin). Use it rather than adding a space id to
267
+ `permissions.admins`: that list also makes each entry an admin member of every
268
+ space. An id is alerted only when it resolves to an existing space **with a
269
+ linked conversation**, i.e. a chat Mercury can actually send into; an alert
270
+ never creates a space. An admin whose DM is also linked to a recipient space
271
+ is told once, through the space. With nothing reachable the alert has nowhere
272
+ to go — Mercury logs that fact at ERROR and leaves the cooldown unclaimed, so
273
+ the next failure tries again.
274
+ - **Startup check.** At boot Mercury logs `Operator alerts will reach no one: …`
275
+ at ERROR when no configured admin or recipient resolves to a deliverable
276
+ conversation, so the gap shows up before the first outage rather than during it.
267
277
  - **Channel** is the ordinary adapter outbox, the same path scheduled-task
268
278
  failures use. It carries no agent run and no LLM, so it still works when the
269
279
  agent's own credential is what died.
@@ -511,7 +521,7 @@ agent:
511
521
  ```
512
522
 
513
523
  - **`claimed`** (default) — only variables an extension declared via `mercury.env()` are passed, and only when the triggering caller holds that extension's permission. Undeclared variables stay on the host.
514
- - **`all`** — every `MERCURY_*` var except a fixed blocklist is passed into the container with the prefix stripped (`MERCURY_BILLING_API_KEY` → `BILLING_API_KEY`). Convenient, but blunt: a secret added to `.env` for one purpose reaches **every space's container**, regardless of who triggered the turn or whether that space has anything to do with it. Vars an extension declares `hostOnly` are excluded even here — `MERCURY_BRAVE_API_KEY` stays on the host once `web-search` is installed, which brokers Brave queries through `mrctl capability web-search`.
524
+ - **`all`** — every `MERCURY_*` var except a fixed blocklist is passed into the container with the prefix stripped (`MERCURY_BILLING_API_KEY` → `BILLING_API_KEY`). Convenient, but blunt: a secret added to `.env` for one purpose reaches **every space's container**, regardless of who triggered the turn or whether that space has anything to do with it. Vars an extension declares `hostOnly` are excluded even here — `MERCURY_BRAVE_API_KEY` and `MERCURY_TAVILY_API_KEY` stay on the host once `web-search` is installed, which brokers search queries through `mrctl capability web-search` (see `docs/web-search.md` for the provider chain and its `web-search.providers`, `monthly_budget` and `tavily_monthly_budget` keys).
515
525
 
516
526
  **Model-provider credentials are exempt** and pass in both modes (`MERCURY_ANTHROPIC_API_KEY`, `MERCURY_ANTHROPIC_OAUTH_TOKEN`, `MERCURY_GEMINI_API_KEY`, `MERCURY_GROQ_API_KEY`, and the rest of the provider list). pi reads them inside the container, and no extension declares them — without the exemption, `claimed` would leave the agent unable to reach any model. They remain subject to the blocklist.
517
527
 
@@ -423,3 +423,5 @@ carries) and the bridge forwards it — the two-line change this note predicted.
423
423
  The other `isMention` site (`discord-native.ts:346`) is history fetch, not
424
424
  ingress. 2 regression tests in `tests/discord-bridge.test.ts`. No Discord space
425
425
  is linked on this bot, so this is verified by test, not live.
426
+
427
+ - **Deploy pending (2026-10-08):** the box runs `6ddb895`; `dev` carries `933dafa` (heartbeat locale). 118 English "⏳ Processing…" notices went out in Hebrew spaces this week. Sync with `~/sync-mercury.sh` in a gap, then confirm the next notice reads "⏳ עובד על זה…".
@@ -2360,3 +2360,110 @@ The ⏳ heartbeat now uses the space's `messages.locale`; `main`, `tel-aviv-flat
2360
2360
  Host-only (`src/core/routes/links.ts`, not baked): it rides whatever restart deploys `mrctl-links-admin-commands`.
2361
2361
 
2362
2362
  - [ ] MANUAL-VERIFY(2026-10-05): On the box that runs M1.2, the global admin creates `mrctl links create <mgmt> '*' --level read --note "probe-note" --disclosure "probe-disclosure"`. Then, in another space, ask that space's admin's bot "who can access this space?": the reply names the management space and the disclosure, and never says "probe-note". The owner's own `mrctl links list` still shows `note: probe-note`. Revoke the probe link afterwards.
2363
+
2364
+ ## Plan tagula-client-1008 / S1
2365
+
2366
+ Archive shadow fix (`shadow-rehearsal-archive-reconcile-deletes-live-drive-files`). Restart-only: `src/ops/shadow-snapshot.ts` is host code, and the archive extension reaches a box as the installed snapshot that a restart refreshes. Nothing is baked into the image.
2367
+
2368
+ - [ ] MANUAL-VERIFY(2026-10-08): On the Tagula box after the restart, `grep -c orphansRefused /root/<project>/.mercury/extensions/archive/gc.ts` prints at least 1. That is the installed copy, not the repo.
2369
+ - [ ] MANUAL-VERIFY(2026-10-08): On the Tagula box, the next live `archive-reconcile` logs `missing=32` for `tagula-management` and no other space reports missing files. No `reconcile refused` line appears for any space; if one does, read its counts before anything else.
2370
+ - [ ] MANUAL-VERIFY(2026-10-08): The next shadow snapshot on a Drive-backed box: the last `MERCURY_ARCHIVE_BACKEND=` line of the shadow's `.env` is `local`, and the last `MERCURY_ARCHIVE_LOCAL_DIR=` points inside the snapshot. After `shadow up`, the shadow's journal shows `[archive] ready — backend=local (shadow: …`. The live space's Drive archive folder has the same file count before and after the rehearsal.
2371
+ - [ ] MANUAL-VERIFY(2026-10-08): Read the Drive activity log for the archive folder around 2026-10-08 01:21–01:26 IDT. Confirm that the deletes of the 32 `tagula-management` files came from the shadow runs. Write the result into the post-mortem.
2372
+ - [ ] MANUAL-VERIFY(2026-10-08): Recover the 32 lost `tagula-management` files on the box (read-only listing of the Drive folder against the manifest hashes, then rebuild from the space folder, `backups/` and other Drive copies by hash). Afterwards the live reconcile reports fewer than 32 missing.
2373
+
2374
+ ## Plan tagula-client-1008 / S3
2375
+
2376
+ `oauth-token-handed-to-container-can-expire-or-be-rotated-mid-run`: restart only (`src/storage/pi-auth.ts` and `src/agent/container-runner.ts` are host-side, not baked).
2377
+
2378
+ - [ ] MANUAL-VERIFY(2026-10-08): After the restart that deploys this, on each bot (both run on the long-lived `MERCURY_ANTHROPIC_OAUTH_TOKEN`): the next turn succeeds, and `journalctl --user -u mercury --since <restart>` has **no** `Refreshing anthropic oauth token ahead of expiry` and no `running consumer(s) still hold it` lines. The env token must bypass `auth.json` entirely.
2379
+
2380
+ ## Plan tagula-client-1008 / S5
2381
+
2382
+ - [ ] MANUAL-VERIFY(2026-10-08): After the Tagula box runs this fix, the owner adds `alerts: { recipients: [tagula-management] }` to `mercury.yaml` (restart needed: config is read at startup). The journal after the restart has `Operator alerts have a delivery path recipients=1` (or more), not `Operator alerts will reach no one`.
2383
+ - [ ] MANUAL-VERIFY(2026-10-08): The next operator alert on the Tagula box (credential failure, extension task failure, partial delivery) arrives in the `tagula-management` WhatsApp group, and the journal shows `Operator alerted` / `Credential failure alerted to operators`, not `could not tell an operator`.
2384
+ - [ ] MANUAL-VERIFY(2026-10-08): On this box (`~/whatsapp-bot`), after the next restart the journal has `Operator alerts have a delivery path`. If it says `will reach no one` instead, the owner's DM is not linked to a space here either.
2385
+
2386
+ ## Plan tagula-client-1008 / S6
2387
+
2388
+ `mrctl-recall-is-gated-on-the-compact-permission`: host-only (`src/core/routes/messages.ts`) plus the recall skill, which is re-copied at startup. A restart deploys it on each box.
2389
+
2390
+ - [ ] MANUAL-VERIFY(2026-10-08): After the restart on the Tagula box, a client (a `member`) asks the bot about something from an earlier article. The host log for that run has no `Permission denied … permission=compact` (or `=prompt`) line, and the trace shows `mrctl recall` returning messages, not a 403. Grep the installed skill: `grep -c "Requires \`prompt\`" <project>/.mercury/global/skills/recall/SKILL.md` prints 1.
2391
+
2392
+ ## Plan tagula-client-1008 / S10
2393
+
2394
+ Image rebuild (`src/agent/container-entry.ts` is baked), then restart; verify the derived image is built before testing.
2395
+
2396
+ - [ ] MANUAL-VERIFY(2026-10-08): `docker run --rm --entrypoint grep <derived ext image> -c "## Staying silent" /app/src/agent/container-entry.ts` prints 1 (fix `chat-silence-sentinel-is-never-taught-so-the-model-explains-its-silence`).
2397
+ - [ ] MANUAL-VERIFY(2026-10-08): In a Tagula group whose `AGENTS.md` does not mention `NO_UPDATE`, one person writes to another and asks the bot not to answer: nothing is sent to the group, and the journal shows `Chat turn answered with silence` for that run.
2398
+ - [ ] MANUAL-VERIFY(2026-10-10): Same image: `docker run --rm --entrypoint grep <derived ext image> -c "nothing to add" /app/src/agent/container-entry.ts` prints 0, and `-c "Never use it in place of an answer"` prints 1 (fix `silence-rule-lets-the-model-drop-a-direct-answer`).
2399
+ - [ ] MANUAL-VERIFY(2026-10-10): In a DM, ask the bot a plain question ("did today's article go out?"): it answers, and the journal has no `Chat turn answered with silence` line for that run. Then read that line's daily count for a few days after the deploy: frequent silence means the model is dodging (D-018).
2400
+
2401
+ ## Plan tagula-client-1008 / S2
2402
+
2403
+ Image rebuild (`src/agent/container-entry.ts` is baked), then restart; the host hint and the drift metric are in `src/core/runtime.ts` and go live with the restart.
2404
+
2405
+ - [x] MANUAL-VERIFY(2026-10-10): `docker run --rm --entrypoint grep <derived ext image> -c "## Reply language" /app/src/agent/container-entry.ts` prints 1 (fix `reply-language-drifts-to-english-on-hebrew-input`). **PASSED 2026-10-10**: `mercury-agent-ext:9b669aa35969` printed 1.
2406
+ - [x] MANUAL-VERIFY(2026-10-10): Send the bot a Hebrew question that takes many tool calls (for example a lookup across several sites). The reply is in Hebrew, and the run's trace shows the prompt ending in `<reply_language>he</reply_language>`. **PASSED 2026-10-10**: weather + USD/ILS question in `main`, Hebrew reply with tool calls, trace `mercury-1791648092438-1.jsonl` carries the tag.
2407
+ - [x] MANUAL-VERIFY(2026-10-10): In `main`, write one message in English: the reply is in English and the journal has no `Reply language drifted` line for it. **FAILED 2026-10-10** (1 of 2 English messages answered in Hebrew; filed and fixed as `reply-language-english-drifts-to-hebrew`, `9597274`). **PASSED 2026-10-11** after that deploy: 4 of 4 English messages answered in English, each trace carries `<reply_language>en</reply_language>`, a Hebrew control answered in Hebrew, 0 drift lines.
2408
+ - [ ] MANUAL-VERIFY(2026-10-10): A week after the deploy, count `Reply language drifted` lines in the journal against the Hebrew-input runs. Close or act on `docs/bugs/reply-language-drift-gets-no-rewrite.md` from that number.
2409
+ - [ ] MANUAL-VERIFY(2026-10-10): On the Tagula box, after its next deploy: the same count, by space (aggregate only). Before the fix it was 25 of 168.
2410
+
2411
+ ## mrctl recall scoped to the run's conversation (`2f5b62b` + `mrctl-recall-scope-admits-legacy-and-departed-conversation-rows` + `mrctl-recall-space-level-rows-ignore-who-actually-received-them`, local `dev`, unpushed 2026-10-09)
2412
+
2413
+ - [ ] MANUAL-VERIFY(2026-10-09): Push local `dev` to `origin/dev` once the owner approves. It carries `a1b11d9` (recall opened to members) together with its fixes `2f5b62b`, the `mrctl-recall-scope-admits-legacy-and-departed-conversation-rows` squash and the `mrctl-recall-space-level-rows-ignore-who-actually-received-them` squash; push all four together or not at all.
2414
+ - [ ] MANUAL-VERIFY(2026-10-09): Deploy is **not** restart-only. (1) `src/types.ts` is a baked file (a type-only edit, but release-gate §1 classes it as image): rebuild with `container/build.sh`, then restart. (2) `searchMessages` changed its positional signature, and `overview` is not in `src/extensions/catalog.ts`, so a restart does not refresh an installed copy. An old `actions.ts` passes `limit` as the scope: it fails closed, but the operator search quietly breaks. Wherever `overview` is installed (likely the Tagula box; not on this box), refresh it and check: `grep -c "q, null, limit" <project>/.mercury/extensions/overview/actions.ts` prints 1.
2415
+ - [ ] MANUAL-VERIFY(2026-10-09): After the deploy, in a space with a group and a **non-silent** task: let one scheduled post go out, then as a member in that group ask the bot to recall a word from it. It should find it. `SELECT count(*) FROM message_deliveries` is above 0.
2416
+ - [ ] MANUAL-VERIFY(2026-10-09): Same box, a space with a **silent** task that has run since the deploy: as a member, ask the bot to recall a word from that task's output. It should find nothing.
2417
+ - [ ] MANUAL-VERIFY(2026-10-09): Scheduled posts sent **before** this deploy have no delivery record, so members can no longer recall them. This is the accepted cost of failing closed, not a regression.
2418
+ - [ ] MANUAL-VERIFY(2026-10-09): After the deploy, in a space linking an admin DM and a group: the admin first writes a made-up word in the DM (it must be written **after** the deploy; a pre-2026-09-12 word would pass or fail for the wrong reason). Then, as a member in the group, ask the bot to recall that word. It should find nothing. Then ask for a word said in the group after the deploy; it should find it.
2419
+ - [ ] MANUAL-VERIFY(2026-10-09): Same space, as a member in the group, ask the bot to recall a word that appears only in the admin's DM from **before** 2026-09-12 (`SELECT content FROM messages WHERE space_id='<space>' AND conversation IS NULL AND role='user' LIMIT 5` finds one). It should find nothing.
2420
+
2421
+ ## Plan tagula-client-1008 / S7
2422
+
2423
+ - [ ] MANUAL-VERIFY(2026-10-10): On a console box (Tagula), in a space whose Anthropic grant was revoked: send one message. The user should get the "session expired / reconnect" reply, not "Something went wrong", and the operator should get one 🚨 DM naming `MERCURY_ANTHROPIC_OAUTH_TOKEN (console credential blob)`. A second message within the cooldown should send no second DM.
2424
+ - [ ] MANUAL-VERIFY(2026-10-10): After reconnecting in the console, the next message should get a normal answer, and a later revoke should alert again without waiting for the cooldown.
2425
+
2426
+ ## Plan monitoring-1005 / S12
2427
+
2428
+ - [ ] MANUAL-VERIFY(2026-10-11): Before re-rendering the unit, copy `~/.config/systemd/user/mercury.service` aside. Re-run `service install` from a script file with the old unit's `PATH` exported. `diff` old and new should show exactly two added lines, `NotifyAccess=all` and `WatchdogSec=120`, and the `PATH` line should be unchanged.
2429
+ - [ ] MANUAL-VERIFY(2026-10-11): After the restart (in a gap), `systemctl --user show mercury -p WatchdogUSec -p NotifyAccess` should print `2min` and `all`. The journal should have one `systemd watchdog: pinging … watchdogMs=120000 intervalMs=30000` line. Ten minutes later the unit should still be `active` with the same `MainPID` (pings are being accepted).
2430
+ - [ ] MANUAL-VERIFY(2026-10-11): Over the next days, `journalctl --user -u mercury | grep 'systemd watchdog'` should show no `ping failed` lines. Any `event loop was blocked` line names a stall worth a bug report.
2431
+
2432
+ ## Plan monitoring-1005 / S7 — a queued WhatsApp send is no longer reported as delivered (added 2026-10-11, deploy-gated: restart)
2433
+
2434
+ - [ ] MANUAL-VERIFY(2026-10-11): After restart, with WhatsApp disconnected, call `POST /api/send` to the owner's DM. It should answer **202** with `{"queued":true}` (not `{"delivered":true}`), and the journal should show `Direct send queued, not delivered`. When WhatsApp reconnects, the message should arrive once.
2435
+ - [ ] MANUAL-VERIFY(2026-10-11): The next time WhatsApp is down while a task in `MERCURY_HEARTBEAT_TASKS` runs: the journal should show `Scheduled task output queued, not delivered` and **no** `Heartbeat pinged` line, the run is `error` in `task_runs`, there is no `Scheduled task will be retried` line, and healthchecks.io goes late for that task.
2436
+
2437
+ ## Bug fix pi-stdout-chunks-decoded-separately-split-utf8-in-replies (added 2026-10-11, deploy-gated: image rebuild)
2438
+
2439
+ - [ ] MANUAL-VERIFY(2026-10-11): After `container/build.sh` and a restart in a gap, run `docker run --rm --entrypoint grep mercury-agent:latest -c onUtf8Data /app/src/agent/container-entry.ts` (should print 2 or more) and `… -c setEncoding /app/resources/pi-extensions/subagent/index.ts` (should print 2). On Tagula, check the same thing in the image tag the box runs.
2440
+ - [ ] MANUAL-VERIFY(2026-10-11): About two weeks after the deploy, `SELECT count(*) FROM messages WHERE role='assistant' AND created_at > '<deploy time>' AND content LIKE '%' || char(65533) || '%'` should be 0 on both boxes. Before the fix it was about 1 in 110 replies. A hit whose `��` shows up in pi's own `message_end` line, not on a chunk boundary, is the separate model-emitted case named in the post-mortem.
2441
+
2442
+ ## Plan monitoring-1005 / S8 — a logged-out WhatsApp device is loud, not mute (added 2026-10-11, deploy-gated: restart)
2443
+
2444
+ - [x] MANUAL-VERIFY(2026-10-11): After the restart (in a gap), `curl -s http://127.0.0.1:8787/health` should contain `"whatsappNeedsRepair":false` and `"whatsapp":true` under `adapters`. **PASSED 2026-10-12**: box at `a454651` (restarted 2026-10-11 21:16), `/health` returned `"adapters":{"whatsapp":true},"whatsappNeedsRepair":false`.
2445
+ - [ ] MANUAL-VERIFY(2026-10-11): Do not unlink the live device to test this. The next time WhatsApp really logs the bot out, the journal should show exactly one `ERROR` line `WhatsApp logged out … mercury auth whatsapp …` and no `WhatsApp reconnecting` after it. `/health` should show `"whatsappNeedsRepair":true`, and `GET /auth/whatsapp` (with the API secret) should answer `{"status":"needs-repair","reason":"logged-out"}`.
2446
+
2447
+ ## search-provider-fallback-chain: keys and Tagula deploy (2026-10-11)
2448
+
2449
+ - [ ] MANUAL-VERIFY(2026-10-11): Tagula (`tagula-assistant`) still runs 0.24.3-beta.3 without the Tavily provider; its `.env` already holds its own `MERCURY_TAVILY_API_KEY` (backup `.env.bak-2026-10-11-tavily` beside it). After it is deployed with `cdf7d09` or later and restarted in a gap, `ls /opt/tagula/assistants/tagula-assistant/.mercury/extensions/web-search/providers/` lists `tavily.ts` and one search in the management space logs `provider=tavily` (Tagula's Brave credit is gone until 2026-11-01).
2450
+ - [ ] MANUAL-VERIFY(2026-10-11): The local bot's Tavily key was only called directly, never through the chain. When Brave next runs out or is skipped, one search's journal line shows `provider=tavily`.
2451
+
2452
+ ## Plan monitoring-1005 / S9 — messages sent while the bot was offline are answered or noticed (added 2026-10-12, deploy-gated: restart)
2453
+
2454
+ - [ ] MANUAL-VERIFY(2026-10-12): After the restart (in a gap), send the bot a DM from another phone within a minute of the restart. It should be answered, and the journal should show `WhatsApp offline message admitted` (or `WhatsApp inbound` if it arrived live).
2455
+ - [ ] MANUAL-VERIFY(2026-10-12): Next real outage longer than 15 minutes (do not cause one): the journal should show one `WhatsApp offline message dropped: too old to answer` line per missed message and one `WhatsApp offline notice sent` per DM chat, and that chat should get one "I was offline…" (or Hebrew) message with the right time range.
2456
+
2457
+ ## Plan tagula-predeploy-1014 / S1 — public Google Docs links are read without gws (added 2026-10-14, deploy-gated: image rebuild)
2458
+
2459
+ - [ ] MANUAL-VERIFY(2026-10-14): As a member without gws, send the bot a public Google Docs link, then a private one. The first should come back with the document's content, the second with "this document isn't shared publicly — set it to Anyone with the link, or paste it", and no permission message either time.
2460
+
2461
+ ## Plan tagula-predeploy-1014 / S2 — a bot-check page is reported as a block, never a pass (added 2026-10-14, deploy-gated: image rebuild)
2462
+
2463
+ - [ ] MANUAL-VERIFY(2026-10-14): After the beta.4 image is built on the Tagula box (plan D1), `docker run --rm --entrypoint grep <the mercury-agent image> -c "Blocked pages" /app/src/agent/container-entry.ts` prints 1 (grep the image, not the repo).
2464
+ - [ ] MANUAL-VERIFY(2026-10-14): The next time a site blocks a fetch (for example passportnews.co.il from the Tagula box), the reply says it was blocked and quotes the page title ("Just a moment…" or "Performing security verification"). It must not say the check was passed or that the site "didn't respond after".
2465
+
2466
+ ## Plan tagula-predeploy-1014 / S3 — the first navigation waits for pinchtab's browser (added 2026-10-14, deploy-gated: image rebuild, rides beta.4)
2467
+
2468
+ - [ ] MANUAL-VERIFY(2026-10-14): After beta.4 is deployed to the Tagula box, `docker run --rm --entrypoint grep <the derived mercury-agent-ext image> -c _pinchtab_await_instance /usr/local/bin/pinchtab_ensure` prints a number above 0. Grep the image, not the repo.
2469
+ - [ ] MANUAL-VERIFY(2026-10-14): Over the next week of Tagula traces, no `Error 409` `no_current_tab` right after a run's first `pinchtab_ensure`. If a navigation does fail, `pinchtab_nav` prints `the navigation to … FAILED`, not a silent exit 0.
@@ -36,7 +36,7 @@ Custom roles can be created by assigning permissions to any role name.
36
36
 
37
37
  | Permission | Description |
38
38
  |------------|-------------|
39
- | `prompt` | Send messages to the assistant |
39
+ | `prompt` | Send messages to the assistant, and let it search the stored history its run already sees (`mrctl recall`, `GET /api/messages/search`): in a space linking several conversations, the run's own conversation plus the space's own rows, never another conversation or a scheduled-task prompt |
40
40
  | `stop` | Abort running agent and clear queue |
41
41
  | `compact` | Reset session boundary (fresh context) |
42
42
  | `tasks.list` | View scheduled tasks |
@@ -56,6 +56,7 @@ Custom roles can be created by assigning permissions to any role name.
56
56
  | `spaces.list` | View all spaces |
57
57
  | `spaces.rename` | Rename the current space |
58
58
  | `spaces.delete` | Delete current space and all related DB data |
59
+ | `spaces.pause` | Run chat `/pause` and `/resume` in a group, where slash commands are otherwise admin-only. Not a member default — grant it with `mrctl permissions set member <current list>,spaces.pause`. In a DM, `/pause` needs only `prompt` |
59
60
  | `model.list` | List the configured model chain (`mrctl model list`, chat `/model list`) |
60
61
  | `model.switch` | Pin the space to one model leg (`mrctl model switch`, chat `/model switch`) or clear that pin (`mrctl model reset`, chat `/model reset`) — takes effect on the next agent run. A pinned space has no fallback; reset is refused while the space has an active scheduled task |
61
62
  | `links.list` | See the space links touching this space, which spaces reach it and at what level, and their audit (`mrctl links list/inspect/audit`). Admin-only by default: it names every space that reaches this one. Creating, changing or revoking a link (`mrctl links create/update/revoke`) is **not** a permission — those verbs are global-admin-only, and no role grant enables them |
@@ -24,8 +24,8 @@
24
24
  Apply CLAUDE.md "a flag sampled before an `await` is a guard": queue on the throw as well as on `!connected`. Ratchet B (bare-delivery-await) must not go up.
25
25
 
26
26
  **Siblings must know** (write these into your log):
27
- - the new outcome type and where it is exported, because S13 maps the scheduler outcome after you;
28
- - the exact `/api/send` 202 body, because the relay (S6) treats it as not yet delivered;
27
+ - the new outcome type and where it is exported, because plan `tagula-client-1008` S9 (formerly S13 here) maps the scheduler outcome after you;
28
+ - the exact `/api/send` 202 body, because the WhatsApp relay (`docs/backlog/healthchecks-whatsapp-relay.md`, plan `watchdog-1011`) treats it as not yet delivered;
29
29
  - any rename in `whatsapp.ts`, because S8 and S9 edit that file after you.
30
30
 
31
31
  **Related, not yours:** `general-0928`'s `whatsapp-outbound-queue-survives-restart` will *persist* the queue. Do not persist it here. Make "queued" visible, and leave the residual pointing at that idea.
@@ -4,7 +4,7 @@
4
4
 
5
5
  | ID | Blocks | Question | Options | Answer | Answered |
6
6
  |----|--------|----------|---------|--------|----------|
7
- | Q1 | S1 | Do you approve the Goal of `docs/backlog/healthchecks-whatsapp-relay.md` (Phase 1: one DM per real up/down transition of a Tagula healthchecks.io check, sent through the home bot's `/api/send`; no reminders; the home project is not covered)? `/f-feature-planning` on a backlog doc goes straight to Architecture. | approve / feedback: … | | |
8
- | Q2 | S5 | Which Telegram bot does the daily digest send through: the one healthchecks.io already uses, or a new dedicated bot? A new token is a secret, and it must be mirrored into a gitignored local file in the same sitting (global secrets rule). | reuse / new | | |
9
- | Q3 | S13 | Lane: does Avishai Tsabari own `src/core/runtime.ts` (landed commits in the last 14 d, none in flight)? | ours / theirs / split | | |
10
- | Q4 | S11 | Lane: does Avishai Tsabari own `src/agent/container-entry.ts` (landed commits in the last 14 d, none in flight)? | ours / theirs / split | | |
7
+ | Q1 | S1 | Do you approve the Goal of `docs/backlog/healthchecks-whatsapp-relay.md` (Phase 1: one DM per real up/down transition of a Tagula healthchecks.io check, sent through the home bot's `/api/send`; no reminders; the home project is not covered)? `/f-feature-planning` on a backlog doc goes straight to Architecture. | approve / feedback: … | approve — the rewritten Goal of 2026-10-07 (fleet-monitor Worker relay feed). Owner also wants every alert on all three channels: email, Telegram and WhatsApp, WhatsApp being the one most watched **Moot 2026-10-11:** this approval was for the Worker-shape Goal, which was reverted the same day to healthchecks.io; S6 dropped, re-approval tracked in plan `watchdog-1011` | 2026-10-11 (owner; written by Claude) |
8
+ | Q2 | S5 | Which Telegram bot does the daily digest send through: the one healthchecks.io already uses, or a new dedicated bot? A new token is a secret, and it must be mirrored into a gitignored local file in the same sitting (global secrets rule). | reuse / new | moot — S5 dropped 2026-10-11 (the digest waits for phase 3; its transport is re-decided then, `notes/2026-10-11-monitoring-rollout-order.md`) | 2026-10-11 (Claude, on the owner's instruction) |
9
+ | Q3 | S13 | Lane: does Avishai Tsabari own `src/core/runtime.ts` (landed commits in the last 14 d, none in flight)? | ours / theirs / split | moot — S13 moved to plan tagula-client-1008 with `--drop`; the lane is measured there (no open PR, no live branch in the file; Avishai's last edits landed) | 2026-10-08 (Claude, on the owner's instruction to decide) |
10
+ | Q4 | S11 | Lane: does Avishai Tsabari own `src/agent/container-entry.ts` (landed commits in the last 14 d, none in flight)? | ours / theirs / split | moot — S11 moved to plan tagula-client-1008 with `--drop`; the lane is measured there (no open PR, no live branch in the file; Avishai's last edits landed) | 2026-10-08 (Claude, on the owner's instruction to decide) |
@@ -1,10 +1,10 @@
1
1
  # Plan: monitoring-1005
2
2
 
3
- **Status**: Active
4
- **Created**: 2026-10-05 **Last updated**: 2026-10-05
3
+ **Status**: Archived
4
+ **Created**: 2026-10-05 **Last updated**: 2026-10-12
5
5
  **Landing mode**: pr
6
6
  **Max width**: 4
7
- **Inputs**: build monitoring — live-bot failure monitoring: healthchecks-whatsapp-relay, box-watchdog, run-outcome-counters, operator-alert-ping-mirror, daily-ops-digest-via-telegram, space-probe-harness addendum, and bugs whatsapp-messages-sent-while-offline-are-dropped-forever, queued-whatsapp-send-is-reported-as-delivered, health-reports-every-adapter-as-up, whatsapp-logged-out-socket-leaves-the-process-up-and-mute, console-oauth-invalid-grant-reaches-no-operator, third-party-apps-400-is-retried-and-shown-as-try-again, service-unit-never-restarts-a-hung-process, scheduled-run-over-cloud-quota-posts-the-quota-text-as-output
7
+ **Inputs**: build monitoring — live-bot failure monitoring: healthchecks-whatsapp-relay, box-watchdog, run-outcome-counters, operator-alert-ping-mirror, daily-ops-digest-via-telegram, space-probe-harness addendum, and bugs whatsapp-messages-sent-while-offline-are-dropped-forever, queued-whatsapp-send-is-reported-as-delivered, health-reports-every-adapter-as-up, whatsapp-logged-out-socket-leaves-the-process-up-and-mute, console-oauth-invalid-grant-reaches-no-operator, third-party-apps-400-is-retried-and-shown-as-try-again, service-unit-never-restarts-a-hung-process, scheduled-run-over-cloud-quota-posts-the-quota-text-as-output; `--rebuild --drop S5 S6` (owner, 2026-10-11)
8
8
  **Me**: saharw01, Saharw01@gmail.com
9
9
 
10
10
  > Written by `/f-ops-plan` build (and `--rebuild`) and `archive` only. Nothing perishable lives here — no base sha, no other author's file list, no story counts; `next` measures those every time it runs. `plan-state.sh` parses the tables below by their header row, so keep the column order.
@@ -13,6 +13,10 @@
13
13
 
14
14
  > **Session rules.** The owner is present, but no session deploys. Do not run `~/sync-mercury.sh`, restart the service, rebuild the image, or read `~/whatsapp-bot/.env`. Each session stops after its local commits and the check gate (CLAUDE.local.md "Push access"). The only push allowed is the docs-only claim push. Live checks go to `docs/pending-verification.md` under the session's heading.
15
15
 
16
+ > **Rebuild 2026-10-11 (owner).** Monitoring stays on healthchecks.io and the fleet-monitor Worker is deferred (`docs/notes/2026-10-06-round0-plans-adversarial-review.md` § Handled so far). S5 (the digest) and S6 (the relay build) are dropped: the digest waits for phase 3, and the relay's Goal changed again, so it is re-planned in plan `watchdog-1011` together with box-watchdog. Q1 and Q2 are moot. This plan now carries the live bot's WhatsApp reliability fixes only.
17
+
18
+ > **Cross-repo.** The order across mercury, tagula-agents and fleet-monitor is `docs/notes/2026-10-11-monitoring-rollout-order.md`. This plan runs in parallel with phases 1–2 there. It has no dependency on another repo, and none waits on it.
19
+
16
20
  ## Items
17
21
 
18
22
  | ID | Kind | Slug | Doc | Command | Round | Needs |
@@ -21,15 +25,10 @@
21
25
  | S2 | plan | box-watchdog | docs/ideas/box-watchdog.md | /f-feature-planning box-watchdog | 0 | — |
22
26
  | S3 | plan | run-outcome-counters | docs/ideas/run-outcome-counters.md | /f-feature-planning run-outcome-counters | 0 | — |
23
27
  | S4 | plan | operator-alert-ping-mirror | docs/ideas/operator-alert-ping-mirror.md | /f-feature-planning operator-alert-ping-mirror | 0 | — |
24
- | S5 | plan | daily-ops-digest-via-telegram | docs/ideas/daily-ops-digest-via-telegram.md | /f-feature-planning daily-ops-digest-via-telegram | 0 | Q2 |
25
- | S6 | feature | healthchecks-whatsapp-relay | docs/backlog/healthchecks-whatsapp-relay.md | /f-feature-dev healthchecks-whatsapp-relay | 4 | — |
26
28
  | S7 | bug | queued-whatsapp-send-is-reported-as-delivered | docs/bugs/queued-whatsapp-send-is-reported-as-delivered.md | /f-bug-fix queued-whatsapp-send-is-reported-as-delivered | 1 | — |
27
29
  | S8 | bug | whatsapp-logged-out-socket-leaves-the-process-up-and-mute | docs/bugs/whatsapp-logged-out-socket-leaves-the-process-up-and-mute.md | /f-bug-fix whatsapp-logged-out-socket-leaves-the-process-up-and-mute | 2 | — |
28
30
  | S9 | bug | whatsapp-messages-sent-while-offline-are-dropped-forever | docs/bugs/whatsapp-messages-sent-while-offline-are-dropped-forever.md | /f-bug-fix whatsapp-messages-sent-while-offline-are-dropped-forever | 3 | — |
29
- | S10 | bug | console-oauth-invalid-grant-reaches-no-operator | docs/bugs/console-oauth-invalid-grant-reaches-no-operator.md | /f-bug-fix console-oauth-invalid-grant-reaches-no-operator | 1 | — |
30
- | S11 | bug | third-party-apps-400-is-retried-and-shown-as-try-again | docs/bugs/third-party-apps-400-is-retried-and-shown-as-try-again.md | /f-bug-fix third-party-apps-400-is-retried-and-shown-as-try-again | 1 | Q4 |
31
31
  | S12 | bug | service-unit-never-restarts-a-hung-process | docs/bugs/service-unit-never-restarts-a-hung-process.md | /f-bug-fix service-unit-never-restarts-a-hung-process | 1 | — |
32
- | S13 | bug | scheduled-run-over-cloud-quota-posts-the-quota-text-as-output | docs/bugs/scheduled-run-over-cloud-quota-posts-the-quota-text-as-output.md | /f-bug-fix scheduled-run-over-cloud-quota-posts-the-quota-text-as-output | 2 | Q3 |
33
32
 
34
33
  > Kind ∈ `feature` | `bug` | `refactor` | `plan` (a Round 0 planning session) | `story` (from `--goal`; runs `/f-feature-dev`).
35
34
  > Needs = decision IDs from `decisions.md` that must be answered before this session may launch, or `—`.
@@ -41,12 +40,11 @@
41
40
  |------|----|------|-------|
42
41
  | S7 | S8 | start-after | file: src/adapters/whatsapp.ts (both predicted) |
43
42
  | S8 | S9 | start-after | file: src/adapters/whatsapp.ts (both predicted) |
44
- | S7 | S13 | start-after | file: src/core/task-scheduler.ts (both predicted) |
45
- | S7 | S6 | merge-after | semantic: the relay treats a 2xx from /api/send as delivered, which holds only once a queued send answers 202 queued (user) |
46
43
 
47
44
  > Kind ∈ `start-after` (To may not launch until From is landed) | `merge-after` (To may launch now, may not land until From is landed).
48
45
  > Basis starts with `file:` (inferred from the collision map) or `semantic:` (asked) — never mixed in one row.
49
- > Semantic edges: asked 2026-10-05, answer `S6 after S7`.
46
+ > Semantic edges: asked 2026-10-05, answer `S6 after S7`. S6 was dropped on 2026-10-11, so the edge went with it; the relay in plan `watchdog-1011` lands after this plan's S7 by its own edge.
47
+ > Rebuild 2026-10-08 (`--drop S10 S11 S13`): the three moved to plan `tagula-client-1008`, which owns the files they share with its higher-priority sessions. That plan's S9 (formerly S13 here) now carries a cross-plan `start-after` edge onto this plan's S7 for `src/core/task-scheduler.ts`.
50
48
  > S7 → S9 is implied by the chain through S8 and is not written separately.
51
49
 
52
50
  ## Rounds
@@ -55,12 +53,11 @@
55
53
 
56
54
  | Session | Action | Clears |
57
55
  |---------|--------|--------|
58
- | S1 | plan healthchecks-whatsapp-relay: Architecture (Phase 2), after Q1 | S6 (via `--rebuild`) |
56
+ | S1 | plan healthchecks-whatsapp-relay (Goal only; Architecture moved to plan `watchdog-1011`) | — |
59
57
  | S2 | plan box-watchdog | — |
60
58
  | S3 | plan run-outcome-counters | — |
61
59
  | S4 | plan operator-alert-ping-mirror | — |
62
- | S5 | plan daily-ops-digest-via-telegram, after Q2 | — |
63
- | — | owner answers decisions.md Q1–Q4 | S1, S5, S11, S13 |
60
+ | — | decisions.md Q1–Q4 all closed (Q3, Q4 moot since 2026-10-08; Q1, Q2 moot since 2026-10-11) | — |
64
61
 
65
62
  > S2–S5 are ideas, so they get planning sessions only. Their implementation sessions are planned once their Architecture exists: `--add` them in a `--rebuild`, or put them in a follow-up plan.
66
63
 
@@ -69,8 +66,6 @@
69
66
  | Session | Item | Predicted surfaces (count) |
70
67
  |---------|------|----------------------------|
71
68
  | S7 | queued-whatsapp-send-is-reported-as-delivered | 4 |
72
- | S10 | console-oauth-invalid-grant-reaches-no-operator | 1 |
73
- | S11 | third-party-apps-400-is-retried-and-shown-as-try-again | 2 |
74
69
  | S12 | service-unit-never-restarts-a-hung-process | 2 |
75
70
 
76
71
  ### Round 2
@@ -78,7 +73,6 @@
78
73
  | Session | Item | Predicted surfaces (count) |
79
74
  |---------|------|----------------------------|
80
75
  | S8 | whatsapp-logged-out-socket-leaves-the-process-up-and-mute | 1 |
81
- | S13 | scheduled-run-over-cloud-quota-posts-the-quota-text-as-output | 2 |
82
76
 
83
77
  ### Round 3
84
78
 
@@ -86,12 +80,6 @@
86
80
  |---------|------|----------------------------|
87
81
  | S9 | whatsapp-messages-sent-while-offline-are-dropped-forever | 1 |
88
82
 
89
- ### Round 4
90
-
91
- | Session | Item | Predicted surfaces (count) |
92
- |---------|------|----------------------------|
93
- | S6 | healthchecks-whatsapp-relay | 0 (stale until S1 lands — then `--rebuild`) |
94
-
95
83
  ## Collision map
96
84
 
97
85
  > Whole files, predicted. `docs/` and infrastructure paths are excluded exactly as `overlap-check.sh` excludes them. Nine such paths were ignored: the research note, cited once by each of the seven bugs, plus `ideas/run-outcome-counters.md` and `ideas/whatsapp-outbound-queue-survives-restart.md`. Line-range variants were collapsed to their file: `src/adapters/whatsapp.ts:380`, `:653-661` and `:358-376`, `src/agent/container-runner.ts:740-843`, and `src/core/runtime.ts:3285-3337`.
@@ -99,7 +87,6 @@
99
87
  | File | Sessions |
100
88
  |------|----------|
101
89
  | src/adapters/whatsapp.ts | S7, S8, S9 |
102
- | src/core/task-scheduler.ts | S7, S13 |
103
90
 
104
91
  ## Predicted surfaces
105
92
 
@@ -111,10 +98,6 @@
111
98
 
112
99
  ### S4
113
100
 
114
- ### S5
115
-
116
- ### S6
117
-
118
101
  ### S7
119
102
 
120
103
  - src/adapters/whatsapp.ts
@@ -130,25 +113,11 @@
130
113
 
131
114
  - src/adapters/whatsapp.ts
132
115
 
133
- ### S10
134
-
135
- - src/agent/container-runner.ts
136
-
137
- ### S11
138
-
139
- - src/agent/container-entry.ts
140
- - src/agent/pi-failure-class.ts
141
-
142
116
  ### S12
143
117
 
144
118
  - src/cli/service-unit.ts
145
119
  - src/main.ts
146
120
 
147
- ### S13
148
-
149
- - src/core/runtime.ts
150
- - src/core/task-scheduler.ts
151
-
152
121
  ## Adjudicated overlaps
153
122
 
154
123
  > Pre-answers for the execution commands' preflight overlap prompt. Scoped to exact branch + file pairs on branches that belong to NO active plan (a hand-opened worktree, another contributor). A branch of a sibling plan's session is never listed here — it becomes a cross-plan edge instead.
@@ -168,8 +137,8 @@
168
137
 
169
138
  | File / area | Author | Basis |
170
139
  |-------------|--------|-------|
171
- | src/core/runtime.ts | Avishai Tsabari | landed commits in 14 d (`21ea163` 09-28, `b866976` 10-01, `a6aa018` 10-05); lane Q3 (S13) |
172
- | src/agent/container-entry.ts | Avishai Tsabari | landed commits in 14 d; lane Q4 (S11) |
140
+ | src/core/runtime.ts | Avishai Tsabari | landed commits in 14 d (`21ea163` 09-28, `b866976` 10-01, `a6aa018` 10-05); lane Q3 (S13; moved to plan tagula-client-1008 on 2026-10-08) |
141
+ | src/agent/container-entry.ts | Avishai Tsabari | landed commits in 14 d; lane Q4 (S11; moved to plan tagula-client-1008 on 2026-10-08) |
173
142
  | src/core/operator-alerts.ts | Avishai Tsabari | landed commits in 14 d. No session predicts it yet; S4's implementation will, so re-measure at `--rebuild` |
174
143
 
175
144
  > Avishai's live item at build time was `host-notices-are-english-in-hebrew-spaces` (promoted to debug on `origin/dev` `200cd25`; it names `src/core/handler.ts` and `src/core/system-messages.ts`). Neither intersects this plan.
@@ -178,5 +147,10 @@
178
147
 
179
148
  | Item | Reason | Home |
180
149
  |------|--------|------|
150
+ | S5 daily-ops-digest-via-telegram | dropped by owner 2026-10-11: on hold until phase 3, transport to be re-decided (`notes/2026-10-11-monitoring-rollout-order.md`) | docs/ideas/daily-ops-digest-via-telegram.md |
151
+ | S6 healthchecks-whatsapp-relay | dropped by owner 2026-10-11: the Goal reverted to healthchecks.io; re-planned in plan `watchdog-1011` | docs/backlog/healthchecks-whatsapp-relay.md |
181
152
  | health-reports-every-adapter-as-up | the WhatsApp half is fixed on local `dev` as `6cf4ea7` (`/health` reads `getQrStatus()`), but the bug doc is still `Open` and was never archived. The rest (`queuedOutbound`, `lastCloseReason`) needs its own decision: close the doc with those fields as residuals, or narrow it. The idea `dashboard-adapter-status-is-frozen-true` (`d426fb7`) is the sibling surface. | docs/bugs/health-reports-every-adapter-as-up.md |
182
153
  | space-probe-harness | the idea says "deliberately not now". It waits on rehearsal-bench M2.2 (`simulateIngress`) and on tagula-agents settling its probe shape. The 2026-10-05 cross-bot WhatsApp probe addendum also needs S2 (box-watchdog) to exist as the reader. | docs/ideas/space-probe-harness.md |
154
+ | S10 console-oauth-invalid-grant-reaches-no-operator | dropped by user — moved to plan tagula-client-1008 (2026-10-08) | docs/bugs/console-oauth-invalid-grant-reaches-no-operator.md |
155
+ | S11 third-party-apps-400-is-retried-and-shown-as-try-again | dropped by user — moved to plan tagula-client-1008 (2026-10-08) | docs/bugs/third-party-apps-400-is-retried-and-shown-as-try-again.md |
156
+ | S13 scheduled-run-over-cloud-quota-posts-the-quota-text-as-output | dropped by user — moved to plan tagula-client-1008 (2026-10-08) | docs/bugs/scheduled-run-over-cloud-quota-posts-the-quota-text-as-output.md |
@@ -0,0 +1,47 @@
1
+ ## Launched — 2026-10-11T11:14Z
2
+ Branch: worktree-fix-service-unit-never-restarts-a-hung-process
3
+ Session: 3e65697f-325c-4c1e-9d4f-1a70538134fb
4
+
5
+ ## Report — 2026-10-11T12:34Z
6
+ Outcome: delivered
7
+ Delivered: local
8
+ Blocked-on: —
9
+ Deploy needs: unit re-render (PATH-preserving, diff before/after) + restart in a gap
10
+ Source: command
11
+ Files changed:
12
+ - docs/debug/moderate/2026-10-11-service-unit-never-restarts-a-hung-process.md
13
+ - docs/debug/service-unit-never-restarts-a-hung-process.md
14
+ - docs/pending-verification.md
15
+ - src/cli/mercury.ts
16
+ - src/cli/service-unit.ts
17
+ - src/core/systemd-watchdog.ts
18
+ - src/main.ts
19
+ - tests/fixtures/release-gate/regression-map.json
20
+ - tests/service-unit.test.ts
21
+ - tests/systemd-watchdog.test.ts
22
+ Siblings must know:
23
+ - watchdog-1011/S1 (box-watchdog): the in-process watchdog catches a frozen event loop only. A wedged socket or a deadlocked await keeps the timer running and is still the external /health probe's job.
24
+ - The unit now has NotifyAccess=all: any process in the unit's cgroup can send sd_notify messages. Nothing else uses it today.
25
+ --- final report (verbatim) ---
26
+ ~~~
27
+ Fixed service-unit-never-restarts-a-hung-process (moderate).
28
+ Squash commit a80b7dd on local dev (on top of 65a260f, a parallel session's local docs(verify) tick that was replayed onto origin/dev to reconcile the divergence). NOT pushed: push needs owner approval.
29
+ Files: src/cli/service-unit.ts (NotifyAccess=all, WatchdogSec=120), src/core/systemd-watchdog.ts (new: runtime pinger, wrapper startup raise + SIGABRT handler), src/main.ts, src/cli/mercury.ts, tests/systemd-watchdog.test.ts, tests/service-unit.test.ts, tests/fixtures/release-gate/regression-map.json, docs/pending-verification.md.
30
+ Post-mortem: docs/debug/moderate/2026-10-11-service-unit-never-restarts-a-hung-process.md
31
+ Proved on real systemd (transient user units): healthy stays active; frozen child -> Result=watchdog with the wrapper's log line; NotifyAccess=main negative control fails silently; an 8 s blocking pull survives only with the raise.
32
+ Gate: ~/check-mercury.sh check — 16/16 links, 6928 pass / 0 fail.
33
+ DELIVERED: local
34
+ ~~~
35
+
36
+ ## Exit — 2026-10-11T12:37Z
37
+ Verdict: unattributed (2 files)
38
+ Source: session-end-hook
39
+ ~~~
40
+ EXIT-RECEIPT: unattributed (2 files)
41
+ SHARED: /home/guysaha/projects/mercury with live session 17b2b227-e433-4924-b157-bc8594f320ea (since 2026-10-11T10:49:02Z)
42
+ SHARED: /home/guysaha/projects/mercury with live session b85f6792-899d-4e1d-95ba-4917fe8fbb88 (since 2026-10-11T08:46:30Z)
43
+ SHARED: /home/guysaha/projects/mercury with live session c9491da9-e77d-48a0-984a-ed8a7a779e97 (since 2026-10-11T11:14:08Z)
44
+ UNATTRIBUTED: /home/guysaha/projects/mercury/docs/plans/monitoring-1005/sessions/ — 2 files (S12.md, S7.md): changed during this session, but live session 17b2b227-e433-4924-b157-bc8594f320ea b85f6792-899d-4e1d-95ba-4917fe8fbb88 c9491da9-e77d-48a0-984a-ed8a7a779e97 shares this checkout -> nothing records whose this is: ask the owner; never discard it
45
+ DEFERRED: push 3 commit(s) on dev -> git (/f-status reports ahead=3)
46
+ NOTE: remote state as of the last fetch (--no-fetch)
47
+ ~~~
@@ -0,0 +1,75 @@
1
+ ## Launched — 2026-10-11T11:14Z
2
+ Branch: worktree-fix-queued-whatsapp-send-is-reported-as-delivered
3
+ Session: c9491da9-e77d-48a0-984a-ed8a7a779e97
4
+
5
+ ## Report — 2026-10-11T13:14Z
6
+ Outcome: delivered
7
+ Delivered: local
8
+ Blocked-on: —
9
+ Deploy needs: restart
10
+ Source: command
11
+ Files changed:
12
+ - docs/backlog/box-watchdog.md
13
+ - docs/backlog/healthchecks-whatsapp-relay.md
14
+ - docs/backlog/operator-alert-ping-mirror.md
15
+ - docs/backlog/run-outcome-counters.md
16
+ - docs/bugs/queued-whatsapp-send-is-reported-as-delivered.md
17
+ - docs/debug/major/2026-10-11-queued-whatsapp-send-is-reported-as-delivered.md
18
+ - docs/debug/moderate/2026-10-11-service-unit-never-restarts-a-hung-process.md
19
+ - docs/debug/service-unit-never-restarts-a-hung-process.md
20
+ - docs/ideas/daily-ops-digest-via-telegram.md
21
+ - docs/notes/2026-10-06-round0-plans-adversarial-review.md
22
+ - docs/notes/2026-10-11-monitoring-rollout-order.md
23
+ - docs/pending-verification.md
24
+ - docs/plans/monitoring-1005/briefs/S5.md
25
+ - docs/plans/monitoring-1005/briefs/S6.md
26
+ - docs/plans/monitoring-1005/briefs/S7.md
27
+ - docs/plans/monitoring-1005/decisions.md
28
+ - docs/plans/monitoring-1005/plan.md
29
+ - docs/plans/watchdog-1011/briefs/S1.md
30
+ - docs/plans/watchdog-1011/decisions.md
31
+ - docs/plans/watchdog-1011/plan.md
32
+ - src/adapters/whatsapp.ts
33
+ - src/bridges/whatsapp.ts
34
+ - src/cli/mercury.ts
35
+ - src/cli/service-unit.ts
36
+ - src/core/routes/send.ts
37
+ - src/core/systemd-watchdog.ts
38
+ - src/core/task-scheduler.ts
39
+ - src/core/task-sender.ts
40
+ - src/main.ts
41
+ - src/types.ts
42
+ - tests/direct-send.test.ts
43
+ - tests/fixtures/release-gate/regression-map.json
44
+ - tests/scheduler-heartbeat.test.ts
45
+ - tests/service-unit.test.ts
46
+ - tests/systemd-watchdog.test.ts
47
+ - tests/task-sender.test.ts
48
+ - tests/whatsapp-outbound-queue.test.ts
49
+ Siblings must know:
50
+ - New outcome types: `OutboundDelivery` + optional `PlatformBridge.deliver` in src/types.ts; `OutboundQueuedError` / `QueuedDelivery` exported from src/core/task-sender.ts; `QueuedPostResult` / `WhatsAppPostResult` from src/adapters/whatsapp.ts. `TaskDeliveryError.queued` (src/core/task-scheduler.ts) is true when the cause is an OutboundQueuedError — tagula-client-1008 S9 maps the scheduler outcome after this: a queued run is ledgered `error`, no heartbeat, no retry, no failure report. Sent-to-one/queued-to-another is still a PartialDeliveryError, which runtime.ts counts as `posted` (pings) — S9's call.
51
+ - POST /api/send answers exactly `202` with body `{"queued": true}` when the send was parked (no spaceId); 200 `{delivered: true, spaceId}` is now only a real send. The WhatsApp relay must treat 202 as not delivered.
52
+ - whatsapp.ts: no renames. `postMessage` return type is now `WhatsAppPostResult` (adds optional `queued`); `queueOutbound` returns `QueuedPostResult`. Bridge `sendReply` behaviour unchanged; new `deliver` and private `send` share one path.
53
+ - Other sendDirect callers (routes/capability.ts, extension ctx.send) now get an OutboundQueuedError throw on a queued send, and runtime.sendDirect logs "Direct send failed" before /api/send answers 202 — runtime.ts was out of this lane.
54
+ --- final report (verbatim) ---
55
+ ~~~
56
+ Fixed: a queued WhatsApp send is reported as delivered (major).
57
+ Squash commit 92615e7 on local dev (not pushed). Files: src/adapters/whatsapp.ts, src/bridges/whatsapp.ts, src/types.ts, src/core/task-sender.ts, src/core/task-scheduler.ts, src/core/routes/send.ts, + 4 test files and tests/fixtures/release-gate/regression-map.json.
58
+ Post-mortem: docs/debug/major/2026-10-11-queued-whatsapp-send-is-reported-as-delivered.md
59
+ Gate: ~/check-mercury.sh check — all 16 links passed, 6943 pass / 0 fail.
60
+ Live checks: docs/pending-verification.md "## Plan monitoring-1005 / S7".
61
+ DELIVERED: local (push not approved in this session). The claim push of the promotion commit was refused by the auto-mode classifier twice; not pushed.
62
+ Rebase note: local dev had diverged from origin/dev (3 local, 2 origin docs-only commits); the branch was replayed onto local dev, so dev must be reconciled with origin/dev before the push.
63
+ ~~~
64
+
65
+ ## Exit — 2026-10-11T13:25Z
66
+ Verdict: unattributed (2 files)
67
+ Source: session-end-hook
68
+ ~~~
69
+ EXIT-RECEIPT: unattributed (2 files)
70
+ SHARED: /home/guysaha/projects/mercury with live session 17b2b227-e433-4924-b157-bc8594f320ea (since 2026-10-11T10:49:02Z)
71
+ SHARED: /home/guysaha/projects/mercury with live session b85f6792-899d-4e1d-95ba-4917fe8fbb88 (since 2026-10-11T08:46:30Z)
72
+ UNATTRIBUTED: /home/guysaha/projects/mercury/docs/plans/monitoring-1005/sessions/ — 2 files (S12.md, S7.md): changed during this session, but live session 17b2b227-e433-4924-b157-bc8594f320ea b85f6792-899d-4e1d-95ba-4917fe8fbb88 shares this checkout -> nothing records whose this is: ask the owner; never discard it
73
+ DEFERRED: push 5 commit(s) on dev, which is also 2 behind origin/dev -> git pull --rebase first, then push (/f-status reports ahead=5)
74
+ NOTE: remote state as of the last fetch (--no-fetch)
75
+ ~~~