@rubytech/create-maxy-code 0.1.441 → 0.1.443

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 (95) hide show
  1. package/dist/__tests__/converge-client-admins.test.js +50 -0
  2. package/dist/converge-client-admins.js +67 -0
  3. package/dist/index.js +107 -1
  4. package/package.json +1 -1
  5. package/payload/platform/docs/superpowers/plans/2026-07-13-account-schema-ontology-projection.md +547 -0
  6. package/payload/platform/docs/superpowers/plans/2026-07-14-graph-top-level-labels-ontology-single-source.md +458 -0
  7. package/payload/platform/docs/superpowers/specs/2026-07-13-account-schema-ontology-projection-design.md +178 -0
  8. package/payload/platform/docs/superpowers/specs/2026-07-14-graph-top-level-labels-ontology-single-source-design.md +119 -0
  9. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  10. package/payload/platform/plugins/admin/PLUGIN.md +7 -1
  11. package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +19 -2
  12. package/payload/platform/plugins/admin/mcp/dist/index.js +126 -1
  13. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +30 -0
  15. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -1
  16. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +78 -0
  17. package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -1
  18. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +37 -2
  19. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  20. package/payload/platform/plugins/docs/references/troubleshooting.md +35 -0
  21. package/payload/platform/plugins/memory/PLUGIN.md +2 -0
  22. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js +12 -0
  23. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js.map +1 -1
  24. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts +9 -1
  25. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts.map +1 -1
  26. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js +19 -2
  27. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js.map +1 -1
  28. package/payload/platform/plugins/memory/references/schema-estate-agent.md +8 -3
  29. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +37 -4
  30. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
  31. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +27 -3
  32. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
  33. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +52 -11
  34. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
  35. package/payload/platform/plugins/outlook/mcp/dist/index.js +1 -1
  36. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  37. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +5 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -1
  39. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +32 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
  41. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +20 -22
  42. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  43. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +3 -1
  44. package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +58 -0
  45. package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +6 -0
  46. package/payload/platform/scripts/lib/account-schema-owned-dirs.py +143 -10
  47. package/payload/platform/scripts/lib/provision-account-dir.sh +5 -0
  48. package/payload/platform/scripts/logs-read.sh +24 -6
  49. package/payload/platform/scripts/logs-read.test.sh +42 -0
  50. package/payload/platform/scripts/name-glsmith-owner.sh +239 -0
  51. package/payload/platform/scripts/rss-sampler.sh +107 -0
  52. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  53. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
  54. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  55. package/payload/server/public/assets/{AdminLoginScreens-CukwQufW.js → AdminLoginScreens-BJVwtpLH.js} +1 -1
  56. package/payload/server/public/assets/{AdminShell-BwEBH6tT.js → AdminShell-CMu8_Xwn.js} +1 -1
  57. package/payload/server/public/assets/{Checkbox-B629mOPp.js → Checkbox-CzD0ORqA.js} +1 -1
  58. package/payload/server/public/assets/{admin-CdFRCUUZ.js → admin-D0yk2LMq.js} +1 -1
  59. package/payload/server/public/assets/{browser-BWR59IkB.js → browser-CvfbgznO.js} +1 -1
  60. package/payload/server/public/assets/{calendar-kuTcxX1t.js → calendar-fw4WethJ.js} +1 -1
  61. package/payload/server/public/assets/chat-DhD-NES_.js +1 -0
  62. package/payload/server/public/assets/chevron-left-B3xSeEDR.js +1 -0
  63. package/payload/server/public/assets/data-CUnDzDox.js +1 -0
  64. package/payload/server/public/assets/{file-download-4mKJxUi-.js → file-download-Px4s0Bhp.js} +1 -1
  65. package/payload/server/public/assets/{graph-CboWM2_-.js → graph-DbT8nA6R.js} +1 -1
  66. package/payload/server/public/assets/{graph-labels-B8YAdo3Z.js → graph-labels-C1YIyLiA.js} +1 -1
  67. package/payload/server/public/assets/{maximize-2-CxstTgoK.js → maximize-2-BwphzI9S.js} +1 -1
  68. package/payload/server/public/assets/{operator-oSaB1mya.js → operator-zcIfeB14.js} +1 -1
  69. package/payload/server/public/assets/{page-DMeJHVfA.js → page-6fCnIb45.js} +2 -2
  70. package/payload/server/public/assets/page-CfQFAJia.js +1 -0
  71. package/payload/server/public/assets/{public-C54tl6V4.js → public-C0ehZCdE.js} +1 -1
  72. package/payload/server/public/assets/{rotate-ccw-COGQTi7n.js → rotate-ccw-C7BqkMec.js} +1 -1
  73. package/payload/server/public/assets/{tasks-B97VpwEJ.js → tasks-DlgiCafL.js} +1 -1
  74. package/payload/server/public/assets/{time-entry-format-C09rDHo9.js → time-entry-format-CyNYVDkq.js} +1 -1
  75. package/payload/server/public/assets/{useCopyFeedback-DHoYHiK9.js → useCopyFeedback-ByGUMN94.js} +1 -1
  76. package/payload/server/public/assets/useSubAccountSwitcher-1izQvPiD.css +1 -0
  77. package/payload/server/public/assets/useVoiceRecorder-XgpWvXpk.js +2 -0
  78. package/payload/server/public/browser.html +5 -5
  79. package/payload/server/public/calendar.html +6 -6
  80. package/payload/server/public/chat.html +12 -12
  81. package/payload/server/public/data.html +10 -10
  82. package/payload/server/public/graph.html +11 -11
  83. package/payload/server/public/index.html +13 -13
  84. package/payload/server/public/operator.html +14 -14
  85. package/payload/server/public/public.html +12 -12
  86. package/payload/server/public/tasks.html +5 -5
  87. package/payload/server/server.js +742 -321
  88. package/payload/platform/plugins/memory/references/schema-trades.md +0 -34
  89. package/payload/server/public/assets/chat-ejnq2rck.js +0 -1
  90. package/payload/server/public/assets/chevron-left-u4tjq7fI.js +0 -1
  91. package/payload/server/public/assets/data-dZbOyLdT.js +0 -1
  92. package/payload/server/public/assets/page-DEkI-Gl1.js +0 -1
  93. package/payload/server/public/assets/useSubAccountSwitcher-Dzmd7Aip.css +0 -1
  94. package/payload/server/public/assets/useVoiceRecorder-b7HzTFs0.js +0 -2
  95. /package/payload/server/public/assets/{useSubAccountSwitcher-DLJFISqf.js → useSubAccountSwitcher-s6WlRn52.js} +0 -0
@@ -162,4 +162,34 @@ export declare function seedAccountGraphRoot(args: {
162
162
  * never an edge — see CLAUDE.md), detaching its relationships. */
163
163
  export declare const ACCOUNT_NODE_COUNT_CYPHER = "MATCH (n) WHERE n.accountId = $id RETURN count(n) AS c";
164
164
  export declare const ACCOUNT_PURGE_CYPHER = "MATCH (n) WHERE n.accountId = $id DETACH DELETE n";
165
+ /** Task 1623 — the managing-admin status for a client sub-account. `absent` when
166
+ * no managingAdminUserId is set; `dangling` when set but not held by a live
167
+ * house admin; `assigned` otherwise. Mirrors reconcileAccountAdminCensus's
168
+ * classification so the roster tool and the standing census never disagree. */
169
+ export declare function classifyManagingAdmin(managingAdminUserId: string | undefined, liveHouseAdminUserIds: string[]): "assigned" | "absent" | "dangling";
170
+ /** Task 1623 — a client owner is `named` iff its owned Person carries a
171
+ * non-empty givenName (the Task 1570 name source); otherwise `nameless`. */
172
+ export declare function ownerNameStatus(givenName: string | null | undefined): "named" | "nameless";
173
+ /** Task 1623 — read a sub-account's managingAdminUserId off its account.json.
174
+ * Returns undefined when absent/empty/unparseable (corruption discipline). */
175
+ export declare function readManagingAdminUserId(accountsDir: string, accountId: string): string | undefined;
176
+ /** Task 1623 — name a client sub-account's business owner. The name lives on the
177
+ * owner's owned Person (Task 1570 name source), NOT AdminUser.name. Refuses an
178
+ * empty/placeholder name (isPlaceholderOwnerName) before any write. Renames the
179
+ * owner's EXISTING owned Person if it has one (the nameless-owner repair case);
180
+ * otherwise creates one and binds it via OWNS. Does not route through
181
+ * writeAdminUserAndPerson: that function name-matches to reuse/create a Person,
182
+ * and against an already-nameless owned Person it would add a SECOND Person
183
+ * rather than rename the existing one. Sets embedding=null so the standing
184
+ * reindex re-embeds the renamed Person (raw cypher carries no embedding). */
185
+ export declare function setOwnerName(args: {
186
+ session: SeedSessionLike;
187
+ accountId: string;
188
+ name: string;
189
+ }): Promise<{
190
+ personRenamed: boolean;
191
+ personCreated: boolean;
192
+ givenName: string;
193
+ familyName: string | null;
194
+ }>;
165
195
  //# sourceMappingURL=account-lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-lifecycle.d.ts","sourceRoot":"","sources":["../../src/tools/account-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-lifecycle.d.ts","sourceRoot":"","sources":["../../src/tools/account-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -321,4 +321,82 @@ export async function seedAccountGraphRoot(args) {
321
321
  * never an edge — see CLAUDE.md), detaching its relationships. */
322
322
  export const ACCOUNT_NODE_COUNT_CYPHER = "MATCH (n) WHERE n.accountId = $id RETURN count(n) AS c";
323
323
  export const ACCOUNT_PURGE_CYPHER = "MATCH (n) WHERE n.accountId = $id DETACH DELETE n";
324
+ /** Task 1623 — the managing-admin status for a client sub-account. `absent` when
325
+ * no managingAdminUserId is set; `dangling` when set but not held by a live
326
+ * house admin; `assigned` otherwise. Mirrors reconcileAccountAdminCensus's
327
+ * classification so the roster tool and the standing census never disagree. */
328
+ export function classifyManagingAdmin(managingAdminUserId, liveHouseAdminUserIds) {
329
+ if (!managingAdminUserId)
330
+ return "absent";
331
+ return liveHouseAdminUserIds.includes(managingAdminUserId) ? "assigned" : "dangling";
332
+ }
333
+ /** Task 1623 — a client owner is `named` iff its owned Person carries a
334
+ * non-empty givenName (the Task 1570 name source); otherwise `nameless`. */
335
+ export function ownerNameStatus(givenName) {
336
+ return givenName && givenName.trim() ? "named" : "nameless";
337
+ }
338
+ /** Task 1623 — read a sub-account's managingAdminUserId off its account.json.
339
+ * Returns undefined when absent/empty/unparseable (corruption discipline). */
340
+ export function readManagingAdminUserId(accountsDir, accountId) {
341
+ const configPath = resolve(accountsDir, accountId, "account.json");
342
+ try {
343
+ const cfg = JSON.parse(readFileSync(configPath, "utf-8"));
344
+ return typeof cfg.managingAdminUserId === "string" && cfg.managingAdminUserId ? cfg.managingAdminUserId : undefined;
345
+ }
346
+ catch {
347
+ return undefined;
348
+ }
349
+ }
350
+ /** Task 1623 — name a client sub-account's business owner. The name lives on the
351
+ * owner's owned Person (Task 1570 name source), NOT AdminUser.name. Refuses an
352
+ * empty/placeholder name (isPlaceholderOwnerName) before any write. Renames the
353
+ * owner's EXISTING owned Person if it has one (the nameless-owner repair case);
354
+ * otherwise creates one and binds it via OWNS. Does not route through
355
+ * writeAdminUserAndPerson: that function name-matches to reuse/create a Person,
356
+ * and against an already-nameless owned Person it would add a SECOND Person
357
+ * rather than rename the existing one. Sets embedding=null so the standing
358
+ * reindex re-embeds the renamed Person (raw cypher carries no embedding). */
359
+ export async function setOwnerName(args) {
360
+ const { session, accountId, name } = args;
361
+ if (isPlaceholderOwnerName(name)) {
362
+ throw new Error(`setOwnerName: a real business-owner name is required (got ${JSON.stringify(name)})`);
363
+ }
364
+ const trimmed = name.trim();
365
+ const firstSpace = trimmed.search(/\s/);
366
+ const givenName = firstSpace === -1 ? trimmed : trimmed.slice(0, firstSpace).trim();
367
+ const familyName = firstSpace === -1 ? null : trimmed.slice(firstSpace + 1).trim() || null;
368
+ const now = new Date().toISOString();
369
+ const res = await session.run(`MATCH (au:AdminUser {accountId: $accountId, role: 'owner'})
370
+ OPTIONAL MATCH (au)-[:OWNS]->(existing:Person)
371
+ WITH au, existing LIMIT 1
372
+ CALL {
373
+ WITH au, existing
374
+ WITH au, existing WHERE existing IS NOT NULL
375
+ SET existing.givenName = $givenName, existing.familyName = $familyName,
376
+ existing.embedding = null, existing.updatedAt = $now
377
+ RETURN true AS renamed, false AS created
378
+ UNION
379
+ WITH au, existing
380
+ WITH au WHERE existing IS NULL
381
+ CREATE (p:Person {accountId: $accountId, userId: au.userId, givenName: $givenName, familyName: $familyName,
382
+ role: 'admin-personal', scope: 'admin', embedding: null, createdAt: $now})
383
+ MERGE (au)-[:OWNS]->(p)
384
+ RETURN false AS renamed, true AS created
385
+ }
386
+ RETURN renamed AS personRenamed, created AS personCreated`, { accountId, givenName, familyName, now });
387
+ // An empty result means the outer MATCH found no role:'owner' AdminUser for the
388
+ // account (mistyped accountId, or an unseeded/rootless account). That is a
389
+ // failure to repair, not a silent success — refuse loudly so the caller never
390
+ // reports a fabricated "created Person" while the owner stays nameless.
391
+ const rec = res.records[0];
392
+ if (!rec) {
393
+ throw new Error(`setOwnerName: no owner AdminUser found for account ${accountId} (owner must be seeded before it can be named)`);
394
+ }
395
+ return {
396
+ personRenamed: Boolean(rec.get("personRenamed")),
397
+ personCreated: Boolean(rec.get("personCreated")),
398
+ givenName,
399
+ familyName,
400
+ };
401
+ }
324
402
  //# sourceMappingURL=account-lifecycle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-lifecycle.js","sourceRoot":"","sources":["../../src/tools/account-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-lifecycle.js","sourceRoot":"","sources":["../../src/tools/account-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:9f7fc73400d2f9cf942e2df6f544bc69b95abe820ac1ff9b529807c3c7fd6407
4
+ content-hash: sha256:e83c3708b39a62506dcba40e603fdeb09dd5b11d5cc7d964f3353cd73f01642d
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -2763,7 +2763,7 @@ either is a regression.
2763
2763
 
2764
2764
  **`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp/operator reader (`/whatsapp`, `OperatorConversations`) omits the prop and keeps the default `renderTimeline`, so its bubble/DM chrome is unchanged — except that since the attachment-render extraction the default renderer draws inbound `operator-inbound` uploads and `agent-file` deliveries inline (image thumbnail / pdf.js preview / voice-note player / download chip) via the attachment renderer shared with `/chat`, extracted to `app/chat/attachment-render.tsx` to break the cycle with `transcript-render.tsx`; `renderChatTimeline` is untouched. Both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`, `app/chat/__tests__/pdf-preview.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
2765
2765
 
2766
- **WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is read server-side under the same account-scope guard the `/data` download route applies. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`.
2766
+ **WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is authorised server-side (`authorizeReplyFileRef`) against the send's own account (the conversation owner) **or** the session's pinned account (`getAccountIdForSession` — the exact scope the DeviceFilePicker used to offer it), so a house/managing-admin session can attach a managed-client file the picker listed. Because a reply sends bytes OUT to an external WhatsApp recipient, any other account, a `public` partition, and any install-wide / non-account path are refused fail-closed; the cross-account admission's authority is the session's pinned account, never the caller-supplied body `accountId` (the own-account admission matches the body `accountId`, which the route already trusts via `isValidAccountId` and the existing-conversation guard). A scope refusal returns a distinct HTTP 403 reason (`file-ref-cross-account` / `file-ref-public` / `file-ref-foreign`) and copy, never "device file not found" (reserved for a genuine resolve/stat miss). Per-ref `[wa-manual-send] op=reply-file-ref … via=own|session|deny reason=<…> ok=<bool>` logs the decision before any send; `via=deny ok=true` is the exfiltration signature that must never appear. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`. **Composer sizing matches the webchat composer:** the reply textarea auto-grows to fit multi-line content (measured from `scrollHeight`, clamped to a one-row minimum and a `viewport/3` maximum, scrollable past the cap with the scrollbar hidden), and a top-border grab handle drags (pointer) or nudges (ArrowUp/ArrowDown, keyboard-focusable) to an explicit height in the same clamp; a manual drag pins the height and overrides auto-grow until the field is cleared, which releases it back to auto-grow. A completed manual resize logs `[operator-ui] op=wa-composer-resize mode=drag|key h=<px>`; a bare click on the handle (no drag) logs nothing.
2767
2767
 
2768
2768
  **`/chat` live activity line.** While a turn is in flight the transcript tail shows one ephemeral `ChatActivity` line (mounted only while `busy`, admin/operator only). It tracks real activity, not a timer: while a `Task` subagent runs it shows that subagent's headline (`agentType · description`, prefixed `N agents ·` when ≥2 are concurrent), sourced from `agent-<hex>.meta.json` via named `activity` SSE events the admin reader pushes from the session's `subagents/` dir; with no subagent active it shows a neutral word that advances only on a real turn arrival. The line carries a turn-elapsed clock and flips to a `stalled` state once nothing has been written for 5 minutes (`now − lastEmitAt`), so the operator can tell a wedge from progress without SSH. It is never added to the persisted timeline. Detail and the `[webchat-activity]` observability live in [`admin-webchat-native-channel.md`](../../../.docs/admin-webchat-native-channel.md).
2769
2769
 
@@ -4720,6 +4720,41 @@ Maxy has access to all platform logs and can filter them for you.
4720
4720
 
4721
4721
  ---
4722
4722
 
4723
+ ## Box went unreachable, suspected memory exhaustion
4724
+
4725
+ **Symptom:** The Pi stopped responding to everything (no web, no SSH, no ping) and needed a power-cycle. This is the signature of memory exhaustion: the box fills RAM and swap, then wedges while the kernel tries to free memory.
4726
+
4727
+ **What protects against it:** Every install runs a standing memory audit every 30 seconds, zram compressed swap so pressure hits RAM instead of the SD card, and earlyoom, which kills the single largest process before the kernel freezes the box. A kill shows up as one service restarting, not a whole-box outage, and SSH is protected so the box stays reachable.
4728
+
4729
+ **Check the approach to OOM after a reboot.** The audit log survives reboot. Read it:
4730
+
4731
+ ```
4732
+ ~/<install>/platform/scripts/logs-read.sh --tail mem 100
4733
+ ```
4734
+
4735
+ Replace `<install>` with the install directory (for example `realagent-code`). Then:
4736
+
4737
+ - Look for `op=mem-pressure` lines. They fire when available memory crosses the low-water mark, before any kill, and name the heaviest service (`topSlice`).
4738
+ - A single service's reading (`ptys`, `neo4j`, `brand`, `edge`, `vnc`) rising over time while the others stay flat is a memory leak in that service.
4739
+ - `op=mem-sample` lines that read `na` for the per-service fields are normal until the kernel memory controller is enabled on that box; available memory, swap, and the pressure warning still work.
4740
+
4741
+ **Confirm a kill happened and the service came back:**
4742
+
4743
+ ```
4744
+ journalctl -t earlyoom --since -1h
4745
+ journalctl --user -u <hostname>.service --since -1h | grep -iE "Started|Scheduled restart"
4746
+ ```
4747
+
4748
+ **Check whether the kernel OOM-killer fired anyway** (it should not, if earlyoom pre-empted it):
4749
+
4750
+ ```
4751
+ journalctl -b -1 -k | grep -i oom
4752
+ ```
4753
+
4754
+ A kernel `invoked oom-killer` line means the mitigation did not pre-empt the kernel on that occasion. A gap in the `op=mem-sample` timestamps means the sampler itself stopped. Both are worth escalating.
4755
+
4756
+ ---
4757
+
4723
4758
  ## Cloudflare Tunnel Down (Remote Access Broken)
4724
4759
 
4725
4760
  **Symptom:** You can reach Maxy on your local network but not via your public domain.
@@ -75,7 +75,7 @@ either is a regression.
75
75
 
76
76
  **`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp/operator reader (`/whatsapp`, `OperatorConversations`) omits the prop and keeps the default `renderTimeline`, so its bubble/DM chrome is unchanged — except that since the attachment-render extraction the default renderer draws inbound `operator-inbound` uploads and `agent-file` deliveries inline (image thumbnail / pdf.js preview / voice-note player / download chip) via the attachment renderer shared with `/chat`, extracted to `app/chat/attachment-render.tsx` to break the cycle with `transcript-render.tsx`; `renderChatTimeline` is untouched. Both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`, `app/chat/__tests__/pdf-preview.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
77
77
 
78
- **WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is read server-side under the same account-scope guard the `/data` download route applies. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`.
78
+ **WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is authorised server-side (`authorizeReplyFileRef`) against the send's own account (the conversation owner) **or** the session's pinned account (`getAccountIdForSession` — the exact scope the DeviceFilePicker used to offer it), so a house/managing-admin session can attach a managed-client file the picker listed. Because a reply sends bytes OUT to an external WhatsApp recipient, any other account, a `public` partition, and any install-wide / non-account path are refused fail-closed; the cross-account admission's authority is the session's pinned account, never the caller-supplied body `accountId` (the own-account admission matches the body `accountId`, which the route already trusts via `isValidAccountId` and the existing-conversation guard). A scope refusal returns a distinct HTTP 403 reason (`file-ref-cross-account` / `file-ref-public` / `file-ref-foreign`) and copy, never "device file not found" (reserved for a genuine resolve/stat miss). Per-ref `[wa-manual-send] op=reply-file-ref … via=own|session|deny reason=<…> ok=<bool>` logs the decision before any send; `via=deny ok=true` is the exfiltration signature that must never appear. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`. **Composer sizing matches the webchat composer:** the reply textarea auto-grows to fit multi-line content (measured from `scrollHeight`, clamped to a one-row minimum and a `viewport/3` maximum, scrollable past the cap with the scrollbar hidden), and a top-border grab handle drags (pointer) or nudges (ArrowUp/ArrowDown, keyboard-focusable) to an explicit height in the same clamp; a manual drag pins the height and overrides auto-grow until the field is cleared, which releases it back to auto-grow. A completed manual resize logs `[operator-ui] op=wa-composer-resize mode=drag|key h=<px>`; a bare click on the handle (no drag) logs nothing.
79
79
 
80
80
  **`/chat` live activity line.** While a turn is in flight the transcript tail shows one ephemeral `ChatActivity` line (mounted only while `busy`, admin/operator only). It tracks real activity, not a timer: while a `Task` subagent runs it shows that subagent's headline (`agentType · description`, prefixed `N agents ·` when ≥2 are concurrent), sourced from `agent-<hex>.meta.json` via named `activity` SSE events the admin reader pushes from the session's `subagents/` dir; with no subagent active it shows a neutral word that advances only on a real turn arrival. The line carries a turn-elapsed clock and flips to a `stalled` state once nothing has been written for 5 minutes (`now − lastEmitAt`), so the operator can tell a wedge from progress without SSH. It is never added to the persisted timeline. Detail and the `[webchat-activity]` observability live in [`admin-webchat-native-channel.md`](../../../.docs/admin-webchat-native-channel.md).
81
81
 
@@ -224,6 +224,41 @@ For specific plugin logs: "Show Telegram logs" or "Show contacts plugin logs."
224
224
 
225
225
  ---
226
226
 
227
+ ## Box went unreachable, suspected memory exhaustion
228
+
229
+ **Symptom:** The Pi stopped responding to everything (no web, no SSH, no ping) and needed a power-cycle. This is the signature of memory exhaustion: the box fills RAM and swap, then wedges while the kernel tries to free memory.
230
+
231
+ **What protects against it:** Every install runs a standing memory audit every 30 seconds, zram compressed swap so pressure hits RAM instead of the SD card, and earlyoom, which kills the single largest process before the kernel freezes the box. A kill shows up as one service restarting, not a whole-box outage, and SSH is protected so the box stays reachable.
232
+
233
+ **Check the approach to OOM after a reboot.** The audit log survives reboot. Read it:
234
+
235
+ ```
236
+ ~/<install>/platform/scripts/logs-read.sh --tail mem 100
237
+ ```
238
+
239
+ Replace `<install>` with the install directory (for example `realagent-code`). Then:
240
+
241
+ - Look for `op=mem-pressure` lines. They fire when available memory crosses the low-water mark, before any kill, and name the heaviest service (`topSlice`).
242
+ - A single service's reading (`ptys`, `neo4j`, `brand`, `edge`, `vnc`) rising over time while the others stay flat is a memory leak in that service.
243
+ - `op=mem-sample` lines that read `na` for the per-service fields are normal until the kernel memory controller is enabled on that box; available memory, swap, and the pressure warning still work.
244
+
245
+ **Confirm a kill happened and the service came back:**
246
+
247
+ ```
248
+ journalctl -t earlyoom --since -1h
249
+ journalctl --user -u <hostname>.service --since -1h | grep -iE "Started|Scheduled restart"
250
+ ```
251
+
252
+ **Check whether the kernel OOM-killer fired anyway** (it should not, if earlyoom pre-empted it):
253
+
254
+ ```
255
+ journalctl -b -1 -k | grep -i oom
256
+ ```
257
+
258
+ A kernel `invoked oom-killer` line means the mitigation did not pre-empt the kernel on that occasion. A gap in the `op=mem-sample` timestamps means the sampler itself stopped. Both are worth escalating.
259
+
260
+ ---
261
+
227
262
  ## Cloudflare Tunnel Down (Remote Access Broken)
228
263
 
229
264
  **Symptom:** You can reach {{productName}} on your local network but not via your public domain.
@@ -247,6 +247,8 @@ Before any structured write, load `references/schema-base.md` via `plugin-read`.
247
247
 
248
248
  **Brand declares the default vertical** in `brand.json#vertical` (the schema file basename without `.md`, e.g. `"schema-estate-agent"`, or `null` for non-vertical brands). The validator enforces base + that vertical against every write. If the file named by `brand.json#vertical` is absent from `references/`, the memory server fails to start — a misconfigured brand never validates against the wrong rule set silently.
249
249
 
250
+ The same vertical drives the **account file-schema**: `platform/scripts/lib/account-schema-owned-dirs.py` reads the `## Top-level node types` table of the brand's `references/<vertical>.md` and derives one top-level operator-entity bucket per `schema:`-namespaced label (kebab-case-plural, `Site` mapped to `customer-sites`), unioning them into each account's `SCHEMA.md` allowed set. So the account data directory mirrors the graph ontology rather than a hardcoded folder list. A vertical whose schema file carries no top-level table contributes no domain buckets, and `account-schema-owned-dirs.py reconcile` reports the gap.
251
+
250
252
  **Every account has exactly one root `:LocalBusiness`.** The installer's `seed-neo4j.sh` MERGEs it at install (and on every re-seed) with the unique key `accountId`, `createdBySource = 'installer'`, a non-null `createdAt`, and `businessType` set to the bare slug derived from `brand.json#vertical` (i.e. `"schema-estate-agent"` becomes `"estate-agent"`, `null` stays null). The MERGE is idempotent: re-runs preserve `createdAt`; `businessType` is coalesced so an operator override on the node wins over the brand default. Failure to write the node aborts the install with `[install-invariant] localbusiness-bootstrap result=failed reason=<text>`. The recorder, validator, and any other writer can rely on the LocalBusiness existing from the first turn of the first install — no first-use bootstrap branch.
251
253
 
252
254
  **A LocalBusiness with its own `businessType` overrides the default** for writes that resolve to it. The validator looks up the account's LocalBusiness on every write; if `businessType` is set (e.g. `"creator"`), the resolved vertical becomes `schema-${businessType}` instead of the brand default. The override applies only to writes anchored under that LocalBusiness.
@@ -68,6 +68,18 @@ test("resolveActiveVertical: LocalBusiness with businessType → localbusiness-o
68
68
  source: "localbusiness-override",
69
69
  });
70
70
  });
71
+ test("resolveActiveVertical: businessType 'trades' folds onto schema-construction", async () => {
72
+ const session = mockSession([{ businessType: "trades" }]);
73
+ const result = await resolveActiveVertical({
74
+ session,
75
+ accountId: "acct-1",
76
+ brandVertical: "schema-estate-agent",
77
+ });
78
+ assert.deepEqual(result, {
79
+ resolvedVertical: "schema-construction",
80
+ source: "localbusiness-override",
81
+ });
82
+ });
71
83
  test("resolveActiveVertical: businessType override wins when brandVertical is null", async () => {
72
84
  const session = mockSession([{ businessType: "creator" }]);
73
85
  const result = await resolveActiveVertical({
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-active-vertical.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/resolve-active-vertical.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve-active-vertical.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/resolve-active-vertical.test.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,19 @@
4
4
  * Order of resolution:
5
5
  * 1. The write's account-level :LocalBusiness has a non-empty
6
6
  * `businessType` property → vertical = `schema-${businessType}`,
7
- * source = `localbusiness-override`.
7
+ * source = `localbusiness-override`, after applying VERTICAL_ALIASES.
8
8
  * 2. Otherwise → vertical = the brand-declared default, source =
9
9
  * `brand-default`. Brand vertical is `null` for non-vertical brands
10
10
  * (Maxy default), in which case only base rules apply.
11
11
  *
12
+ * VERTICAL_ALIASES folds a businessType that has no ontology of its own onto
13
+ * the vertical that already carries its labels. `trades` (plumber, electrician,
14
+ * decorator) is service-delivery work on the canonical construction/SiteDesk
15
+ * ontology and ships no divergent labels, so it resolves to `schema-construction`
16
+ * — there is no `schema-trades.md`. Without this fold a `trades` businessType
17
+ * would resolve to a non-existent file and every construction label would be
18
+ * validated out-of-scope (base-only), silently dropping the rules that apply.
19
+ *
12
20
  * The Cypher query reads the LocalBusiness anchored at `accountId`. Today's
13
21
  * data shape is one LocalBusiness per account; `LIMIT 1` defends against
14
22
  * incidental duplicates without claiming to resolve them.
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-active-vertical.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-active-vertical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,wBAAwB,CAAC;AAExE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA0B1B"}
1
+ {"version":3,"file":"resolve-active-vertical.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-active-vertical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,wBAAwB,CAAC;AAWxE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,2BAA2B,GAClC,OAAO,CAAC,eAAe,CAAC,CA4B1B"}
@@ -4,11 +4,19 @@
4
4
  * Order of resolution:
5
5
  * 1. The write's account-level :LocalBusiness has a non-empty
6
6
  * `businessType` property → vertical = `schema-${businessType}`,
7
- * source = `localbusiness-override`.
7
+ * source = `localbusiness-override`, after applying VERTICAL_ALIASES.
8
8
  * 2. Otherwise → vertical = the brand-declared default, source =
9
9
  * `brand-default`. Brand vertical is `null` for non-vertical brands
10
10
  * (Maxy default), in which case only base rules apply.
11
11
  *
12
+ * VERTICAL_ALIASES folds a businessType that has no ontology of its own onto
13
+ * the vertical that already carries its labels. `trades` (plumber, electrician,
14
+ * decorator) is service-delivery work on the canonical construction/SiteDesk
15
+ * ontology and ships no divergent labels, so it resolves to `schema-construction`
16
+ * — there is no `schema-trades.md`. Without this fold a `trades` businessType
17
+ * would resolve to a non-existent file and every construction label would be
18
+ * validated out-of-scope (base-only), silently dropping the rules that apply.
19
+ *
12
20
  * The Cypher query reads the LocalBusiness anchored at `accountId`. Today's
13
21
  * data shape is one LocalBusiness per account; `LIMIT 1` defends against
14
22
  * incidental duplicates without claiming to resolve them.
@@ -17,6 +25,14 @@
17
25
  * on a Neo4j failure. A silent fallback would mask a connectivity problem
18
26
  * with a doctrinally-wrong validation outcome.
19
27
  */
28
+ /**
29
+ * businessType values that carry no ontology of their own and fold onto another
30
+ * vertical's schema file. Keyed by the raw `businessType`, valued by the schema
31
+ * file basename (without `.md`) to resolve to.
32
+ */
33
+ const VERTICAL_ALIASES = {
34
+ trades: "schema-construction",
35
+ };
20
36
  export async function resolveActiveVertical(params) {
21
37
  const { session, accountId, brandVertical } = params;
22
38
  const brandDefault = {
@@ -36,8 +52,9 @@ export async function resolveActiveVertical(params) {
36
52
  if (typeof raw !== "string" || raw.trim().length === 0) {
37
53
  return brandDefault;
38
54
  }
55
+ const businessType = raw.trim();
39
56
  return {
40
- resolvedVertical: `schema-${raw.trim()}`,
57
+ resolvedVertical: VERTICAL_ALIASES[businessType] ?? `schema-${businessType}`,
41
58
  source: "localbusiness-override",
42
59
  };
43
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-active-vertical.js","sourceRoot":"","sources":["../../src/lib/resolve-active-vertical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAkBH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAmC;IAEnC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IACrD,MAAM,YAAY,GAAoB;QACpC,gBAAgB,EAAE,aAAa;QAC/B,MAAM,EAAE,eAAe;KACxB,CAAC;IACF,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;aAES,EACT,EAAE,SAAS,EAAE,CACd,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,OAAO;QACL,gBAAgB,EAAE,UAAU,GAAG,CAAC,IAAI,EAAE,EAAE;QACxC,MAAM,EAAE,wBAAwB;KACjC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"resolve-active-vertical.js","sourceRoot":"","sources":["../../src/lib/resolve-active-vertical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH;;;;GAIG;AACH,MAAM,gBAAgB,GAA2B;IAC/C,MAAM,EAAE,qBAAqB;CAC9B,CAAC;AAcF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAmC;IAEnC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IACrD,MAAM,YAAY,GAAoB;QACpC,gBAAgB,EAAE,aAAa;QAC/B,MAAM,EAAE,eAAe;KACxB,CAAC;IACF,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B;;aAES,EACT,EAAE,SAAS,EAAE,CACd,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAChC,OAAO;QACL,gBAAgB,EACd,gBAAgB,CAAC,YAAY,CAAC,IAAI,UAAU,YAAY,EAAE;QAC5D,MAAM,EAAE,wBAAwB;KACjC,CAAC;AACJ,CAAC"}
@@ -8,17 +8,22 @@ When loading this reference, confirm: "Using schema-base + schema-estate-agent".
8
8
 
9
9
  ---
10
10
 
11
- ## Additional Node Types
11
+ ## Top-level node types (operator-entry, natural key)
12
12
 
13
13
  | Entity | Neo4j Label | Schema.org Type | Required Properties |
14
14
  |--------|-------------|-----------------|---------------------|
15
15
  | Property | `Property` | `schema:Accommodation` | `accountId`, `slug` (id, address-derived), `address` |
16
16
  | Listing | `Listing` | `schema:RealEstateListing` | `accountId`, `slug`, `displayName`, `listingType` (sale/let), `status`, `sourceSystem`, `sourceId`, `scope`, `heroImageUrl`*, `pageUrl`*, `blurb` |
17
- | ImageObject | `ImageObject` | `schema:ImageObject` | `accountId`, `listingSlug`, `url`, `description`, `tags`, `scope` |
18
17
  | Viewing | `Viewing` | `schema:Event` (subtype) | `accountId`, `listing` (id), `applicant` (id), `date`, `feedback`, `outcome` |
19
- | Applicant | `Applicant` | `schema:Person` (extended) | Base Person properties + `budget`, `tenure`, `moveDate`, `requirements` |
20
18
  | Offer | `Offer` | `schema:Offer` | `accountId`, `listing` (id), `applicant` (id), `price`, `conditions`, `status`, `date` |
21
19
 
20
+ ## Child node types (reached via parent neighbourhood)
21
+
22
+ | Entity | Neo4j Label | Schema.org Type | Required Properties |
23
+ |--------|-------------|-----------------|---------------------|
24
+ | ImageObject | `ImageObject` | `schema:ImageObject` | `accountId`, `listingSlug`, `url`, `description`, `tags`, `scope` |
25
+ | Applicant | `Applicant` | `schema:Person` (extended) | Base Person properties + `budget`, `tenure`, `moveDate`, `requirements` |
26
+
22
27
  \* `heroImageUrl` and `pageUrl` are required for any Listing whose `status` is `for-sale`, `under-offer`, or `sold` (anything publicly listable). Listings with `status: "off-market"` or `status: "withdrawn"` are exempt — they describe stock not currently visible to visitors and have no public listing page to point at. The curator writes `status: "off-market"` and skips the two URLs when the source has no public marketing.
23
28
 
24
29
  ### Property — obligatory hub
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
3
3
  import { readFileSync } from "node:fs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { dirname, resolve } from "node:path";
6
- import { _internals, startDeviceCode, pollDeviceToken } from "../auth/device-flow.js";
6
+ import { _internals, startDeviceCode, pollDeviceToken, parseAzureTokenError } from "../auth/device-flow.js";
7
7
  function mockFetch(handler) {
8
8
  const calls = [];
9
9
  const original = globalThis.fetch;
@@ -75,15 +75,48 @@ test("pollDeviceToken maps slow_down / expired_token / access_denied", async ()
75
75
  }
76
76
  }
77
77
  });
78
- test("pollDeviceToken throws on an unrecognised error", async () => {
79
- const m = mockFetch(() => json({ error: "invalid_client" }, 400));
78
+ test("pollDeviceToken returns a structured error (not a throw) on an unrecognised error", async () => {
79
+ const m = mockFetch(() => json({
80
+ error: "invalid_grant",
81
+ error_description: "AADSTS70008: The provided authorization code or refresh token has expired due to inactivity.",
82
+ error_codes: [70008],
83
+ suberror: "token_expired",
84
+ correlation_id: "corr-1",
85
+ trace_id: "trace-1",
86
+ timestamp: "2026-07-13 16:10:17Z",
87
+ }, 400));
80
88
  try {
81
- await assert.rejects(pollDeviceToken({ clientId: "c", tenantId: "common" }, "D"), /invalid_client/);
89
+ const out = await pollDeviceToken({ clientId: "c", tenantId: "common" }, "D");
90
+ assert.equal(out.kind, "error");
91
+ if (out.kind === "error") {
92
+ assert.equal(out.httpStatus, 400);
93
+ assert.equal(out.error, "invalid_grant");
94
+ assert.equal(out.aadsts, "AADSTS70008");
95
+ assert.equal(out.suberror, "token_expired");
96
+ assert.equal(out.correlationId, "corr-1");
97
+ assert.equal(out.traceId, "trace-1");
98
+ assert.match(out.errorDescription, /expired due to inactivity/);
99
+ }
82
100
  }
83
101
  finally {
84
102
  m.restore();
85
103
  }
86
104
  });
105
+ test("parseAzureTokenError recovers the AADSTS code from the description when error_codes is absent", () => {
106
+ const e = parseAzureTokenError(400, JSON.stringify({
107
+ error: "invalid_grant",
108
+ error_description: "AADSTS50011: The redirect URI does not match.",
109
+ }));
110
+ assert.equal(e.aadsts, "AADSTS50011");
111
+ assert.equal(e.error, "invalid_grant");
112
+ });
113
+ test("parseAzureTokenError keeps a non-JSON body in raw without throwing", () => {
114
+ const e = parseAzureTokenError(502, "<html>Bad Gateway</html>");
115
+ assert.equal(e.kind, "error");
116
+ assert.equal(e.httpStatus, 502);
117
+ assert.equal(e.aadsts, null);
118
+ assert.equal(e.raw, "<html>Bad Gateway</html>");
119
+ });
87
120
  test("pollDeviceToken 200 -> success with tokenResponse + scopes", async () => {
88
121
  const m = mockFetch(() => json({
89
122
  access_token: "AT", refresh_token: "RT", expires_in: 3600, token_type: "Bearer",
@@ -1 +1 @@
1
- {"version":3,"file":"device-flow.test.js","sourceRoot":"","sources":["../../src/__tests__/device-flow.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"device-flow.test.js","sourceRoot":"","sources":["../../src/__tests__/device-flow.test.ts"],"names":[],"mappings":"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"}