@rubytech/create-realagent 1.0.828 → 1.0.829

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 (72) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +2 -1
  3. package/payload/platform/package.json +2 -2
  4. package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +39 -54
  5. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +26 -58
  6. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +2 -2
  7. package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
  8. package/payload/platform/plugins/memory/PLUGIN.md +4 -4
  9. package/payload/platform/plugins/memory/mcp/dist/index.js +18 -218
  10. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  11. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +103 -0
  12. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
  13. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -1
  14. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +30 -20
  15. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -1
  16. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +16 -1
  17. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +12 -3
  19. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -1
  20. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +2 -138
  21. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
  22. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +10 -5
  23. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -1
  24. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts +2 -0
  25. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts.map +1 -0
  26. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +148 -0
  27. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -0
  28. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +1 -64
  29. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  30. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +6 -336
  31. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  32. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +7 -11
  33. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  34. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +1 -11
  35. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  36. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +21 -17
  37. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
  38. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +77 -37
  39. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
  40. package/payload/platform/plugins/memory/references/schema-base.md +2 -0
  41. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +54 -4
  42. package/payload/platform/plugins/whatsapp/PLUGIN.md +1 -1
  43. package/payload/platform/scripts/seed-neo4j.sh +15 -14
  44. package/payload/platform/templates/specialists/agents/database-operator.md +9 -15
  45. package/payload/server/chunk-CUSH3UXP.js +2305 -0
  46. package/payload/server/chunk-IWNDVGKT.js +10077 -0
  47. package/payload/server/chunk-KC7NUABI.js +654 -0
  48. package/payload/server/chunk-WUVXPZIV.js +1116 -0
  49. package/payload/server/client-pool-3TM3SRIA.js +32 -0
  50. package/payload/server/cloudflare-task-tracker-4NIODMGL.js +19 -0
  51. package/payload/server/maxy-edge.js +3 -3
  52. package/payload/server/neo4j-migrations-XTQ4WEV6.js +428 -0
  53. package/payload/server/server.js +6 -6
  54. package/payload/platform/plugins/whatsapp-import/PLUGIN.md +0 -48
  55. package/payload/platform/plugins/whatsapp-import/bin/ingest.mjs +0 -617
  56. package/payload/platform/plugins/whatsapp-import/bin/whatsapp-ingest.sh +0 -98
  57. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/delta-append.test.ts +0 -163
  58. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export-lrm.test.ts +0 -83
  59. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/parse-export.test.ts +0 -678
  60. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/sessionize.test.ts +0 -91
  61. package/payload/platform/plugins/whatsapp-import/lib/src/__tests__/to-classifier-input.test.ts +0 -59
  62. package/payload/platform/plugins/whatsapp-import/lib/src/delta-cursor.ts +0 -54
  63. package/payload/platform/plugins/whatsapp-import/lib/src/derive-keys.ts +0 -82
  64. package/payload/platform/plugins/whatsapp-import/lib/src/index.ts +0 -22
  65. package/payload/platform/plugins/whatsapp-import/lib/src/parse-export.ts +0 -471
  66. package/payload/platform/plugins/whatsapp-import/lib/src/sessionize.ts +0 -81
  67. package/payload/platform/plugins/whatsapp-import/lib/src/to-classifier-input.ts +0 -48
  68. package/payload/platform/plugins/whatsapp-import/lib/tsconfig.json +0 -9
  69. package/payload/platform/plugins/whatsapp-import/lib/vitest.config.ts +0 -9
  70. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/SKILL.md +0 -124
  71. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/conversation-archive-shape.md +0 -143
  72. package/payload/platform/plugins/whatsapp-import/skills/whatsapp-import/references/export-parse.md +0 -109
@@ -1,3 +1,4 @@
1
+ import { type ValidatorEnv } from "../lib/schema-validator.js";
1
2
  interface ProfileUpdateParams {
2
3
  accountId: string;
3
4
  userId: string;
@@ -28,27 +29,30 @@ interface ProfileUpdateParams {
28
29
  */
29
30
  notApplicable?: boolean;
30
31
  /**
31
- * Task 886 §D operator-identity fields written to the OWNS-bound
32
- * Person node, NOT to UserProfile. Pre-Task-886 the agent had no tool
33
- * surface to attach an email/phone to the operator's personal-profile
34
- * Person; Coverage iterated only Preferences and never told the agent
35
- * identity was missing. The schema already accepts these fields on
36
- * Person (waitlist plugin and whatsapp/persist-message both write
37
- * `Person {email}` / `Person {telephone}` per schema-base.md:15) — this
38
- * adds the operator-identity capture path on top.
32
+ * Task 893open Person properties for personal-profile elicitation.
33
+ * The agent decides which Person properties best help it serve the
34
+ * operator (identity, contact, context); the schema validator (synonym
35
+ * pass + Task 849 forbidden-property pass) is the central enforcement.
36
+ * No allow-list, no enumeration. Writes route to the operator's
37
+ * personal-profile Person via `(au:AdminUser)-[:OWNS]->(p:Person)`.
39
38
  *
40
- * `email` and `telephone` are the only canonical Person identity props
41
- * accepted here. `phone` is the schema synonym for `telephone` (per
42
- * schema-base.md:75 synonym table); callers that pass `phone` get a
43
- * loud-fail rather than a silent rewrite picking the canonical name
44
- * up-front keeps grep aligned with the schema doctrine.
39
+ * Validation runs in `mode: "update"` (Task 893): synonym + forbidden
40
+ * checks fire (so `phone` rejects with "use telephone", `name` rejects
41
+ * with the Forbidden Properties rationale), but the required-property
42
+ * loop is skipped (the personal-profile Person was created with
43
+ * givenName/familyName at PIN setup; partial SET should not re-validate
44
+ * those).
45
45
  */
46
- personFields?: {
47
- email?: string;
48
- telephone?: string;
49
- };
46
+ personFields?: Record<string, unknown>;
50
47
  /** For mode: "merge" — preferenceIds of sources to merge into this preference */
51
48
  mergeSourceIds?: string[];
49
+ /**
50
+ * Schema validator environment — passed in by the MCP server (built once
51
+ * at startup, see `index.ts`). Required when `personFields` is non-empty
52
+ * so the central validator can enforce synonym + forbidden-property
53
+ * rules on operator-identity writes (Task 893).
54
+ */
55
+ validator?: ValidatorEnv;
52
56
  }
53
57
  interface ProfileUpdateResult {
54
58
  preferenceId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"profile-update.d.ts","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"AAqBA,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,UAAU,mBAAmB;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAoT9B"}
1
+ {"version":3,"file":"profile-update.d.ts","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAqC9E,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,UAAU,GAAG,aAAa,CAAC;IACpC,IAAI,CAAC,EAAE,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,CAAC;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC;CAC1B;AAED,UAAU,mBAAmB;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAiV9B"}
@@ -2,6 +2,7 @@ import { getSession } from "../lib/neo4j.js";
2
2
  import { embed } from "../lib/embeddings.js";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { notTrashed } from "../../../../../lib/graph-trash/dist/index.js";
5
+ import { validateWrite } from "../lib/schema-validator.js";
5
6
  // Cross-process agreement: these values must match neo4j-store.ts
6
7
  const INITIAL_CONFIDENCE = 0.5;
7
8
  const REINFORCEMENT_INCREMENT = 0.15;
@@ -15,8 +16,26 @@ const VALID_CATEGORIES = new Set([
15
16
  "interaction",
16
17
  ]);
17
18
  const VALID_MODES = new Set(["reinforce", "update", "contradict", "merge"]);
19
+ // Task 893 — system-managed Person properties that agent input must never
20
+ // overwrite. Account-isolation (accountId, userId, scope) and write
21
+ // provenance (createdAt, createdByAgent, createdBySession, updatedAt)
22
+ // belong to the platform, not the agent. The Cypher MATCH pins the row
23
+ // by accountId, but `SET p += $fields` would still overwrite that
24
+ // property if accountId appears in the map — silently breaking account
25
+ // isolation for any future read keyed on the property. Defence in depth.
26
+ const PERSON_SYSTEM_MANAGED_PROPS = new Set([
27
+ "accountId",
28
+ "userId",
29
+ "scope",
30
+ "embedding",
31
+ "createdAt",
32
+ "updatedAt",
33
+ "createdByAgent",
34
+ "createdByTool",
35
+ "createdBySession",
36
+ ]);
18
37
  export async function profileUpdate(params) {
19
- const { accountId, userId, category, key, value, source = "behavioural", mode = "reinforce", conversationId, profileFields, personFields, mergeSourceIds, notApplicable = false, } = params;
38
+ const { accountId, userId, category, key, value, source = "behavioural", mode = "reinforce", conversationId, profileFields, personFields, mergeSourceIds, notApplicable = false, validator, } = params;
20
39
  if (!VALID_CATEGORIES.has(category)) {
21
40
  throw new Error(`Invalid category "${category}". Must be one of: ${[...VALID_CATEGORIES].join(", ")}`);
22
41
  }
@@ -40,6 +59,41 @@ export async function profileUpdate(params) {
40
59
  if (mode === "merge" && (!mergeSourceIds || mergeSourceIds.length === 0)) {
41
60
  throw new Error("mergeSourceIds required when mode is 'merge'.");
42
61
  }
62
+ // Task 893 — synchronous personFields hygiene + schema validation. Runs
63
+ // here (before getSession()/embed()) so synonym/forbidden rejection
64
+ // throws without opening a Neo4j session or burning an Ollama call. The
65
+ // resulting `personSafeFields` map is reused below for the SET.
66
+ //
67
+ // Two layers of protection on the input:
68
+ // 1. Validator (synonyms + Forbidden Properties) — semantic enforcement.
69
+ // 2. System-managed-property strip — defends account-isolation and
70
+ // provenance from LLM-driven tampering. Never accept agent input
71
+ // that would overwrite accountId, userId, scope, or createdBy*
72
+ // stamps on the Person; those are env- or system-managed.
73
+ // Account isolation is doctrine (loud-fail rather than silent
74
+ // cross-account write).
75
+ let personSafeFields = null;
76
+ if (personFields && Object.keys(personFields).length > 0) {
77
+ const filtered = {};
78
+ for (const [k, v] of Object.entries(personFields)) {
79
+ if (v === null || v === undefined)
80
+ continue;
81
+ if (typeof v === "string" && v.trim().length === 0)
82
+ continue;
83
+ if (PERSON_SYSTEM_MANAGED_PROPS.has(k)) {
84
+ throw new Error(`profile-update personFields: '${k}' is a system-managed Person property — refusing to accept agent input that would overwrite it. Account isolation and provenance stamps are set by the platform, not the agent.`);
85
+ }
86
+ filtered[k] = v;
87
+ }
88
+ if (Object.keys(filtered).length > 0) {
89
+ if (!validator) {
90
+ throw new Error("profile-update: `personFields` requires the schema validator — caller (MCP server) must pass `validator` from the env built at startup. This is the central enforcement point per Task 893.");
91
+ }
92
+ // Throws on synonym (e.g. `phone`) or forbidden (`name`) keys.
93
+ validateWrite({ labels: ["Person"], properties: filtered, accountId }, validator, { mode: "update" });
94
+ personSafeFields = filtered;
95
+ }
96
+ }
43
97
  const session = getSession();
44
98
  const now = new Date().toISOString();
45
99
  try {
@@ -74,43 +128,29 @@ export async function profileUpdate(params) {
74
128
  `, { accountId, userId, fields: safeFields, now });
75
129
  }
76
130
  }
77
- // Task 886 §D — Person identity fields. Writes to the operator's
78
- // personal-profile Person node bound to the AdminUser via OWNS (the
79
- // edge the PIN-setup writeAdminUserAndPerson path created). The
80
- // RETURN count guard is mandatory: a MATCH-SET against a missing
81
- // Person silently no-ops and the agent would think the write
82
- // succeeded (project_sprint_learnings: neo4j-match-set-no-op).
83
- //
84
- // Allow-list: only `email` and `telephone` reach the SET. Synonym
85
- // rewriting (`phone` `telephone`) is the writer's responsibility,
86
- // not this tool's callers that pass `phone` get rejected so grep
87
- // stays aligned with schema-base.md doctrine.
88
- if (personFields && (personFields.email !== undefined || personFields.telephone !== undefined)) {
89
- const personSafeFields = {};
90
- if (typeof personFields.email === "string" && personFields.email.length > 0) {
91
- personSafeFields.email = personFields.email;
92
- }
93
- if (typeof personFields.telephone === "string" && personFields.telephone.length > 0) {
94
- personSafeFields.telephone = personFields.telephone;
131
+ // Task 893open Person properties for personal-profile elicitation.
132
+ // The closed `{ email?, telephone? }` literal from Task 886 §D is gone;
133
+ // hygiene + validator both ran synchronously above, so by here
134
+ // `personSafeFields` is either null (nothing to write) or a non-empty
135
+ // map of validator-accepted keys. Writes route via the OWNS edge.
136
+ // The RETURN count guard is mandatory: MATCH-SET against a missing
137
+ // Person silently no-ops (sprint-learning: neo4j-match-set-no-op).
138
+ if (personSafeFields !== null) {
139
+ const personUpdate = await session.run(`
140
+ MATCH (au:AdminUser {userId: $userId})-[:OWNS]->(p:Person {accountId: $accountId})
141
+ SET p += $fields, p.updatedAt = $now
142
+ RETURN count(p) AS affected, collect(elementId(p))[0] AS personElementId
143
+ `, { accountId, userId, fields: personSafeFields, now });
144
+ const affected = personUpdate.records[0]?.get("affected");
145
+ const affectedN = typeof affected === "number" ? affected : (affected?.toNumber?.() ?? 0);
146
+ if (affectedN !== 1) {
147
+ throw new Error(`profile-update personFields: AdminUser-OWNS-Person not found for userId=${userId} accountId=${accountId.slice(0, 8)}… (affected=${affectedN}). Personal-profile Person is created at PIN setup; if this fires the OWNS edge is missing and the operator-identity capture path is broken.`);
95
148
  }
96
- if (Object.keys(personSafeFields).length > 0) {
97
- const personUpdate = await session.run(`
98
- MATCH (au:AdminUser {userId: $userId})-[:OWNS]->(p:Person {accountId: $accountId})
99
- SET p += $fields, p.updatedAt = $now
100
- RETURN count(p) AS affected, collect(elementId(p))[0] AS personElementId
101
- `, { accountId, userId, fields: personSafeFields, now });
102
- const affected = personUpdate.records[0]?.get("affected");
103
- const affectedN = typeof affected === "number" ? affected : (affected?.toNumber?.() ?? 0);
104
- if (affectedN !== 1) {
105
- throw new Error(`profile-update personFields: AdminUser-OWNS-Person not found for userId=${userId} accountId=${accountId.slice(0, 8)}… (affected=${affectedN}). Personal-profile Person is created at PIN setup; if this fires the OWNS edge is missing and the operator-identity capture path is broken.`);
106
- }
107
- // Identity-completion log — one line per identity field set in this
108
- // call. Pre-Task-886 the agent had no observability of identity
109
- // fields landing on Person; this gives operators a grep target
110
- // matching the existing `[profile] sparse-state injected` pattern.
111
- for (const fieldName of Object.keys(personSafeFields)) {
112
- process.stderr.write(`[profile] identity-completed accountId=${accountId.slice(0, 8)}… field=${fieldName}\n`);
113
- }
149
+ // One log line per Person property set in this call — generic over
150
+ // the open Record, not per-kind. Operators grep
151
+ // `[profile] identity-completed` to see what landed.
152
+ for (const fieldName of Object.keys(personSafeFields)) {
153
+ process.stderr.write(`[profile] identity-completed accountId=${accountId.slice(0, 8)}… field=${fieldName}\n`);
114
154
  }
115
155
  }
116
156
  // Handle merge mode — combines multiple preferences into one
@@ -1 +1 @@
1
- {"version":3,"file":"profile-update.js","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profile-update.js","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"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"}
@@ -45,6 +45,8 @@ When loading this reference, confirm which schema files were consulted by noting
45
45
 
46
46
  **Personal-profile role on Person (Task 704):** the optional `role` property on a `Person` node carries the value `"admin-personal"` when the node is the operator's personal-profile bootstrap (onboarding step 9 personal mode). The graph-write gate accepts `Person {role: "admin-personal"}` in lieu of a `LocalBusiness` so personal-mode users can complete onboarding without registering a business. Do not set `role: "admin-personal"` on customer or staff Person nodes — it's the personal-profile discriminator and only the bootstrap node should carry it.
47
47
 
48
+ **Personal-profile Person is open by default (Task 893).** Any Person property the agent judges useful for serving the operator is permitted on the personal-profile Person — identity, contact, context, anything that makes future assistance more useful. The set is comprehensive, not enumerated. The only constraints are the Forbidden Properties table (Task 849; e.g. `Person.name` rejects in favour of `givenName` + `familyName`) and the Schema.org synonym table (e.g. `phone` rejects in favour of `telephone`). The schema validator is the central enforcement; callers do not pre-rewrite or pre-filter. The `profile-update` tool's `personFields` parameter is the conversational surface that writes here, validating in `mode: "update"` so SET-only writes do not re-run the required-property check (givenName/familyName were established at PIN setup).
49
+
48
50
  **CreativeWork** covers long-form textual records written by the platform: session summaries (`session-compact`), workflow digests (e.g. public chat review), and skill definitions saved by `skill-builder`. The `title` is a short identifier; the `abstract` carries the full content that drives the embedding.
49
51
 
50
52
  **DefinedTerm** covers reusable concepts, learnings, and glossary entries — e.g. project retrospective learnings (`name` is a short handle, `description` is the full learning). Additional properties like `category` are encouraged but not required.
@@ -1,11 +1,27 @@
1
1
  ---
2
2
  name: document-ingest
3
- description: Universal document ingestion — maps any unstructured document (PDF, text, transcript, web page) to ontologically-grounded `:Section` graph nodes via Haiku-driven classification. Triggers when the operator uploads or fetches a document for ingestion. One skill for every document type — no per-doctype branching.
3
+ description: Universal document ingestion — maps any unstructured document (PDF, text, transcript, web page) OR chat archive (WhatsApp `_chat.txt`) to ontologically-grounded graph nodes via Haiku-driven classification. Triggers when the operator uploads or fetches a document or chat export for ingestion. One skill for every input shape — no per-doctype, no per-channel branching.
4
4
  ---
5
5
 
6
6
  # Document Ingest
7
7
 
8
- Ingests any unstructured document (PDF, text, transcript, web page) into the graph. Every classified section becomes one `:Section` node carrying a secondary label from a closed enumeration (`:Section:Position`, `:Section:Chapter`, `:Section:Parties`, …); identity-kind anchor edges go from the document subject directly at the multi-labeled section node. There are no per-doctype skills (no `cv-import`, no `contract-import`) — the classifier in `memory-classify` decides which kind every section maps to. The skill orchestrates the pipeline; the classifier reads the loaded ontology; the writer enforces the validator. **Classifier failure is terminal — the ingest aborts entirely; nothing is written. Loud failures, never silent landfill.**
8
+ Ingests any unstructured input — documents (PDF, text, transcript, web page) and chat archives (WhatsApp `_chat.txt`) — into the graph. Every classified section becomes one `:Section` node. **Two parent shapes, one pipeline:**
9
+
10
+ | Input shape | Parent label | Section secondary label | Identity property | mode |
11
+ |---|---|---|---|---|
12
+ | PDF / text / web (default) | `:KnowledgeDocument` | `:Section:<Kind>` from closed enumeration (`Position`, `Chapter`, `Parties`, …) | `attachmentId` | `document` |
13
+ | Chat archive (`_chat.txt`) | `:ConversationArchive` | `:Section:Conversation` | `conversationIdentity` | `chat` |
14
+
15
+ The classifier in `memory-classify` decides which section kinds each section maps to (document mode) or chunks the archive into topic-bounded `:Section:Conversation` nodes (chat mode). The skill orchestrates the pipeline; the classifier reads the loaded ontology; the writer enforces the validator. **Classifier failure is terminal — the ingest aborts entirely; nothing is written. Loud failures, never silent landfill.**
16
+
17
+ ## Routing — chat vs document (mandatory first decision)
18
+
19
+ Before anchor confirmation, decide the parent shape from the input:
20
+
21
+ - **Chat archive** — input filename ends in `_chat.txt`, the dispatch brief names the input as a WhatsApp chat / messaging-channel export, or the operator labels it as such. Set `mode='chat'` and `parentLabel='ConversationArchive'`. Skip anchor confirmation; run participant confirmation instead (see § Participant confirmation). The classifier produces `:Section:Conversation` chunks; no anchor edges, no related entities.
22
+ - **Document** — everything else. Set `mode='document'` and `parentLabel='KnowledgeDocument'` (or omit — these are the defaults). Run the anchor confirmation flow below.
23
+
24
+ Both branches go through the same three tools (`memory-ingest-extract` → `memory-classify` → `memory-ingest`); only the parameters differ.
9
25
 
10
26
  ## Anchor confirmation (mandatory first step)
11
27
 
@@ -27,6 +43,26 @@ The confirmation flow:
27
43
  3. Run a one-shot graph read to resolve the anchor's element ID. For UserProfile: `MATCH (u:UserProfile {accountId: $accountId}) RETURN elementId(u) AS anchorId, 'UserProfile' AS anchorLabel`. For LocalBusiness: `MATCH (b:LocalBusiness {accountId: $accountId}) RETURN elementId(b) AS anchorId, 'LocalBusiness' AS anchorLabel`. For a third party: search by name via `memory-search` and pick the matching node.
28
44
  4. Persist `$anchorNodeId` and `$anchorLabel` for the rest of the run. These flow into both `memory-classify` (as part of the `anchorDescription`) and `memory-ingest` (as the `anchorNodeId` + `anchorLabel` parameters).
29
45
 
46
+ ## Participant confirmation (chat mode only)
47
+
48
+ Chat archives are multi-party — no single subject anchor. Instead, every distinct sender name in the archive must resolve to an existing `:AdminUser` or `:Person` elementId before any classify or ingest call. No auto-creation; missing participants are blockers, not silent skips.
49
+
50
+ The confirmation flow:
51
+
52
+ 1. Read the dispatch brief. Extract the archive path and any operator-stated participant identities.
53
+ 2. Read a small sample of the archive (head ~50 lines) via the `Read` tool to discover the distinct sender names that appear at line starts after the bracketed-timestamp prefix.
54
+ 3. For every distinct senderName, search the graph via `memory-search` (or a one-shot `MATCH (n) WHERE (n:Person OR n:AdminUser) AND n.accountId = $accountId AND (n.name = $name OR (n.givenName + ' ' + n.familyName) = $name) RETURN elementId(n)`).
55
+ 4. **Resolved fully** — every senderName mapped to exactly one elementId. Capture the owner's elementId (the operator who exported the archive — usually the `:AdminUser` for this account; ask if ambiguous) and the comma-separated list of remaining participant elementIds.
56
+ 5. **Unresolved** — at least one senderName has no matching node. Surface to the operator: *"Archive `<filename>` mentions sender `<name>` but no `:Person` / `:AdminUser` matches. Create the contact first or correct the name, then re-dispatch."* Do NOT proceed.
57
+ 6. **Ambiguous** — a senderName matches multiple nodes. Ask the operator which one. Do NOT proceed until disambiguated.
58
+
59
+ Persist `$ownerElementId` and `$participantElementIds` (array, owner excluded) for the run. These flow into `memory-ingest` as the `participantElementIds` parameter (owner + others, deduped).
60
+
61
+ Compute archive metadata before classify:
62
+ - `archiveSha256` — `bash sha256sum "<file>" | cut -d' ' -f1`. Stamped on the parent + every chunk.
63
+ - `archiveSourceFile` — the basename (e.g. `_chat.txt`).
64
+ - `conversationIdentity` — pass as the `attachmentId` parameter to `memory-ingest`. Format: `chat:<sha256(accountId + ":" + sortedParticipantElementIds)>` where `sortedParticipantElementIds` is the sorted-then-comma-joined list of `[owner, ...participants]`. Same conversation across re-exports → same identity → idempotent MERGE on the `:ConversationArchive`.
65
+
30
66
  ## Pipeline
31
67
 
32
68
  Four steps in order. Steps 1–3 are deterministic tool calls (the agent does not classify; the agent calls the classifier tool). Step 4 is agent-driven graph writes against the existing graph, gated by the dispatch brief's named entity list. Hallucination defence and ontology validation stay server-side in `memory-classify` and the `memory-write` validator.
@@ -68,7 +104,13 @@ Form: "Classifying `<filename>` (`<N>` chars) — expect ~`<estimate>`."
68
104
 
69
105
  ### 2. `memory-classify`
70
106
 
71
- Calls Haiku with the loaded ontology and the cached text. Inputs: `attachmentId` (same one), `anchorDescription` (a short sentence built from the confirmed anchor — e.g. `"subject = UserProfile (the account owner); edges from UserProfile."` or `"subject = LocalBusiness {name: 'Acme Roofing'} (the operator's business); edges from LocalBusiness."`). Returns:
107
+ Calls Haiku with the loaded ontology and the cached text.
108
+
109
+ **Document mode (default).** Inputs: `attachmentId` (same one), `anchorDescription` (a short sentence built from the confirmed anchor — e.g. `"subject = UserProfile (the account owner); edges from UserProfile."` or `"subject = LocalBusiness {name: 'Acme Roofing'} (the operator's business); edges from LocalBusiness."`).
110
+
111
+ **Chat mode.** Inputs: `attachmentId` (same one), `mode='chat'`, `anchorDescription` (a short sentence naming the conversation — e.g. `"WhatsApp conversation between Joel and Adam (2 participants)"`). The chat prompt drops the natural-edge map, the closed enumeration, and the orphan logic — Haiku produces topic-bounded `:Section:Conversation` chunks with `summary`, `keywords`, `firstMessageAt`, `lastMessageAt`, `participantNames`, `messageCount` per chunk. The whole archive may produce one chunk (short conversation) or many (long chat with topic transitions); chunks cover every message in chronological order with no gaps.
112
+
113
+ Returns:
72
114
 
73
115
  - `documentSummary` — 1-3 sentences for the KnowledgeDocument node
74
116
  - `documentKeywords` — 3-10 lowercase topic keywords
@@ -83,7 +125,13 @@ After step 2 succeeds, emit a chat message before step 3 naming what the classif
83
125
 
84
126
  ### 3. `memory-ingest`
85
127
 
86
- Writes the classified document. Inputs: `attachmentId`, `documentSummary`, `anchorNodeId`, `anchorLabel`, `sections`, `documentEdges` (pass through if present), `orphanCandidates` (pass through if present), `scope` (from the brief — confirm with the operator if absent), optional `documentKeywords`, `userKeywords`, `sourceUrl`, `sourceType`. Returns:
128
+ Writes the classified document or chat archive.
129
+
130
+ **Document mode (default).** Inputs: `attachmentId`, `documentSummary`, `anchorNodeId`, `anchorLabel`, `sections`, `documentEdges` (pass through if present), `orphanCandidates` (pass through if present), `scope` (from the brief — confirm with the operator if absent), optional `documentKeywords`, `userKeywords`, `sourceUrl`, `sourceType`.
131
+
132
+ **Chat mode.** Inputs: `attachmentId` (set to `conversationIdentity`), `parentLabel='ConversationArchive'`, `documentSummary`, `sections` (the chunks from chat-mode classify), `scope`, plus the chat-archive metadata: `archiveSha256` (cleanup discriminator), `archiveSourceFile` (audit), `participantElementIds` (owner + others, for `:PARTICIPANT_IN` edges). Pass `anchorNodeId` and `anchorLabel` as any non-empty placeholder (e.g. the owner's elementId + `'AdminUser'`) — they are unused on the chat path but the parameter is non-optional. The writer MERGEs `:ConversationArchive { conversationIdentity }`, drops any chunks stamped with this `archiveSha256` (idempotent re-ingest), CREATEs new chunks chained by `:NEXT`, and MERGEs `:PARTICIPANT_IN` edges from each participant.
133
+
134
+ Returns:
87
135
 
88
136
  - `documentNodeId`, `sectionCount`
89
137
  - `kindBreakdown` — per-kind count, e.g. `{"Position": 4, "Chapter": 12, "Other": 1}`
@@ -99,6 +147,8 @@ Re-ingesting the same `attachmentId` is safe — the writer drops prior `:Sectio
99
147
 
100
148
  ### 4. `wire-brief-entities`
101
149
 
150
+ **Skipped in chat mode** — `:ConversationArchive` does not carry KD-level brief-wired edges; participants are already attached via `:PARTICIPANT_IN` and message bodies stay verbatim inside chunk text (mention extraction is deferred to a separate insight-derivation task). Document mode only.
151
+
102
152
  After `memory-ingest` returns the new KnowledgeDocument's `documentNodeId`, this step iterates the entities the dispatch brief named and connects each to the new document with the natural KD-level edge.
103
153
 
104
154
  **Entity sources.** The dispatch brief's "key entities to connect" list. Brief shape: prose names of Persons, Organizations, Services, Tasks, Events, KnowledgeDocuments, BrandingData that the document describes or references. Example: *"Person nodes for Joel Smalley, Adam Mackay, Dan McLeod; LocalBusiness / Organization nodes for Real Agent / Real Agency; Any existing Task nodes related to Real Agent Lettings."* Extract every named entity from the brief before any `memory-write`.
@@ -51,7 +51,7 @@ When per-group activation is `mention`, the agent fires only if the inbound mess
51
51
 
52
52
  ## Live persistence
53
53
 
54
- Every `messages.upsert` event (both `notify` and `append`, both `fromMe` directions) writes a `:Message:WhatsAppMessage` row to Neo4j attached to the sessionKey-keyed `:Conversation`. A single capture site at `platform/ui/app/lib/whatsapp/manager.ts` covers inbound, outbound (Baileys echoes agent-sent messages back through `messages.upsert` with `fromMe=true`), and owner-mirror — without touching `outbound/send.ts`. `messageId` namespace is `whatsapp-live:<waName>:<remoteJid>:<msg.key.id>` where `<waName>` is the Baileys credential dirname (e.g. `default`); collision-free with the `whatsapp-export:` namespace used by the offline `whatsapp-import` plugin. Persist failures are loud (`[whatsapp-persist] FAIL …`) and never block dispatch — silent loss is the worse failure mode.
54
+ Every `messages.upsert` event (both `notify` and `append`, both `fromMe` directions) writes a `:Message:WhatsAppMessage` row to Neo4j attached to the sessionKey-keyed `:Conversation`. A single capture site at `platform/ui/app/lib/whatsapp/manager.ts` covers inbound, outbound (Baileys echoes agent-sent messages back through `messages.upsert` with `fromMe=true`), and owner-mirror — without touching `outbound/send.ts`. `messageId` namespace is `whatsapp-live:<waName>:<remoteJid>:<msg.key.id>` where `<waName>` is the Baileys credential dirname (e.g. `default`). The live plugin writes `:Message:WhatsAppMessage` rows; offline `_chat.txt` archives are document-shaped narrative and route through `document-ingest` with `parentLabel='ConversationArchive'` (unified-ingest pipeline migration) producing `:Section:Conversation` chunks — entity types differ, no namespace collision. Persist failures are loud (`[whatsapp-persist] FAIL …`) and never block dispatch — silent loss is the worse failure mode.
55
55
 
56
56
  **`accountId` contract.** `n.accountId` on every `:Conversation`, `:Person`, and `:Message:WhatsAppMessage` row stamped by this plugin is the **platform-side UUID** resolved by [`resolvePlatformAccountId()`](../../ui/app/lib/whatsapp/platform-account-id.ts) from `data/accounts/<uuid>/account.json` — NOT the Baileys credential dirname (which is only used as the `messageId`/`sessionKey` namespace token). The boot-time line `[whatsapp-persist] resolved-account-id waname=<dir> uuid=<uuid>` records the resolution. Doctrine: see `.docs/neo4j.md` "Account isolation invariant" — migration 004 `pruneAlienAccounts` `DETACH DELETE`s any node whose `accountId` is not a UUID dir on every boot. The helper loud-throws on zero or multi accounts (Phase 0 single-account invariant), aborting the WhatsApp connection start before any write can occur.
57
57
 
@@ -98,22 +98,23 @@ fi
98
98
  # webfetch-preflight.mjs: detects JS-SPA shells before WebFetch's
99
99
  # 60s extraction timeout (Task 536). Fail-open on any error;
100
100
  # on positive SPA detection exits 2 with WEBFETCH_CANNOT_READ_JS_SPA.
101
- # archive-ingest-surface-gate.sh (Task 855; supersedes Task 846):
101
+ # archive-ingest-surface-gate.sh (Task 855; trimmed by Task 894):
102
102
  # narrows the database-operator subagent's effective surface
103
- # during WhatsApp archive ingestion to exactly one Bash entry
104
- # (whatsapp-import/bin/whatsapp-ingest.sh) plus read-only
105
- # neighbours, by blocking the legacy MCP deviation tools
106
- # (mcp__memory__whatsapp-export-parse,
107
- # mcp__memory__whatsapp-export-insight-write, and
108
- # mcp__memory__memory-archive-write when archiveType is
109
- # whatsapp-export). Preserves Task 846's plugin-source edit,
110
- # JS test-runner, and post-parse-error blocks (LinkedIn and
111
- # future per-source archive parsers still use the legacy MCP
112
- # path until they migrate to deterministic Bash entries).
103
+ # during flat-dataset archive ingestion (LinkedIn today;
104
+ # future CRM-type seeds) by enforcing three blocks:
105
+ # plugin-source edits under platform/plugins/*/lib/*, JS
106
+ # test-runner Bash commands, and a post-parse-error flag
107
+ # that blocks the rest of the turn after any
108
+ # *-export-parse / *-import-parse tool returns isError=true.
109
+ # Task 894 removed the WhatsApp-specific MCP-tool blocks
110
+ # (the three legacy whatsapp-export tools were deleted; chat
111
+ # archives now flow through the unified document-ingest
112
+ # pipeline with parentLabel='ConversationArchive' and
113
+ # mode='chat').
113
114
  # Wired at three points: explicit Edit/Write/NotebookEdit/Bash
114
- # matchers, a no-matcher PreToolUse entry (catches the legacy
115
- # MCP tools and post-parse-error gate fires on every tool),
116
- # and a PostToolUse regex matcher for parse tools.
115
+ # matchers, a no-matcher PreToolUse entry (post-parse-error
116
+ # gate fires on every tool), and a PostToolUse regex matcher
117
+ # for parse tools.
117
118
  # UserPromptSubmit — archive-ingest-surface-gate.sh clears the
118
119
  # parse-error flag when the operator's next prompt arrives.
119
120
  HOOKS_PATH="\$PLATFORM_ROOT/plugins/admin/hooks"
@@ -3,7 +3,7 @@ name: database-operator
3
3
  description: "Document and archive ingestion and ad-hoc graph operations — running the universal `document-ingest` skill for any unstructured document (PDF, text, transcript, web page, audio, video) and per-source archive-import skills (LinkedIn Basic Data Export today; CRM-type seed archives as each plugin ships), plus operator-driven graph hygiene (prune orphans, deduplicate entities, add edges, normalise labels). Delegate when the operator uploads any document, drops an archive directory into chat, or asks for any graph operation that is not a routine per-turn write."
4
4
  summary: "Ingests every unstructured document and external archive into your graph (LinkedIn today; other CRM sources in future) and handles ad-hoc graph tidy-ups on request. For example, when you upload a CV, a pricing guide, or a contract; when you drop a LinkedIn export folder into chat; or when you ask to prune orphan nodes, merge duplicate people, or add edges between entities."
5
5
  model: claude-sonnet-4-6
6
- tools: Read, Bash, Glob, Grep, mcp__graph__maxy-graph-read_neo4j_cypher, mcp__graph__maxy-graph-write_neo4j_cypher, mcp__graph__maxy-graph-get_neo4j_schema, mcp__memory__memory-write, mcp__memory__memory-update, mcp__memory__memory-delete, mcp__memory__memory-search, mcp__memory__memory-rank, mcp__memory__memory-reindex, mcp__memory__memory-find-candidates, mcp__memory__memory-ingest, mcp__memory__memory-ingest-extract, mcp__memory__memory-ingest-web, mcp__memory__memory-classify, mcp__memory__memory-archive-write, mcp__memory__whatsapp-export-preview, mcp__memory__graph-prune-denylist-list, mcp__memory__graph-prune-denylist-add, mcp__memory__graph-prune-denylist-remove, mcp__contacts__contact-create, mcp__contacts__contact-update, mcp__contacts__contact-lookup, mcp__contacts__contact-list, mcp__tasks__task-create, mcp__admin__file-attach, mcp__admin__plugin-read
6
+ tools: Read, Bash, Glob, Grep, mcp__graph__maxy-graph-read_neo4j_cypher, mcp__graph__maxy-graph-write_neo4j_cypher, mcp__graph__maxy-graph-get_neo4j_schema, mcp__memory__memory-write, mcp__memory__memory-update, mcp__memory__memory-delete, mcp__memory__memory-search, mcp__memory__memory-rank, mcp__memory__memory-reindex, mcp__memory__memory-find-candidates, mcp__memory__memory-ingest, mcp__memory__memory-ingest-extract, mcp__memory__memory-ingest-web, mcp__memory__memory-classify, mcp__memory__memory-archive-write, mcp__memory__graph-prune-denylist-list, mcp__memory__graph-prune-denylist-add, mcp__memory__graph-prune-denylist-remove, mcp__contacts__contact-create, mcp__contacts__contact-update, mcp__contacts__contact-lookup, mcp__contacts__contact-list, mcp__tasks__task-create, mcp__admin__file-attach, mcp__admin__plugin-read
7
7
  ---
8
8
 
9
9
  # Database Operator
@@ -30,17 +30,17 @@ A landfill graph defeats EVIDENCE-BASED: search returns noise, the agent re-writ
30
30
 
31
31
  The pre-publish gate (`platform/scripts/verify-skill-tool-surface.sh`) statically asserts every shipped skill's prescribed `mcp__*` tokens resolve against your frontmatter `tools:` list, so a missing tool is a build error, not a production discovery. LOUD-FAIL is the runtime backstop when that gate is bypassed (e.g. operator-edited skill).
32
32
 
33
- **Archive-ingest surface gate.** Each per-source archive importer ships a single deterministic Bash entry under `platform/plugins/<name>/bin/<name>-ingest.sh`. The harness-level gate at `platform/plugins/admin/hooks/archive-ingest-surface-gate.sh` enforces the surface filter that makes the LLM mechanically incapable of deviating mid-ingest:
33
+ **Archive-ingest surface gate.** Each per-source flat-dataset importer ships a single deterministic surface (today: `memory-archive-write` with `archiveType=linkedin-connections`; future per-source plugins may ship `bin/<name>-ingest.sh` entries). The harness-level gate at `platform/plugins/admin/hooks/archive-ingest-surface-gate.sh` enforces the surface filter that makes the LLM mechanically incapable of deviating mid-ingest:
34
34
 
35
- - **Legacy WhatsApp MCP tools blocked unconditionally:** `mcp__memory__whatsapp-export-parse`, `mcp__memory__whatsapp-export-insight-write`, `mcp__memory__whatsapp-export-insight-pass` (deleted by Task 891), and `mcp__memory__memory-archive-write` when `archiveType=whatsapp-export`. The deterministic Bash entry (`platform/plugins/whatsapp-import/bin/whatsapp-ingest.sh`) is the only supported path; parse, sessionize, classify (mode='chat'), and memory-ingest (parentLabel='ConversationArchive') all run in-process.
36
- - **Non-WhatsApp archiveTypes flow unchanged:** `memory-archive-write` with `archiveType=linkedin-connections` (and future per-source archiveTypes) is allowed. Each per-source plugin migrates to its own `bin/<name>-ingest.sh` on its own schedule.
37
35
  - **Plugin-source edits blocked:** `Edit`/`Write`/`NotebookEdit` against `platform/plugins/*/lib/*` is denied. The operator does not own plugin source.
38
- - **JS test runners blocked** (preserved): `vitest` / `bun test` / `npm test` / `npx jest` Bash commands are denied. The operator does not run plugin tests.
39
- - **Post-parse-error flag** (preserved for non-migrated parsers): when any `mcp__*__*-export-parse` / `mcp__*__*-import-parse` tool returns `isError: true`, every subsequent tool call this turn is blocked until the operator submits a new prompt.
36
+ - **JS test runners blocked:** `vitest` / `bun test` / `npm test` / `npx jest` Bash commands are denied. The operator does not run plugin tests.
37
+ - **Post-parse-error flag:** when any `mcp__*__*-export-parse` / `mcp__*__*-import-parse` tool returns `isError: true`, every subsequent tool call this turn is blocked until the operator submits a new prompt — so a parse failure cannot silently fall back to a partial write.
40
38
 
41
- Every PreToolUse decision emits `[archive-ingest-gate] decision=<allow|block> tool=<n> reason=<r> ...` to server.log so the full trail of one ingest is greppable alongside the `[whatsapp-ingest]` script lines.
39
+ Every PreToolUse decision emits `[archive-ingest-gate] decision=<allow|block> tool=<n> reason=<r> ...` to server.log so the full trail of one ingest is greppable.
42
40
 
43
- *Failure symptoms (now harness-blocked):* invoking `mcp__memory__whatsapp-export-parse` instead of the Bash script, calling `mcp__memory__memory-archive-write` with `archiveType:'whatsapp-export'` directly, editing `parse-export.ts` to "fix" a malformed input, running `npx vitest` to "diagnose" a parser. Treat these blocks as confirmation the gate is doing its job — invoke the script, surface its FAIL line if it fails, and yield. There is no around-the-block path.
41
+ *Failure symptoms (now harness-blocked):* editing plugin `lib/` source to "fix" a malformed input, running `npx vitest` to "diagnose" a parser. Treat these blocks as confirmation the gate is doing its job — surface the failure to the operator and yield.
42
+
43
+ WhatsApp `_chat.txt` archives are document-shaped narrative content and route through the unified `document-ingest` pipeline (`memory-classify` `mode='chat'` + `memory-ingest` `parentLabel='ConversationArchive'`); there is no WhatsApp-specific tool, parser, or surface gate (Task 894).
44
44
 
45
45
  ---
46
46
 
@@ -119,14 +119,8 @@ The classifier maps document sections to typed ontology labels. It does not inve
119
119
  Per-source archive imports keep their own skill because their CSVs already encode entity types deterministically and need no LLM classifier. Currently shipped:
120
120
 
121
121
  - **linkedin-import** — LinkedIn Basic Data Export. Ships with references for `Profile.csv` and `Connections.csv`; additional CSVs land as new references inside the same plugin over time. Path: `platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md`. Load via `plugin-read` before any ingestion.
122
- - **whatsapp-import** — WhatsApp `_chat.txt` export ingestion. **Single-phase chunked-archive contract** (Task 891 — supersedes the prior two-phase load+enrich flow):
123
- 1. **Preview** via `mcp__memory__whatsapp-export-preview` — read-only parse that returns `{conversationSha256, parsed, mediaSkipped, systemSkipped, dateRange, senders:[{name,messageCount}], totalMessages, archiveBytes}`. No Cypher writes.
124
- 2. **Operator confirms owner + every distinct sender.** Iterate the preview's sender histogram one question at a time: for each sender, ask the operator to pick an existing `:AdminUser`/`:Person` elementId or block. Auto-creating participants is forbidden. Identify the owner from the resolved set, then echo back the `{owner, participants...}` pair for explicit yes/no confirmation.
125
- 3. **Archive-write** via `bash platform/plugins/whatsapp-import/bin/whatsapp-ingest.sh <archive> --owner-element-id <id> --participant-person-ids <id1>,<id2>,... --scope <admin|public>`. Parses, sessionizes the parsed messages at gap-hours boundaries (default 12h), classifies each session via Haiku (`memory-classify` with `mode='chat'`) into topic-bounded `:Section:Conversation` chunks, and writes them under a parent `:ConversationArchive` MERGEd on `conversationIdentity = sha256(accountId + ":" + sortedParticipantElementIds)`. Re-imports are delta-append: prior chunks never touched; only messages after `lastIngestedMessageHash` flow through the pipeline. Writer is bound to the operator-confirmed sender set — any parsed senderName outside that closed set LOUD-FAILs `parser-miss reason="..."`.
126
-
127
- Surface to the operator as three chat messages built from the JSON summary on stdout: (a) parse summary with sender histogram + date range; (b) classify summary with chunk count + topic keywords; (c) write summary with `:ConversationArchive` elementId + chunk count + NEXT-chain length + participants linked. Empty-delta re-imports collapse to step (a) plus a noop line. The legacy `mcp__memory__whatsapp-export-parse` / `whatsapp-export-insight-write` / `whatsapp-export-insight-pass` / `memory-archive-write{archiveType:whatsapp-export}` MCP tools are blocked at the harness; the Bash script is the only supported invocation surface. SKILL: `platform/plugins/whatsapp-import/skills/whatsapp-import/SKILL.md`. Phase 2 insight derivation (`:Observation` / `:Task` / `:Preference` / `:MENTIONS` against chunks) is deferred to a separate follow-up task with its own skill.
128
122
 
129
- Distinct from the live `whatsapp` plugin (Baileys QR pairing, in-memory store).
123
+ WhatsApp `_chat.txt` ingest = `document-ingest` with `parentLabel='ConversationArchive'`, `mode='chat'`. No WhatsApp-specific tools (Task 894). Distinct from the live `whatsapp` plugin (Baileys QR pairing, in-memory store).
130
124
 
131
125
  Future CRM-type seed plugins (HubSpot, Salesforce, Pipedrive, iCloud contacts, Gmail CSV, etc.) will ship under the same pattern — each as its own opt-in plugin, each with its own `SKILL.md` path under `platform/plugins/<name>/skills/`. When the admin adds a new archive-import skill, its PLUGIN.md will name itself here and in the admin's `<plugin-manifest>`. No prompt change required.
132
126