@rubytech/create-maxy-code 0.1.472 → 0.1.473

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 (125) hide show
  1. package/dist/__tests__/google-client-id-env.test.js +12 -10
  2. package/dist/index.js +6 -29
  3. package/dist/port-resolution.js +5 -5
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand.json +1 -0
  6. package/payload/platform/docs/superpowers/plans/2026-07-18-ledger-write-path-fix.md +109 -0
  7. package/payload/platform/lib/ledger-core/dist/reconcile.d.ts +7 -0
  8. package/payload/platform/lib/ledger-core/dist/reconcile.d.ts.map +1 -1
  9. package/payload/platform/lib/ledger-core/dist/reconcile.js +5 -2
  10. package/payload/platform/lib/ledger-core/dist/reconcile.js.map +1 -1
  11. package/payload/platform/lib/ledger-core/src/__tests__/reconcile.test.ts +20 -0
  12. package/payload/platform/lib/ledger-core/src/reconcile.ts +12 -2
  13. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +24 -5
  14. package/payload/platform/plugins/docs/references/google-guide.md +10 -3
  15. package/payload/platform/plugins/docs/references/ledger.md +9 -1
  16. package/payload/platform/plugins/docs/references/troubleshooting.md +4 -0
  17. package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
  18. package/payload/platform/plugins/google/PLUGIN.md +4 -1
  19. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +79 -28
  20. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  21. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.d.ts +2 -0
  22. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.js +54 -0
  24. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.js.map +1 -0
  25. package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js +26 -1
  26. package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js.map +1 -1
  27. package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js +3 -2
  28. package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js.map +1 -1
  29. package/payload/platform/plugins/google/mcp/dist/index.d.ts +9 -5
  30. package/payload/platform/plugins/google/mcp/dist/index.d.ts.map +1 -1
  31. package/payload/platform/plugins/google/mcp/dist/index.js +38 -37
  32. package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
  33. package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts +10 -7
  34. package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts.map +1 -1
  35. package/payload/platform/plugins/google/mcp/dist/lib/google-client.js +25 -13
  36. package/payload/platform/plugins/google/mcp/dist/lib/google-client.js.map +1 -1
  37. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +58 -17
  38. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  39. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +143 -37
  40. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  41. package/payload/platform/plugins/google/references/auth.md +91 -74
  42. package/payload/platform/plugins/ledger/PLUGIN.md +13 -1
  43. package/payload/platform/plugins/ledger/mcp/dist/index.js +23 -15
  44. package/payload/platform/plugins/ledger/mcp/dist/index.js.map +1 -1
  45. package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts +11 -1
  46. package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts.map +1 -1
  47. package/payload/platform/plugins/ledger/mcp/dist/lib/read.js +20 -1
  48. package/payload/platform/plugins/ledger/mcp/dist/lib/read.js.map +1 -1
  49. package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts +14 -11
  50. package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts.map +1 -1
  51. package/payload/platform/plugins/ledger/mcp/dist/lib/types.js.map +1 -1
  52. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.d.ts +12 -0
  53. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.d.ts.map +1 -0
  54. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.js +50 -0
  55. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.js.map +1 -0
  56. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts +5 -5
  57. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts.map +1 -1
  58. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js +11 -11
  59. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js.map +1 -1
  60. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts +7 -2
  61. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts.map +1 -1
  62. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js +9 -3
  63. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js.map +1 -1
  64. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts +7 -0
  65. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts.map +1 -1
  66. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js +3 -4
  67. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js.map +1 -1
  68. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts +1 -1
  69. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts.map +1 -1
  70. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js +4 -1
  71. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js.map +1 -1
  72. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +27 -2
  73. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  74. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +33 -2
  75. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  76. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  77. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  78. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  79. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  80. package/payload/platform/services/claude-session-manager/dist/http-server.js +3 -0
  81. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  82. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  83. package/payload/server/{chunk-BSTIQX52.js → chunk-Y6V45R6M.js} +1 -12
  84. package/payload/server/maxy-edge.js +1 -1
  85. package/payload/server/public/activity.html +6 -6
  86. package/payload/server/public/assets/{AdminLoginScreens-BfamGqS7.js → AdminLoginScreens-B7TQZV8u.js} +1 -1
  87. package/payload/server/public/assets/{AdminShell-5nHOAzXO.js → AdminShell-DAuri4Yh.js} +1 -1
  88. package/payload/server/public/assets/{Checkbox-CD6aHwac.js → Checkbox-B1XhnhPk.js} +1 -1
  89. package/payload/server/public/assets/activity-kRwzxEKU.js +1 -0
  90. package/payload/server/public/assets/{admin-Cpcw_YE-.js → admin-BdcccSb5.js} +1 -1
  91. package/payload/server/public/assets/{browser-0znOwk1W.js → browser-B6woQ2qX.js} +1 -1
  92. package/payload/server/public/assets/{calendar-CykigHdg.js → calendar-CalCeg5T.js} +1 -1
  93. package/payload/server/public/assets/chat-9s2-L06v.js +1 -0
  94. package/payload/server/public/assets/chevron-left-C3ho8SnB.js +1 -0
  95. package/payload/server/public/assets/data-Cfr-7ERI.js +1 -0
  96. package/payload/server/public/assets/{graph-JV5_xF3V.js → graph-HeZaatSQ.js} +1 -1
  97. package/payload/server/public/assets/{graph-labels-DPYORjBH.js → graph-labels-4W7JuOgG.js} +1 -1
  98. package/payload/server/public/assets/{maximize-2-8vKr3h21.js → maximize-2-DKx-aTPb.js} +1 -1
  99. package/payload/server/public/assets/{operator-Liul1QEq.js → operator-DD9L2VJM.js} +1 -1
  100. package/payload/server/public/assets/{page-Cg7B1RQx.js → page-Ceado9Kr.js} +1 -1
  101. package/payload/server/public/assets/{page-CYRA87CB.js → page-tJxw0zNO.js} +1 -1
  102. package/payload/server/public/assets/{public-B4HMtpjt.js → public-BYFWxyeC.js} +1 -1
  103. package/payload/server/public/assets/{rotate-ccw-sz5IQSnr.js → rotate-ccw-DrzdV9h7.js} +1 -1
  104. package/payload/server/public/assets/{tasks-D9oYgEzs.js → tasks-DSwoxGzh.js} +1 -1
  105. package/payload/server/public/assets/{time-entry-format-CSuCexpM.js → time-entry-format-Bn79w6tq.js} +1 -1
  106. package/payload/server/public/assets/{triangle-alert-ClS81-CU.js → triangle-alert-CjDVh6r-.js} +1 -1
  107. package/payload/server/public/assets/{useCopyFeedback-Cn6YgeNx.js → useCopyFeedback-DXHkkJw-.js} +1 -1
  108. package/payload/server/public/assets/{useSelectionMode-BaD-ZZRk.js → useSelectionMode-D2H8jAhE.js} +1 -1
  109. package/payload/server/public/assets/{useSubAccountSwitcher-CNZL3PKn.css → useSubAccountSwitcher-Br7Z6Cpu.css} +1 -1
  110. package/payload/server/public/assets/{useVoiceRecorder-BOzHrDAU.js → useVoiceRecorder-zUvPe55I.js} +1 -1
  111. package/payload/server/public/browser.html +5 -5
  112. package/payload/server/public/calendar.html +6 -6
  113. package/payload/server/public/chat.html +12 -12
  114. package/payload/server/public/data.html +11 -11
  115. package/payload/server/public/graph.html +11 -11
  116. package/payload/server/public/index.html +14 -14
  117. package/payload/server/public/operator.html +14 -14
  118. package/payload/server/public/public.html +12 -12
  119. package/payload/server/public/tasks.html +5 -5
  120. package/payload/server/server.js +1414 -1324
  121. package/payload/server/public/assets/activity-Dj2nJzPw.js +0 -1
  122. package/payload/server/public/assets/chat-DIOJZ411.js +0 -1
  123. package/payload/server/public/assets/chevron-left-Cq7UvOI0.js +0 -1
  124. package/payload/server/public/assets/data-lHgqlhmu.js +0 -1
  125. /package/payload/server/public/assets/{useSubAccountSwitcher-CvjWJSGv.js → useSubAccountSwitcher-CUJpgkKI.js} +0 -0
@@ -16,8 +16,11 @@ outcome (values themselves deliberately not recorded):
16
16
  The 604799 figure is the concrete argument for completing brand verification: in Testing,
17
17
  every connected account silently re-consents weekly. Verification removes it.
18
18
 
19
- Phases 1–2 may now proceed against the flow below. Client-secret storage is decided:
20
- house-only at `${PLATFORM_ROOT}/config/google-house.env` (see below).
19
+ The flow below is the ORIGINAL Phase 0 verdict and is retained for its evidence.
20
+ It has since been superseded on two points: the vendor app is a
21
+ Desktop client whose secret ships in brand config, and the redirect is loopback
22
+ rather than a hosted HTTPS callback. Read the Desktop sections further down as
23
+ authoritative where the two differ.
21
24
 
22
25
  ## Original spike verdict (documentation-backed, now confirmed)
23
26
 
@@ -46,9 +49,11 @@ What is decided from published behaviour:
46
49
  - The flow is therefore an **operator-assisted authorization-code (PKCE) flow**, and it
47
50
  needs a redirect method, because Google's out-of-band ("paste the code") flow is fully
48
51
  blocked.
49
- - The recommended redirect method is a **hosted HTTPS callback on the brand's existing
50
- Cloudflare tunnel domain** (a "Web application" client), with a **loopback + manual
51
- code relay** (a "Desktop app" client) as the secret-less fallback.
52
+ - The redirect method recommended at the time was a hosted HTTPS callback on the
53
+ brand's Cloudflare tunnel domain (a "Web application" client). **Superseded by
54
+ the recent decision**: the fallback named here — a Desktop client with a loopback redirect
55
+ and a manual code relay — is what shipped, because only an installed-app secret
56
+ can be distributed to customer devices.
52
57
  - **Verification is the light kind.** Calendar is a *sensitive* scope, not a *restricted*
53
58
  one, so a brand's app needs only OAuth brand/consent-screen verification, never the
54
59
  annual third-party security assessment.
@@ -109,7 +114,7 @@ that carries the `code` and the process that exchanges it live on different mach
109
114
  concrete flows bridge that. The recommendation is Option B primary, Option A as the
110
115
  secret-less fallback.
111
116
 
112
- ### Option B (recommended): hosted HTTPS callback on the brand tunnel domain
117
+ ### Option B (SUPERSEDED): hosted HTTPS callback on the brand tunnel domain
113
118
 
114
119
  Client type **Web application**. A stable authorized redirect URI on the install's existing
115
120
  Cloudflare **public** host, served by the always-running `platform/ui` server (the same
@@ -203,86 +208,93 @@ on that brand, exactly as `outlookClientId` does. The client id ships as the bra
203
208
  `GOOGLE_CLIENT_ID` and inherited down the spawn chain (manager unit env → PTY → MCP child).
204
209
 
205
210
  Divergence from Outlook: the recommended Web-application flow (Option B) also needs a
206
- **client secret**, which lives house-only at `${PLATFORM_ROOT}/config/google-house.env`
207
- (decided; see below). A brand that ships `googleClientId` empty has the plugin inert with an
211
+ **client secret**, which ships in `brand.json` (the house-only file this
212
+ once described is withdrawn). A brand that ships `googleClientId` empty has the plugin inert with an
208
213
  actionable signal (`clientIdConfigured=false`), register refuses, and no operator action
209
214
  makes it work until the vendor client exists — mirroring Outlook's inert behaviour.
210
215
 
211
- ### Installing the secret on a device (operator step, once per install)
216
+ ### The vendor app is a Desktop client, and its secret ships in brand config
212
217
 
213
- Nothing automates this and nothing can: the secret cannot ship in the npm
214
- package, so it is placed by hand after the install exists. Until it is, the
215
- plugin's tools load and `google-account-register` refuses with a message naming
216
- this file — the refusal is deliberate and happens *before* the user consents,
217
- so nobody burns a consent on a flow that cannot complete.
218
+ Decided 2026-07-18, superseding the house-only file this section
219
+ used to describe. That model required placing a secret by hand on every install,
220
+ which cannot reach a customer device and contradicts installer-only doctrine.
218
221
 
219
- On the device, with the values from the brand's Google Cloud OAuth client:
222
+ There is no secret-free alternative: Google requires `client_secret` at the
223
+ token endpoint for **every** client type, including Web clients using PKCE.
220
224
 
221
- ```bash
222
- INSTALL=~/<brand>-code # e.g. ~/sitedesk-code
223
- ( umask 077; mkdir -p "$INSTALL/platform/config" )
224
- ( umask 077; cat > "$INSTALL/platform/config/google-house.env" <<'EOF'
225
- GOOGLE_CLIENT_ID=<the client id>
226
- GOOGLE_CLIENT_SECRET=<the client secret>
227
- EOF
228
- )
229
- chmod 600 "$INSTALL/platform/config/google-house.env"
225
+ So the vendor app is a **Desktop (installed app)** client, because Google
226
+ explicitly sanctions embedding that secret in distributed software — "the client
227
+ secret is obviously not treated as a secret". `brand.json` therefore carries
228
+ both values and the installer stamps them onto the session-manager unit:
229
+
230
+ ```jsonc
231
+ // brands/<brand>/brand.json
232
+ "googleClientId": "<the client id>",
233
+ "googleClientSecret": "<the client secret>"
230
234
  ```
231
235
 
232
- Then restart the install's UI service so the route picks it up.
236
+ They stamp **together or not at all**. A client id without its secret builds a
237
+ consent URL the user can complete but an exchange that cannot, which fails later
238
+ and less legibly than not offering the flow.
233
239
 
234
- Confirm it took without printing the secret the boot line reports presence
235
- only:
240
+ The secret ships to a **public** npm registry. That is the accepted trade: the
241
+ residual risk is app impersonation and quota abuse against the brand's client
242
+ id, not token theft, because PKCE still binds each code to its verifier.
236
243
 
237
- ```bash
238
- grep -m1 'google-mcp. boot' ~/.<brand>-code/logs/server.log
239
- # ... houseSecretPresent=true
240
- ```
244
+ Rejected, each once and for a reason:
241
245
 
242
- `houseSecretPresent=false` on an install whose brand ships a `googleClientId`
243
- is the mis-provision signature. The secret is never echoed, never logged, and
244
- never read by the MCP process only its presence is checked.
246
+ - **Customer-owned apps** (the QuickBooks pattern, where the operator registers
247
+ their own app). Unlike Intuit, Google demands app verification for the
248
+ sensitive Calendar scope homepage, privacy policy, domain ownership, demo
249
+ video — which the target customer cannot produce.
250
+ - **A vendor-hosted exchange broker**, where the install posts the code to a
251
+ brand-operated endpoint. Best security and best UX, but it means operating a
252
+ credential-bearing service for every customer.
253
+ - **A Web client with the secret shipped anyway.** A Web-app secret is genuinely
254
+ confidential in Google's model; publishing it would be a real credential leak
255
+ rather than a sanctioned embed.
245
256
 
246
- ### Client-secret storage: house-only (decided 2026-07-18)
257
+ ### The redirect is loopback, and the IP literal is mandatory
247
258
 
248
- An earlier draft of this file said the secret is "held in the brand's secret store, the same
249
- way Cloudflare tokens are held". That was wrong no brand-level secret store exists. The
250
- decision, mirroring the Cloudflare master token exactly:
259
+ Desktop clients permit only loopback redirects. `https` is rejected outright and
260
+ custom URI schemes are withdrawn ("no longer supported due to the risk of app
261
+ impersonation"), so this is the entire option space.
251
262
 
252
263
  ```
253
- ${PLATFORM_ROOT}/config/google-house.env # mode 600, parent 700
254
- GOOGLE_CLIENT_ID=…
255
- GOOGLE_CLIENT_SECRET=…
264
+ http://127.0.0.1:8571
265
+ ```
266
+
267
+ **Never `localhost`.** RFC 8252 §7.3 makes the port irrelevant when matching a
268
+ loopback redirect, but only for the IP literals `127.0.0.1` and `::1`; strict
269
+ servers match the hostname literally. Register `http://127.0.0.1` on the client.
270
+
271
+ Nothing listens on that port, by design. The consenting browser is the user's
272
+ own phone, so the redirect fails to load and the user copies the code out of the
273
+ address bar and pastes it back to `google-account-register-submit`. The port is
274
+ fixed so consent URLs are deterministic and one register's logs compare with
275
+ another's.
276
+
277
+ This is why the hosted HTTPS callback that the earlier plugin built is gone, along with
278
+ its allowlist entry and its refresh route: a Desktop client cannot use it.
279
+
280
+ ### Vendor runbook: creating the Desktop client
281
+
282
+ 1. In the **existing** Cloud project for the brand — not a new one, so the
283
+ consent screen and any verification progress carry over — go to
284
+ **Credentials → Create credentials → OAuth client ID**.
285
+ 2. Application type **Desktop app**. Name it for the brand.
286
+ 3. Copy the **Client ID** and **Client secret** into that brand's `brand.json`
287
+ as `googleClientId` and `googleClientSecret`.
288
+ 4. Re-bundle and publish. No file is placed on any device by hand.
289
+
290
+ Confirm it took from the boot line, which reports presence and never values:
291
+
292
+ ```bash
293
+ grep -m1 'google-mcp. boot' ~/.<brand>-code/logs/server.log
294
+ # ... clientIdConfigured=true clientSecretConfigured=true
256
295
  ```
257
296
 
258
- Written once per install by the operator, never echoed, never in a project tree.
259
- `platform/plugins/cloudflare/references/api.md` already establishes this pattern for
260
- multi-client installs and names SiteDesk as the case: an account-wide credential inside a
261
- sub-account's secrets file lets that sub-account reach every other client's resources, so
262
- the master lives house-only at `${PLATFORM_ROOT}/config/cloudflare-house.env`, "a location
263
- no sub-account spawn sources". `google-house.env` is that file's twin.
264
-
265
- Rejected, with reasons:
266
-
267
- - **`brands/<brand>/brand.json`** ships inside the published npm package. It carries
268
- `googleClientId` (public, exactly like `outlookClientId`, and the value the inert check
269
- reads) and never the secret.
270
- - **`~/<brand>-code/data/accounts/<accountId>/secrets`** is wrong-scoped twice: the secret is
271
- per-brand not per-account, so replicating it multiplies exposure for no benefit, and on a
272
- multi-tenant install it drops a brand-wide credential into a client sub-account's own
273
- directory.
274
- - **A Desktop-type client** (installed-app secret, documented non-confidential) would remove
275
- the storage question but forces the loopback redirect and its copy-the-code-off-a-404 flow
276
- on a phone, and discards the already-provisioned, verified Web-application client.
277
-
278
- House-only is sufficient here rather than merely tidier, because the token exchange runs in
279
- the `/api/google/oauth/callback` route inside the always-running `platform/ui` server, which
280
- is house-scoped. The secret never needs to reach a per-account MCP spawn.
281
-
282
- **It is a boundary of intent, not of permission.** Every account's session runs as the same
283
- unix user and the house path is deterministic, so an agent holding `Bash` can read the file
284
- regardless; OS user separation was costed and declined. Never cite house-only placement as
285
- proof a sub-account cannot reach the secret.
297
+ Either reading `false` on a brand that ships both is the mis-stamp signature.
286
298
 
287
299
  ---
288
300
 
@@ -312,7 +324,7 @@ follow-up once the plugin lands (mirroring Outlook 1479/1485).
312
324
  new one."). Capture it at creation into its final destination, or plan to rotate. It is
313
325
  never pasted into a chat transcript, a shell command that lands in history, or the repo.
314
326
  Rotation is free and has no downtime: **Add secret**, store the new one, delete the old.
315
- It lives house-only at `${PLATFORM_ROOT}/config/google-house.env` — see above.
327
+ It ships in `brand.json` as `googleClientSecret` — see the Desktop sections above.
316
328
  - **Option A (fallback):** application type **Desktop app**. Copy the **Client ID**.
317
329
  5. Set `googleClientId` in the brand's `brand.json` and re-bundle:
318
330
  ```jsonc
@@ -438,12 +450,17 @@ met and Phases 1–2 (the plugin build) proceed against the confirmed flow.
438
450
 
439
451
  | Brand | Client type | Redirect URI | Client ID | Status |
440
452
  |---|---|---|---|---|
441
- | `sitedesk-code` | Web application | `https://public.sitedesk.online/api/google/oauth/callback` | `1032860640027-p61l59fnog4mad5o7grginpaps9jnu8c.apps.googleusercontent.com` | **Testing** round-trip verified 2026-07-18; brand verification not started; secret pending rotation into its Phase 1 home |
453
+ | `sitedesk-code` | ~~Web application~~ **RETIRED** | ~~`https://public.sitedesk.online/api/google/oauth/callback`~~ | `1032860640027-…` | **Do not use.** A Web client cannot register a loopback redirect, so this id fails `redirect_uri_mismatch` under the Desktop flow. Cleared from `brand.json`; delete the client in the console and revoke its secret. |
454
+ | `sitedesk-code` | Desktop app | `http://127.0.0.1` | *(not yet created)* | Awaiting provisioning in the **existing** `Sitedesk Calendar` project, so consent-screen and verification progress carry over. |
442
455
 
443
456
  The public host was confirmed live and routing to the `platform/ui` server (it serves the
444
- brand's public page). No secret or token is recorded here. The secret minted at creation was
445
- exposed to shell history during the manual round-trip and should be rotated (**Add secret** →
446
- store delete old) when Phase 1 decides where it lives.
457
+ brand's public page). No secret or token is recorded here. The Web client's secret was exposed to shell history during the manual round-trip.
458
+ That client is retired rather than rotated: delete it in the console, which
459
+ revokes the secret with it.
460
+
461
+ **Devices touched by the earlier plugin may still hold `platform/config/google-house.env`
462
+ containing that live Web-client secret.** Nothing reads it any more and nothing
463
+ removes it. Delete it on each such device as part of retiring the Web client.
447
464
 
448
465
  Per-brand next step for `sitedesk-code`: start **brand/consent-screen verification** to lift
449
466
  the 100-test-user cap and the 7-day re-consent measured above. That review is the slow part;
@@ -63,6 +63,16 @@ An `InvoicePayment` reached from an `Invoice` is money received. The same label
63
63
 
64
64
  `CashEntry` does carry `direction`, because it has no parent invoice to derive one from.
65
65
 
66
+ ## The counterparty is passed by id, never by name
67
+
68
+ `ledger-invoice-record` and `ledger-cash-record` take the element id of an existing `Organization` or `Person`, and nothing else about them. The ledger never creates or matches them: look the counterparty up first with `memory-search` or `contact-lookup` and pass the id you find.
69
+
70
+ The display name stored on the invoice is read from that node, not passed as a second argument. One lookup feeds both the stored name and the link, so an invoice cannot read as one company while pointing at another. An id that does not exist on this account is refused with `reason=unknown-counterparty` before anything is written.
71
+
72
+ This is a deliberate boundary, not a convenience gap. The ledger records money; deciding whether "Beagle Direct Ltd" is the same company as an existing "Beagle Direct" is entity resolution, and doing it badly inside a write tool creates duplicate organisations that then split a payment history in two.
73
+
74
+ A `CashEntry` must have a counterparty for a second reason: graph-write refuses a write with no relationship at all, so an unlinked entry cannot be stored.
75
+
66
76
  ## Over-application is refused
67
77
 
68
78
  A payment that would take applied-to-date above the invoice total is rejected. It is never clamped to the remaining amount and never recorded anyway. The refusal names the figure that would settle the invoice, so the operator can correct it in one step.
@@ -75,7 +85,9 @@ After writing a payment, the tool re-reads the invoice from the graph and compar
75
85
 
76
86
  Four ways this can fail emit no event at all: a write narrated but never landed, a payment with no parent invoice, a stored balance property that has reappeared, and a duplicate payment created under a second id. None of them can be caught by logging an action, because no action occurs.
77
87
 
78
- A `[ledger-census]` line is emitted every 15 minutes by the UI server, carrying counts for each, plus any ledger index declared in `schema.cypher` but absent from this database. `alarm=true` on that line means one of them has happened. `ledger-reconcile` is the same check on demand, sharing the same reconcile and the same line formatter.
88
+ A `[ledger-census]` line is emitted every 15 minutes by the UI server, carrying counts for each, plus any ledger index declared in `schema.cypher` but absent from this database, plus `writeRejects24h`.
89
+
90
+ That last counter exists because of a real failure. On 2026-07-18 every ledger write was rejected for a full day while the census reported `invoices=0 payments=0`, which is byte-identical to a healthy ledger nobody has used yet. A rejected write leaves nothing in the graph by definition, so the count is read from the plugin's own log rather than from Neo4j. `alarm=true` on that line means one of them has happened. `ledger-reconcile` is the same check on demand, sharing the same reconcile and the same line formatter.
79
91
 
80
92
  Registration drift between `PLUGIN.md`, the generated canonical-tool-names artifact and the specialist templates is **not** a census signal. It is caught at build time by `platform/scripts/check-canonical-tool-names.mjs` and `check-specialist-tool-surface.mjs`. A runtime counter for it was removed after review: the census runs in the UI server, which has no view of MCP spawns, so the counter could only ever have compared a constant against itself and reported healthy.
81
93
 
@@ -4,7 +4,7 @@ import { eagerTool } from "../../../../lib/mcp-eager/dist/index.js";
4
4
  import { writeNodeWithEdges } from "../../../../lib/graph-write/dist/index.js";
5
5
  import { z } from "zod";
6
6
  import { closeDriver, getSession } from "./lib/neo4j.js";
7
- import { readCensus, readInvoice, readStatement, setPaymentStatus, verifyOutstanding, } from "./lib/read.js";
7
+ import { readCensus, readCounterpartyName, readInvoice, readStatement, setPaymentStatus, verifyOutstanding, } from "./lib/read.js";
8
8
  import { invoiceRecord } from "./tools/invoice-record.js";
9
9
  import { paymentRecord } from "./tools/payment-record.js";
10
10
  import { cashRecord } from "./tools/cash-record.js";
@@ -32,15 +32,21 @@ function refuseNoAccount(toolName) {
32
32
  isError: true,
33
33
  };
34
34
  }
35
+ // `agent` stays undefined when AGENT_SLUG is unset rather than defaulting to
36
+ // "". graph-write resolves `agent ?? source ?? "unknown"`, and an empty string
37
+ // is not nullish, so the old default printed a blank `agent=` on every reject
38
+ // and defeated the fallback entirely.
35
39
  const createdBy = (tool) => ({
36
- agent: agentSlug ?? "",
37
- session: sessionId ?? "",
40
+ agent: agentSlug,
41
+ session: sessionId,
38
42
  tool,
43
+ source: "ledger",
39
44
  });
40
- // graph-write's params are structurally identical to the tools' WriteFn; the
41
- // cast keeps the tool modules free of a graph-write import so their unit tests
42
- // need no Neo4j driver.
43
- const write = (p) => writeNodeWithEdges(p);
45
+ // No cast. Task 1788: the previous version cast writeNodeWithEdges to accept
46
+ // this plugin's own relationship shape, under a comment claiming the params
47
+ // were structurally identical. They were not, and the cast is what let a dead
48
+ // write path ship.
49
+ const write = writeNodeWithEdges;
44
50
  async function withSession(fn) {
45
51
  const session = getSession();
46
52
  try {
@@ -55,7 +61,10 @@ eagerTool(server, "ledger-invoice-record", "Record an invoice you raised (direct
55
61
  .enum(["receivable", "payable"])
56
62
  .describe("'receivable' is money owed to you; 'payable' is money you owe"),
57
63
  confirmationNumber: z.string().min(1).describe("Invoice or bill reference, e.g. INV-2026-014"),
58
- counterparty: z.string().min(1).describe("Who owes you, or who you owe"),
64
+ counterpartyNodeId: z
65
+ .string()
66
+ .min(1)
67
+ .describe("Element id of the existing Organization. Look it up first (memory-search or contact-lookup) — this tool never creates or matches organisations, so passing a name alone will not work"),
59
68
  totalPaymentDue: z.number().positive().describe("Face value of the whole bill"),
60
69
  dueDate: z.string().describe("ISO date the payment falls due, e.g. 2026-08-01"),
61
70
  description: z.string().optional().describe("What the invoice is for"),
@@ -65,6 +74,7 @@ eagerTool(server, "ledger-invoice-record", "Record an invoice you raised (direct
65
74
  return withSession((session) => invoiceRecord({
66
75
  session,
67
76
  write,
77
+ readName: readCounterpartyName,
68
78
  accountId,
69
79
  createdBy: createdBy("ledger-invoice-record"),
70
80
  ...args,
@@ -98,7 +108,6 @@ eagerTool(server, "ledger-credit-record", "Apply a credit note to an invoice you
98
108
  }, async (args) => {
99
109
  if (accountId === null)
100
110
  return refuseNoAccount("ledger-credit-record");
101
- const { reason: _reason, ...rest } = args;
102
111
  return withSession((session) => paymentRecord({
103
112
  session,
104
113
  read: readInvoice,
@@ -108,7 +117,7 @@ eagerTool(server, "ledger-credit-record", "Apply a credit note to an invoice you
108
117
  accountId,
109
118
  createdBy: createdBy("ledger-credit-record"),
110
119
  kind: "credit",
111
- ...rest,
120
+ ...args,
112
121
  // After the spread: the credit schema exposes no paymentType, so this
113
122
  // is the only source of it and must not be overwritten by the cast.
114
123
  paymentType: "credit",
@@ -119,11 +128,10 @@ eagerTool(server, "ledger-cash-record", "Record money in or out that is not atta
119
128
  amount: z.number().positive().describe("Amount — always positive; direction carries the sign"),
120
129
  date: z.string().describe("ISO date of the movement"),
121
130
  description: z.string().min(1).describe("What it was for"),
122
- counterparty: z.string().optional().describe("Who it was with"),
123
- counterpartyType: z
124
- .enum(["person", "organization"])
125
- .optional()
126
- .describe("Whether the counterparty is a person or a business; defaults to organization"),
131
+ counterpartyNodeId: z
132
+ .string()
133
+ .min(1)
134
+ .describe("Element id of the person or organisation this movement was with. Required — an entry linked to nothing cannot be stored"),
127
135
  }, async (args) => {
128
136
  if (accountId === null)
129
137
  return refuseNoAccount("ledger-cash-record");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,16 @@ import type { Session } from "neo4j-driver";
10
10
  import type { InvoiceRead } from "../tools/payment-record.js";
11
11
  import type { StatementRows } from "../tools/statement.js";
12
12
  import type { LedgerCensusRows } from "../../../../../lib/ledger-core/dist/index.js";
13
+ /**
14
+ * The display name of a counterparty node, or null if that element id does not
15
+ * exist on this account.
16
+ *
17
+ * The invoice stores this name AND links to this node, so both must come from
18
+ * one lookup. Taking the name from a separate argument would let an invoice
19
+ * read as one company while pointing at another, and the account filter is
20
+ * what stops an id from a neighbouring account resolving at all.
21
+ */
22
+ export declare function readCounterpartyName(session: Session, accountId: string, nodeId: string): Promise<string | null>;
13
23
  export declare function readInvoice(session: Session, accountId: string, ref: string): Promise<InvoiceRead | null>;
14
24
  /** The op=verify re-read. Deliberately goes back to the graph rather than
15
25
  * trusting the figure the write path just computed. */
@@ -25,5 +35,5 @@ export declare function readStatement(session: Session, accountId: string): Prom
25
35
  * invoice, payments that look like accidental duplicates, and ledger indexes
26
36
  * that are declared in schema.cypher but absent from this database.
27
37
  */
28
- export declare function readCensus(session: Session, accountId: string): Promise<LedgerCensusRows>;
38
+ export declare function readCensus(session: Session, accountId: string, now: number): Promise<LedgerCensusRows>;
29
39
  //# sourceMappingURL=read.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/lib/read.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAerF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgC7B;AAED;wDACwD;AACxD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;4BAE4B;AAC5B,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GACpC,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CA6CxB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAqD3B"}
1
+ {"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/lib/read.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8CAA8C,CAAC;AAgBrF;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAkC7B;AAED;wDACwD;AACxD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;4BAE4B;AAC5B,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GACpC,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CA6CxB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,gBAAgB,CAAC,CAsD3B"}
@@ -1,4 +1,5 @@
1
1
  import { LEDGER_INDEX_NAMES, computeOutstanding, } from "../../../../../lib/ledger-core/dist/index.js";
2
+ import { countWriteRejects24h } from "./write-rejects.js";
2
3
  /** neo4j-driver returns Integer objects for counts; numbers pass through. */
3
4
  function toNum(v) {
4
5
  if (typeof v === "number")
@@ -8,6 +9,21 @@ function toNum(v) {
8
9
  }
9
10
  return 0;
10
11
  }
12
+ /**
13
+ * The display name of a counterparty node, or null if that element id does not
14
+ * exist on this account.
15
+ *
16
+ * The invoice stores this name AND links to this node, so both must come from
17
+ * one lookup. Taking the name from a separate argument would let an invoice
18
+ * read as one company while pointing at another, and the account filter is
19
+ * what stops an id from a neighbouring account resolving at all.
20
+ */
21
+ export async function readCounterpartyName(session, accountId, nodeId) {
22
+ const res = await session.run(`MATCH (o) WHERE elementId(o) = $nodeId AND o.accountId = $accountId
23
+ RETURN coalesce(o.name, trim(coalesce(o.givenName, "") + " " + coalesce(o.familyName, ""))) AS name`, { accountId, nodeId });
24
+ const name = res.records[0]?.get("name");
25
+ return typeof name === "string" && name.trim() !== "" ? name.trim() : null;
26
+ }
11
27
  export async function readInvoice(session, accountId, ref) {
12
28
  // Staged WITH: payments collapse to one row before the credit match expands
13
29
  // again, so the two OPTIONAL MATCHes never form a cartesian product that
@@ -18,6 +34,7 @@ export async function readInvoice(session, accountId, ref) {
18
34
  OPTIONAL MATCH (i)-[:HAS_CREDIT]->(c:Credit)
19
35
  WITH i, ps, collect(DISTINCT c) AS cs
20
36
  RETURN labels(i) AS labels,
37
+ elementId(i) AS nodeId,
21
38
  i.confirmationNumber AS invoiceId,
22
39
  i.totalPaymentDue AS totalPaymentDue,
23
40
  i.dueDate AS dueDate,
@@ -30,6 +47,7 @@ export async function readInvoice(session, accountId, ref) {
30
47
  const labels = rec.get("labels");
31
48
  return {
32
49
  label: labels.includes("InboundInvoice") ? "InboundInvoice" : "Invoice",
50
+ nodeId: rec.get("nodeId"),
33
51
  invoiceId: rec.get("invoiceId"),
34
52
  totalPaymentDue: toNum(rec.get("totalPaymentDue")),
35
53
  dueDateMs: Date.parse(rec.get("dueDate") ?? "") || 0,
@@ -97,7 +115,7 @@ export async function readStatement(session, accountId) {
97
115
  * invoice, payments that look like accidental duplicates, and ledger indexes
98
116
  * that are declared in schema.cypher but absent from this database.
99
117
  */
100
- export async function readCensus(session, accountId) {
118
+ export async function readCensus(session, accountId, now) {
101
119
  const counts = await session.run(
102
120
  // OPTIONAL MATCH, not MATCH: with no payments a plain MATCH eliminates the
103
121
  // row, so records[0] is undefined and invoices reports 0 as well. That is
@@ -133,6 +151,7 @@ export async function readCensus(session, accountId) {
133
151
  date: r.get("date") ?? "",
134
152
  })),
135
153
  declaredNotLive,
154
+ writeRejects24h: countWriteRejects24h(process.env.LOG_DIR ?? "", now),
136
155
  };
137
156
  }
138
157
  //# sourceMappingURL=read.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/lib/read.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/lib/read.ts"],"names":[],"mappings":"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"}
@@ -6,17 +6,20 @@
6
6
  * driver. `index.ts` passes the real `writeNodeWithEdges` and the real reads.
7
7
  */
8
8
  import type { Session } from "neo4j-driver";
9
- export interface CreatedBy {
10
- agent: string;
11
- session: string;
12
- tool: string;
13
- }
14
- export interface GraphRelationship {
15
- type: string;
16
- direction: "incoming" | "outgoing";
17
- targetLabel: string;
18
- targetProps: Record<string, unknown>;
19
- }
9
+ /**
10
+ * Task 1788 — the real graph-write contracts, imported rather than redeclared.
11
+ *
12
+ * This file used to declare its own `GraphRelationship` with
13
+ * `targetLabel`/`targetProps`, and `index.ts` forced it past the type checker
14
+ * with a cast. The real shape needs `targetNodeId`, an element id, so at
15
+ * runtime every relationship carried `undefined` and graph-write rejected every
16
+ * create with `reason=unresolved-target requested=1 found=0`. The whole write
17
+ * path was dead from the day it shipped. Importing the real types is what makes
18
+ * that a compile error instead of a silent runtime rejection, so the redeclared
19
+ * shape must never come back.
20
+ */
21
+ import type { CreatedBy, GraphRelationship } from "../../../../../lib/graph-write/dist/index.js";
22
+ export type { CreatedBy, GraphRelationship };
20
23
  export interface WriteParams {
21
24
  session: Session;
22
25
  labels: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,UAAU,GAAG,UAAU,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE3C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE7C;AAED,6DAA6D;AAC7D,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED;mEACmE;AACnE,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,SAAS,CAAC;AAExD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,GAAG,gBAAgB,CAElF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EAClB,MAAM,8CAA8C,CAAC;AAEtD,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;AAE7C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE3C;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE7C;AAED,6DAA6D;AAC7D,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED;mEACmE;AACnE,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG,SAAS,CAAC;AAExD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,GAAG,gBAAgB,CAElF"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AA0CA,MAAM,UAAU,EAAE,CAAC,IAAY;IAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAMD,MAAM,UAAU,QAAQ,CAAC,SAA2B;IAClD,OAAO,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACnE,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AA+CA,MAAM,UAAU,EAAE,CAAC,IAAY;IAC7B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,KAAK,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAMD,MAAM,UAAU,QAAQ,CAAC,SAA2B;IAClD,OAAO,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC;AACnE,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Counts `[graph-write] reject` lines across the ledger MCP tee logs modified
3
+ * within the trailing 24 hours.
4
+ *
5
+ * Uses file mtime rather than parsing per-line timestamps: the tee log carries
6
+ * no timestamp of its own, and a file untouched for a day cannot hold a reject
7
+ * from the last one. Best-effort — an unreadable log directory yields 0 rather
8
+ * than throwing, because a census that dies on a missing directory tells the
9
+ * operator nothing at all.
10
+ */
11
+ export declare function countWriteRejects24h(logDir: string, now: number): number;
12
+ //# sourceMappingURL=write-rejects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-rejects.d.ts","sourceRoot":"","sources":["../../src/lib/write-rejects.ts"],"names":[],"mappings":"AAeA;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBxE"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Task 1788 — count recent write rejections from the ledger's own MCP logs.
3
+ *
4
+ * A rejected write cannot record its own failure in the graph, because the
5
+ * whole point is that nothing was written. The only durable trace is the
6
+ * stderr line graph-write emits, which `mcp-spawn-tee` captures per session.
7
+ * Counting those lines is what lets the census distinguish a healthy empty
8
+ * ledger from one whose write path is dead — on 2026-07-18 those two states
9
+ * printed identically for a full day.
10
+ */
11
+ import { readdirSync, readFileSync, statSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ const DAY_MS = 86_400_000;
14
+ /**
15
+ * Counts `[graph-write] reject` lines across the ledger MCP tee logs modified
16
+ * within the trailing 24 hours.
17
+ *
18
+ * Uses file mtime rather than parsing per-line timestamps: the tee log carries
19
+ * no timestamp of its own, and a file untouched for a day cannot hold a reject
20
+ * from the last one. Best-effort — an unreadable log directory yields 0 rather
21
+ * than throwing, because a census that dies on a missing directory tells the
22
+ * operator nothing at all.
23
+ */
24
+ export function countWriteRejects24h(logDir, now) {
25
+ let entries;
26
+ try {
27
+ entries = readdirSync(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
28
+ }
29
+ catch {
30
+ return 0;
31
+ }
32
+ let total = 0;
33
+ for (const name of entries) {
34
+ const path = join(logDir, name);
35
+ try {
36
+ if (now - statSync(path).mtimeMs > DAY_MS)
37
+ continue;
38
+ for (const line of readFileSync(path, "utf8").split("\n")) {
39
+ if (line.includes("[graph-write] reject"))
40
+ total += 1;
41
+ }
42
+ }
43
+ catch {
44
+ // A log rotated away mid-read is not a census failure.
45
+ continue;
46
+ }
47
+ }
48
+ return total;
49
+ }
50
+ //# sourceMappingURL=write-rejects.js.map