@rubytech/create-maxy-code 0.1.591 → 0.1.593

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 (126) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/routine-templates/dist/index.d.ts +2 -2
  3. package/payload/platform/lib/routine-templates/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/routine-templates/dist/index.js +2 -9
  5. package/payload/platform/lib/routine-templates/dist/index.js.map +1 -1
  6. package/payload/platform/lib/routine-templates/dist/roster.d.ts +1 -11
  7. package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
  8. package/payload/platform/lib/routine-templates/dist/roster.js +11 -15
  9. package/payload/platform/lib/routine-templates/dist/roster.js.map +1 -1
  10. package/payload/platform/lib/routine-templates/src/__tests__/roster.test.ts +0 -0
  11. package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +8 -3
  12. package/payload/platform/lib/routine-templates/src/index.ts +1 -8
  13. package/payload/platform/lib/routine-templates/src/roster.ts +10 -14
  14. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +7 -3
  15. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
  16. package/payload/platform/plugins/docs/references/internals.md +4 -2
  17. package/payload/platform/plugins/docs/references/telegram-guide.md +2 -0
  18. package/payload/platform/plugins/scheduling/PLUGIN.md +6 -6
  19. package/payload/platform/plugins/scheduling/mcp/dist/index.js +4 -12
  20. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  21. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +85 -1
  22. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
  23. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +55 -1
  24. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
  25. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +10 -1
  26. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
  27. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +42 -6
  28. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
  29. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +22 -0
  30. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
  31. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +73 -0
  32. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
  33. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +93 -1
  34. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  35. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +2 -1
  36. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  37. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +45 -1
  38. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  39. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +19 -2
  40. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  41. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +27 -280
  42. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
  43. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +315 -208
  44. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  45. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +1 -31
  46. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  47. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +15 -95
  48. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  49. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -1
  50. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +5 -36
  51. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -1
  52. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +83 -51
  53. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  54. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +152 -105
  55. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  56. package/payload/platform/plugins/telegram/PLUGIN.md +12 -5
  57. package/payload/platform/plugins/telegram/mcp/dist/__tests__/ask-tool.test.js +31 -0
  58. package/payload/platform/plugins/telegram/mcp/dist/__tests__/ask-tool.test.js.map +1 -1
  59. package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-tool.test.js +30 -0
  60. package/payload/platform/plugins/telegram/mcp/dist/__tests__/card-tool.test.js.map +1 -1
  61. package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-fetch-tool.test.js +24 -0
  62. package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-fetch-tool.test.js.map +1 -1
  63. package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-send-tool.test.js +31 -0
  64. package/payload/platform/plugins/telegram/mcp/dist/__tests__/media-send-tool.test.js.map +1 -1
  65. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.d.ts +2 -0
  66. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.d.ts.map +1 -0
  67. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js +55 -0
  68. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin-registry.test.js.map +1 -0
  69. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.d.ts +2 -0
  70. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.d.ts.map +1 -0
  71. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js +89 -0
  72. package/payload/platform/plugins/telegram/mcp/dist/__tests__/public-pin.test.js.map +1 -0
  73. package/payload/platform/plugins/telegram/mcp/dist/index.js +13 -42
  74. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -1
  75. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts +80 -0
  76. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.d.ts.map +1 -0
  77. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js +96 -0
  78. package/payload/platform/plugins/telegram/mcp/dist/lib/public-pin.js.map +1 -0
  79. package/payload/platform/plugins/telegram/mcp/dist/tools/ask.d.ts +5 -0
  80. package/payload/platform/plugins/telegram/mcp/dist/tools/ask.d.ts.map +1 -1
  81. package/payload/platform/plugins/telegram/mcp/dist/tools/ask.js.map +1 -1
  82. package/payload/platform/plugins/telegram/mcp/dist/tools/card.d.ts +5 -0
  83. package/payload/platform/plugins/telegram/mcp/dist/tools/card.d.ts.map +1 -1
  84. package/payload/platform/plugins/telegram/mcp/dist/tools/card.js.map +1 -1
  85. package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.d.ts +5 -0
  86. package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.d.ts.map +1 -1
  87. package/payload/platform/plugins/telegram/mcp/dist/tools/media-fetch.js.map +1 -1
  88. package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.d.ts +5 -0
  89. package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.d.ts.map +1 -1
  90. package/payload/platform/plugins/telegram/mcp/dist/tools/media-send.js.map +1 -1
  91. package/payload/platform/plugins/telegram/mcp/dist/tools/thread.d.ts +5 -0
  92. package/payload/platform/plugins/telegram/mcp/dist/tools/thread.d.ts.map +1 -1
  93. package/payload/platform/plugins/telegram/mcp/dist/tools/thread.js.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +37 -0
  95. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  96. package/payload/platform/services/claude-session-manager/dist/http-server.js +178 -13
  97. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  98. package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts +13 -5
  99. package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts.map +1 -1
  100. package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js +23 -9
  101. package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js.map +1 -1
  102. package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts +7 -4
  103. package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.d.ts.map +1 -1
  104. package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js +5 -3
  105. package/payload/platform/services/claude-session-manager/dist/telegram-channel-mcp.js.map +1 -1
  106. package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.d.ts +15 -1
  107. package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.d.ts.map +1 -1
  108. package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.js +16 -7
  109. package/payload/platform/services/claude-session-manager/dist/telegram-channel-store.js.map +1 -1
  110. package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.d.ts +28 -0
  111. package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.d.ts.map +1 -0
  112. package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.js +53 -0
  113. package/payload/platform/services/claude-session-manager/dist/telegram-plugin-mcp.js.map +1 -0
  114. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts +9 -5
  115. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.d.ts.map +1 -1
  116. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js +12 -6
  117. package/payload/platform/services/claude-session-manager/dist/wa-channel-mcp.js.map +1 -1
  118. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +7 -3
  119. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
  120. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +5 -1
  121. package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
  122. package/payload/platform/services/telegram-channel/dist/instructions.d.ts +14 -2
  123. package/payload/platform/services/telegram-channel/dist/instructions.d.ts.map +1 -1
  124. package/payload/platform/services/telegram-channel/dist/instructions.js +34 -3
  125. package/payload/platform/services/telegram-channel/dist/instructions.js.map +1 -1
  126. package/payload/server/server.js +74 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.591",
3
+ "version": "0.1.593",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -31,7 +31,7 @@
31
31
  * unrelated, which is worse than no citation.
32
32
  */
33
33
  import { type RoutineTemplate } from "./roster.js";
34
- export { ROUTINE_ROSTER, ROUTINE_ROSTER_KEYS, ROUTINE_TEMPLATE_VERSION, isWatermarkedCheck, gateNeedsCommit, GATE_COMMIT_TOKEN, } from "./roster.js";
34
+ export { ROUTINE_ROSTER, ROUTINE_ROSTER_KEYS, ROUTINE_TEMPLATE_VERSION, isWatermarkedCheck, gateNeedsCommit, } from "./roster.js";
35
35
  export type { RoutineTemplate, RoutineGate, RoutineGateCheck } from "./roster.js";
36
36
  /** The minimal Neo4j session surface the seed needs. Both the admin plugin's
37
37
  * `getSession()` and a driver session from `seed-cli` satisfy it; the tests
@@ -150,7 +150,7 @@ export declare function resolveOwnerTimezone(session: SeedSessionLike, accountId
150
150
  * the commit token is substituted from the same `row.gateChecks` the gate is
151
151
  * built from, so the precondition and the turn's own commit call cannot
152
152
  * disagree about what this routine checks. */
153
- export declare const MERGE_CYPHER = "\nUNWIND $rows AS row\nOPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})\nWITH row,\n pre IS NOT NULL AS existed,\n coalesce(pre.routineTemplateVersion, 0) AS priorVersion,\n pre.operatorEdited IS NOT NULL AS edited\nWITH row, existed, priorVersion, edited,\n (existed AND NOT edited AND priorVersion < $version) AS refreshing\nMERGE (e:Event {accountId: $accountId, routineTemplate: row.key})\n ON CREATE SET e.eventId = randomUUID(),\n e.name = row.name,\n e.description = row.description,\n e.agentPrompt = row.prompt,\n e.recurrence = row.recurrence,\n e.routineTemplateVersion = $version,\n e.eventStatus = 'suspended',\n e.nextRun = null,\n e.agentChannel = null,\n e.agentDestination = null,\n e.actionPlugin = null,\n e.actionTool = null,\n e.actionArgs = null,\n e.sourcePlugin = null,\n e.timezone = $timezone,\n e.createdBySource = 'installer',\n e.createdByAgent = 'system',\n e.createdByTool = 'routine-roster-seed',\n e.createdAt = $now,\n e.updatedAt = $now\n ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,\n e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,\n e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,\n e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,\n e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END\nWITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing\nSET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,\n e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,\n e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{\"eventId\":\"' + e.eventId + '\",\"checks\":' + row.gateChecks + '}' END) ELSE e.gateArgs END,\n e.agentPrompt = CASE WHEN writing AND row.gateChecks IS NOT NULL\n THEN replace(e.agentPrompt, '<<gateCommit>>', '{\"eventId\":\"' + e.eventId + '\",\"checks\":' + row.gateChecks + ',\"commit\":true}')\n ELSE e.agentPrompt END\nRETURN row.key AS key,\n e.eventId AS eventId,\n CASE WHEN NOT existed THEN 'create'\n WHEN priorVersion >= $version THEN 'unchanged'\n WHEN edited THEN 'skip-operator-edited'\n ELSE 'refresh-version' END AS action";
153
+ export declare const MERGE_CYPHER = "\nUNWIND $rows AS row\nOPTIONAL MATCH (pre:Event {accountId: $accountId, routineTemplate: row.key})\nWITH row,\n pre IS NOT NULL AS existed,\n coalesce(pre.routineTemplateVersion, 0) AS priorVersion,\n pre.operatorEdited IS NOT NULL AS edited\nWITH row, existed, priorVersion, edited,\n (existed AND NOT edited AND priorVersion < $version) AS refreshing\nMERGE (e:Event {accountId: $accountId, routineTemplate: row.key})\n ON CREATE SET e.eventId = randomUUID(),\n e.name = row.name,\n e.description = row.description,\n e.agentPrompt = row.prompt,\n e.recurrence = row.recurrence,\n e.routineTemplateVersion = $version,\n e.eventStatus = 'suspended',\n e.nextRun = null,\n e.agentChannel = null,\n e.agentDestination = null,\n e.actionPlugin = null,\n e.actionTool = null,\n e.actionArgs = null,\n e.sourcePlugin = null,\n e.timezone = $timezone,\n e.createdBySource = 'installer',\n e.createdByAgent = 'system',\n e.createdByTool = 'routine-roster-seed',\n e.createdAt = $now,\n e.updatedAt = $now\n ON MATCH SET e.agentPrompt = CASE WHEN refreshing THEN row.prompt ELSE e.agentPrompt END,\n e.name = CASE WHEN refreshing THEN row.name ELSE e.name END,\n e.description = CASE WHEN refreshing THEN row.description ELSE e.description END,\n e.routineTemplateVersion = CASE WHEN refreshing THEN $version ELSE e.routineTemplateVersion END,\n e.updatedAt = CASE WHEN refreshing THEN $now ELSE e.updatedAt END\nWITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing\nSET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,\n e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,\n e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{\"eventId\":\"' + e.eventId + '\",\"checks\":' + row.gateChecks + '}' END) ELSE e.gateArgs END\nRETURN row.key AS key,\n e.eventId AS eventId,\n CASE WHEN NOT existed THEN 'create'\n WHEN priorVersion >= $version THEN 'unchanged'\n WHEN edited THEN 'skip-operator-edited'\n ELSE 'refresh-version' END AS action";
154
154
  /** The post-condition read. Counts every roster row the account actually holds,
155
155
  * independently of what the MERGE above believes it wrote. */
156
156
  export declare const VERIFY_CYPHER = "\nMATCH (e:Event {accountId: $accountId})\nWHERE e.routineTemplate IS NOT NULL\nRETURN count(e) AS actual,\n sum(CASE WHEN e.eventStatus = 'suspended' THEN 1 ELSE 0 END) AS suspended,\n sum(CASE WHEN e.nextRun IS NULL THEN 1 ELSE 0 END) AS nextRunNull,\n sum(CASE WHEN e.description IS NULL THEN 1 ELSE 0 END) AS descNull";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.VERIFY_CYPHER = exports.MERGE_CYPHER = exports.GATE_COMMIT_TOKEN = exports.gateNeedsCommit = exports.isWatermarkedCheck = exports.ROUTINE_TEMPLATE_VERSION = exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = void 0;
3
+ exports.VERIFY_CYPHER = exports.MERGE_CYPHER = exports.gateNeedsCommit = exports.isWatermarkedCheck = exports.ROUTINE_TEMPLATE_VERSION = exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = void 0;
4
4
  exports.acctTag = acctTag;
5
5
  exports.resolveOwnerTimezone = resolveOwnerTimezone;
6
6
  exports.seedRoutineRoster = seedRoutineRoster;
@@ -49,10 +49,6 @@ Object.defineProperty(exports, "ROUTINE_ROSTER_KEYS", { enumerable: true, get: f
49
49
  Object.defineProperty(exports, "ROUTINE_TEMPLATE_VERSION", { enumerable: true, get: function () { return roster_js_2.ROUTINE_TEMPLATE_VERSION; } });
50
50
  Object.defineProperty(exports, "isWatermarkedCheck", { enumerable: true, get: function () { return roster_js_2.isWatermarkedCheck; } });
51
51
  Object.defineProperty(exports, "gateNeedsCommit", { enumerable: true, get: function () { return roster_js_2.gateNeedsCommit; } });
52
- // Task 2634 — the scheduling plugin's write-time guard accepts a prompt that
53
- // carries this token, so the token has to be reachable from the package's own
54
- // entry point rather than only from the roster the seed reads.
55
- Object.defineProperty(exports, "GATE_COMMIT_TOKEN", { enumerable: true, get: function () { return roster_js_2.GATE_COMMIT_TOKEN; } });
56
52
  /** Neo4j returns integers as its own `Integer` type over bolt and as plain
57
53
  * numbers through a test fake. Normalise both without importing the driver. */
58
54
  function toInt(raw) {
@@ -167,10 +163,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
167
163
  WITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing
168
164
  SET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,
169
165
  e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,
170
- e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END,
171
- e.agentPrompt = CASE WHEN writing AND row.gateChecks IS NOT NULL
172
- THEN replace(e.agentPrompt, '<<gateCommit>>', '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + ',"commit":true}')
173
- ELSE e.agentPrompt END
166
+ e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
174
167
  RETURN row.key AS key,
175
168
  e.eventId AS eventId,
176
169
  CASE WHEN NOT existed THEN 'create'
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AA8HA,0BAEC;AAaD,oDAgBC;AAiID,8CAoFC;AAlXD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,2CAA6F;AAE7F,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,SAAS;AACT,yCAUqB;AATnB,2GAAA,cAAc,OAAA;AACd,gHAAA,mBAAmB,OAAA;AACnB,qHAAA,wBAAwB,OAAA;AACxB,+GAAA,kBAAkB,OAAA;AAClB,4GAAA,eAAe,OAAA;AACf,6EAA6E;AAC7E,8EAA8E;AAC9E,+DAA+D;AAC/D,8GAAA,iBAAiB,OAAA;AAiEnB;gFACgF;AAChF,SAAS,KAAK,CAAC,GAAY;IACzB,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,GAAG,IAAI,OAAQ,GAAmC,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC/E,OAAQ,GAAkC,CAAC,QAAQ,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED;4DAC4D;AAC5D,SAAgB,OAAO,CAAC,SAAiB;IACvC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,oBAAoB,CACxC,OAAwB,EACxB,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAC3B;;;aAGS,EACT,EAAE,SAAS,EAAE,CACd,CAAC;IACF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CAsC+C;AAClC,QAAA,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDA+CqB,CAAC;AAElD;+DAC+D;AAClD,QAAA,aAAa,GAAG;;;;;;0EAM6C,CAAC;AAkB3E;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,iBAAiB,CAAC,IAA2B;IACjE,MAAM,EACJ,OAAO,EACP,SAAS,EACT,OAAO,GAAG,oCAAwB,EAClC,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAC9B,MAAM,GAAG,0BAAc,EACvB,GAAG,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,EACzD,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GACzB,GAAG,IAAI,CAAC;IAET,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC;IAC1B,GAAG,CAAC,gCAAgC,IAAI,WAAW,MAAM,CAAC,MAAM,YAAY,OAAO,EAAE,CAAC,CAAC;IAEvF,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAC5E,GAAG,CAAC,sCAAsC,IAAI,OAAO,QAAQ,IAAI,MAAM,WAAW,MAAM,EAAE,CAAC,CAAC;IAE5F,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,oBAAY,EAAE;QAC/C,SAAS;QACT,OAAO;QACP,QAAQ;QACR,GAAG;QACH,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvB,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,mEAAmE;YACnE,oEAAoE;YACpE,iCAAiC;YACjC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI;SAC1D,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,MAAM,GAAsB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/D,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAuB;KACxD,CAAC,CAAC,CAAC;IAEJ,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,GAAG,CAAC,gCAAgC,IAAI,QAAQ,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,MAAM,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,qBAAa,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,MAAM,GAAwB;QAClC,QAAQ,EAAE,MAAM,CAAC,MAAM;QACvB,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QAC7C,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;KAC5C,CAAC;IACF,GAAG,CACD,iCAAiC,IAAI,aAAa,MAAM,CAAC,QAAQ,WAAW,MAAM,CAAC,MAAM,GAAG;QAC1F,aAAa,MAAM,CAAC,SAAS,gBAAgB,MAAM,CAAC,WAAW,aAAa,MAAM,CAAC,QAAQ,EAAE,CAChG,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACnE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,iBAAiB,CAAC,CAAC,MAAM,CAAC;IAC9E,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,sBAAsB,CAAC,CAAC,MAAM,CAAC;IAC/F,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC;IAElC,GAAG,CACD,8BAA8B,IAAI,UAAU,KAAK,YAAY,OAAO,GAAG;QACrE,WAAW,qBAAqB,cAAc,SAAS,cAAc,SAAS,EAAE,CACnF,CAAC;IAEF,OAAO;QACL,SAAS;QACT,OAAO;QACP,QAAQ;QACR,cAAc,EAAE,MAAM;QACtB,MAAM;QACN,OAAO;QACP,SAAS;QACT,qBAAqB;QACrB,SAAS;QACT,MAAM;QACN,KAAK;KACN,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -34,7 +34,7 @@
34
34
  * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
35
35
  * and no operator has edited the row, so an unbumped edit ships to new installs
36
36
  * and never reaches existing ones — bump it in the same commit as the edit. */
37
- export declare const ROUTINE_TEMPLATE_VERSION = 3;
37
+ export declare const ROUTINE_TEMPLATE_VERSION = 4;
38
38
  /**
39
39
  * Task 2379 — the check shapes a shipped template may name.
40
40
  *
@@ -76,16 +76,6 @@ export type RoutineGateCheck = RoutineMailCheck | RoutineD1Check | RoutineWhatsa
76
76
  export interface RoutineGate {
77
77
  readonly checks: readonly RoutineGateCheck[];
78
78
  }
79
- /** Substituted by the seed with the full `scheduling-gate` argument object,
80
- * including the row's own event id.
81
- *
82
- * A template cannot write that id: it is minted by the MERGE. Nor can the turn
83
- * supply it, because the only place a scheduled turn sees its own event is the
84
- * provenance preamble, which carries the first eight characters. The watermark
85
- * file is named from the whole id, so a turn committing against the prefix
86
- * would write a file the next gate never reads and the routine would report
87
- * work for ever. */
88
- export declare const GATE_COMMIT_TOKEN = "<<gateCommit>>";
89
79
  /** True when the check compares against a stored position rather than reading a
90
80
  * current one.
91
81
  *
@@ -1 +1 @@
1
- {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CACtC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD;iDACiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB;iEACiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC9C;AAED;;;;;;;;qBAQqB;AACrB,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAElD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAGnE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;wEACoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;2CAIuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B;;;+DAG2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;2BAO2B;AAC3B,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAI/D;AAkKD;;;;;;;;iFAQiF;AACjF,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAsHpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}
1
+ {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CACtC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD;iDACiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,CAAC;AAEzB;iEACiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC9C;AAWD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAGnE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;wEACoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;2CAIuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B;;;+DAG2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;2BAO2B;AAC3B,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAI/D;AAgKD;;;;;;;;iFAQiF;AACjF,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAsHpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}
@@ -32,7 +32,7 @@
32
32
  * shipping a prompt that reaches for a tool no install serves.
33
33
  */
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = exports.GATE_COMMIT_TOKEN = exports.ROUTINE_TEMPLATE_VERSION = void 0;
35
+ exports.ROUTINE_ROSTER_KEYS = exports.ROUTINE_ROSTER = exports.ROUTINE_TEMPLATE_VERSION = void 0;
36
36
  exports.isWatermarkedCheck = isWatermarkedCheck;
37
37
  exports.gateNeedsCommit = gateNeedsCommit;
38
38
  exports.isClassified = isClassified;
@@ -40,17 +40,15 @@ exports.isClassified = isClassified;
40
40
  * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
41
41
  * and no operator has edited the row, so an unbumped edit ships to new installs
42
42
  * and never reaches existing ones — bump it in the same commit as the edit. */
43
- exports.ROUTINE_TEMPLATE_VERSION = 3;
44
- /** Substituted by the seed with the full `scheduling-gate` argument object,
45
- * including the row's own event id.
46
- *
47
- * A template cannot write that id: it is minted by the MERGE. Nor can the turn
48
- * supply it, because the only place a scheduled turn sees its own event is the
49
- * provenance preamble, which carries the first eight characters. The watermark
50
- * file is named from the whole id, so a turn committing against the prefix
51
- * would write a file the next gate never reads and the routine would report
52
- * work for ever. */
53
- exports.GATE_COMMIT_TOKEN = "<<gateCommit>>";
43
+ exports.ROUTINE_TEMPLATE_VERSION = 4;
44
+ // Task 2663 `GATE_COMMIT_TOKEN` is deleted. It stood in for a
45
+ // `scheduling-gate` call the routine's own turn made to advance its watermark,
46
+ // and the whole reason it had to be a token was that a template cannot write the
47
+ // event id the MERGE mints, while a turn only ever sees the first eight
48
+ // characters of it. That hazard is gone with the commit: the platform advances
49
+ // the mark itself, from the dispatcher, which holds the whole id by
50
+ // construction. A prompt that still contains the literal token is harmless prose
51
+ // naming a tool argument that no longer exists.
54
52
  /** True when the check compares against a stored position rather than reading a
55
53
  * current one.
56
54
  *
@@ -151,9 +149,7 @@ An appointment on the provider calendar with no counterpart in the graph is invi
151
149
 
152
150
  If the account has a busy-time sync configured, run schedule-connector-busy-sync so availability reflects what was just reconciled.
153
151
 
154
- Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.
155
-
156
- When the run has finished and nothing failed, call scheduling-gate with <<gateCommit>> so the next run does not re-examine what you have just reconciled. Do not call it after a run that failed or that you stopped early: the work would be marked as handled without anyone having seen it.`;
152
+ Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.`;
157
153
  const CONTACT_RECONCILE = `Reconcile the people the business actually deals with against the people it has recorded.
158
154
 
159
155
  Call capabilities-here first. If neither a mail plugin nor the contacts plugin is enabled, end the turn without replying.
@@ -1 +1 @@
1
- {"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
@@ -384,9 +384,14 @@ describe("gate seeding", () => {
384
384
  }
385
385
  });
386
386
 
387
- it("substitutes the commit token with the same eventId and checks", () => {
388
- expect(gateBlock()).toContain("replace(e.agentPrompt, '<<gateCommit>>'");
389
- expect(gateBlock()).toContain(`,"commit":true}'`);
387
+ it("writes no commit into any prompt (Task 2663)", () => {
388
+ // The seed used to expand `<<gateCommit>>` into a full argument object so the
389
+ // turn could advance its own watermark. The platform does that now, from the
390
+ // dispatcher, so the seed touching `agentPrompt` at all would only reinstate
391
+ // the writer this task removed.
392
+ expect(gateBlock()).not.toContain("gateCommit");
393
+ expect(gateBlock()).not.toContain('"commit":true');
394
+ expect(gateBlock()).not.toContain("e.agentPrompt");
390
395
  });
391
396
 
392
397
  it("passes serialised checks for a gated row and null for a gateless one", async () => {
@@ -44,10 +44,6 @@ export {
44
44
  ROUTINE_TEMPLATE_VERSION,
45
45
  isWatermarkedCheck,
46
46
  gateNeedsCommit,
47
- // Task 2634 — the scheduling plugin's write-time guard accepts a prompt that
48
- // carries this token, so the token has to be reachable from the package's own
49
- // entry point rather than only from the roster the seed reads.
50
- GATE_COMMIT_TOKEN,
51
47
  } from "./roster.js";
52
48
  export type { RoutineTemplate, RoutineGate, RoutineGateCheck } from "./roster.js";
53
49
 
@@ -234,10 +230,7 @@ MERGE (e:Event {accountId: $accountId, routineTemplate: row.key})
234
230
  WITH row, e, existed, priorVersion, edited, (NOT existed OR refreshing) AS writing
235
231
  SET e.gatePlugin = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling' END) ELSE e.gatePlugin END,
236
232
  e.gateTool = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE 'scheduling-gate' END) ELSE e.gateTool END,
237
- e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END,
238
- e.agentPrompt = CASE WHEN writing AND row.gateChecks IS NOT NULL
239
- THEN replace(e.agentPrompt, '<<gateCommit>>', '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + ',"commit":true}')
240
- ELSE e.agentPrompt END
233
+ e.gateArgs = CASE WHEN writing THEN (CASE WHEN row.gateChecks IS NULL THEN null ELSE '{"eventId":"' + e.eventId + '","checks":' + row.gateChecks + '}' END) ELSE e.gateArgs END
241
234
  RETURN row.key AS key,
242
235
  e.eventId AS eventId,
243
236
  CASE WHEN NOT existed THEN 'create'
@@ -35,7 +35,7 @@
35
35
  * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
36
36
  * and no operator has edited the row, so an unbumped edit ships to new installs
37
37
  * and never reaches existing ones — bump it in the same commit as the edit. */
38
- export const ROUTINE_TEMPLATE_VERSION = 3;
38
+ export const ROUTINE_TEMPLATE_VERSION = 4;
39
39
 
40
40
  /**
41
41
  * Task 2379 — the check shapes a shipped template may name.
@@ -85,16 +85,14 @@ export interface RoutineGate {
85
85
  readonly checks: readonly RoutineGateCheck[];
86
86
  }
87
87
 
88
- /** Substituted by the seed with the full `scheduling-gate` argument object,
89
- * including the row's own event id.
90
- *
91
- * A template cannot write that id: it is minted by the MERGE. Nor can the turn
92
- * supply it, because the only place a scheduled turn sees its own event is the
93
- * provenance preamble, which carries the first eight characters. The watermark
94
- * file is named from the whole id, so a turn committing against the prefix
95
- * would write a file the next gate never reads and the routine would report
96
- * work for ever. */
97
- export const GATE_COMMIT_TOKEN = "<<gateCommit>>";
88
+ // Task 2663 `GATE_COMMIT_TOKEN` is deleted. It stood in for a
89
+ // `scheduling-gate` call the routine's own turn made to advance its watermark,
90
+ // and the whole reason it had to be a token was that a template cannot write the
91
+ // event id the MERGE mints, while a turn only ever sees the first eight
92
+ // characters of it. That hazard is gone with the commit: the platform advances
93
+ // the mark itself, from the dispatcher, which holds the whole id by
94
+ // construction. A prompt that still contains the literal token is harmless prose
95
+ // naming a tool argument that no longer exists.
98
96
 
99
97
  /** True when the check compares against a stored position rather than reading a
100
98
  * current one.
@@ -233,9 +231,7 @@ An appointment on the provider calendar with no counterpart in the graph is invi
233
231
 
234
232
  If the account has a busy-time sync configured, run schedule-connector-busy-sync so availability reflects what was just reconciled.
235
233
 
236
- Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.
237
-
238
- When the run has finished and nothing failed, call scheduling-gate with <<gateCommit>> so the next run does not re-examine what you have just reconciled. Do not call it after a run that failed or that you stopped early: the work would be marked as handled without anyone having seen it.`;
234
+ Reply only when something was actually changed, naming what and why. A clean reconcile ends the turn without replying, every time. This routine runs often, so a message on every clean run trains the operator to ignore it.`;
239
235
 
240
236
  const CONTACT_RECONCILE = `Reconcile the people the business actually deals with against the people it has recorded.
241
237
 
@@ -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:f5ee0e74131f99f1dc825cde6cde89a84f854b578f81d1f65d16df58e89b352e
4
+ content-hash: sha256:fb655268fc14f30d5f01bea4a96c8b69a330d1651cc54ced5ba07850209426c8
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -2969,6 +2969,8 @@ Ask Maxy: "What messages has the bot received?" or "Show recent Telegram activit
2969
2969
 
2970
2970
  **Messages not arriving:** Make sure the bot hasn't been blocked. Try sending `/start` to the bot directly.
2971
2971
 
2972
+ **A scheduled routine never reaches you on Telegram:** Your numeric ID being on more than one account's admin list is fine. The routine goes out on the bot belonging to the account that owns the routine. It is refused only when **two bots on that same account** both list you, because nothing in the routine says which of the two should carry it. Take yourself off one of them, or point the routine at an ID that only one bot lists.
2973
+
2972
2974
  ## Sending from the dashboard
2973
2975
 
2974
2976
  Open a Telegram conversation in the dashboard and you can type a reply straight
@@ -6309,9 +6311,11 @@ The final step in the retrieval pipeline is injecting retrieved content into the
6309
6311
 
6310
6312
  ### Channel spawn routing by role
6311
6313
 
6312
- The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, and the one-shot admin jobs), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, the zero-tool public surface), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
6314
+ The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, the one-shot admin jobs, and every public Telegram bot), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, whose public surface is empty), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
6315
+
6316
+ **What a public spawn holds.** On WhatsApp and webchat, nothing. On Telegram, four message tools and nothing else: `telegram-card`, `telegram-ask`, `telegram-media-send` and `telegram-media-fetch`, granted on `/rc-spawn` when the spawn carries a bot and chat to pin them to. The bot and the chat come from the spawn, never from the turn, so a visitor's message cannot steer a send into another person's conversation or act as another bot on the account.
6313
6317
 
6314
- **A public spawn may not name a specialist.** The zero-tool surface is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` — which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
6318
+ **A public spawn may not name a specialist.** The ringfence is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` — which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
6315
6319
 
6316
6320
  The channel PTY-bridge (`ensureEntry`) routes each inbound by role: an **admin** WhatsApp/Telegram inbound spawns on `/rc-spawn` (keyed by a deterministic per-sender sessionId so the thread resumes across restarts) and drives every turn via `/<id>/input`; a **non-admin** inbound spawns on `/public-spawn`. Each dispatch logs `[<channel>-adaptor] route role=<role> target=<rc-spawn|public-spawn> senderId=…`. LinkedIn ingest and the public session-end review also run on `/rc-spawn`, carrying their prompt as `initialMessage` with `closeAfterTurn` so the PTY stops after one assistant turn.
6317
6321
 
@@ -9,6 +9,16 @@ Invoked by the admin agent directly.
9
9
 
10
10
  This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
11
11
 
12
+ ## 2026-08-11 (0.1.593)
13
+
14
+ - A public Telegram bot can now use buttons, media and the rest of the channel. It held no tool at all, so every answer it gave was plain text.
15
+ - A scheduled Telegram routine is no longer refused for an ambiguity its own account already settles: it was being turned away over which bot to use when only one was possible.
16
+ - Two faults in the record of how far a check has read, both of which lost the position without saying so. A damaged file silently reset every position and the next accepted wake wrote over it, so the evidence disappeared with the fault; and a file holding a list rather than a set of entries passed the validity check and was then emptied on the next advance.
17
+
18
+ ## 2026-08-10 (0.1.592)
19
+
20
+ - A routine that has nothing to do now stops waking the assistant. The record of how far a check had already read was written by the assistant itself, so if it finished a turn without noting that it had looked, the routine woke again on the next tick and kept doing so. The platform now moves that marker itself once a wake is accepted, and a standing check reports a marker that has stopped moving.
21
+
12
22
  ## 2026-08-10 (0.1.591)
13
23
 
14
24
  - A routine that watches Telegram can now be pointed at one bot. Before, it watched every bot on the account, so a routine watching your booking bot also woke up for every message to any other bot beside it, did the work, and threw it away. Naming a bot that does not exist is now reported as a fault rather than quietly treated as "nothing to do".
@@ -357,9 +357,11 @@ The final step in the retrieval pipeline is injecting retrieved content into the
357
357
 
358
358
  ### Channel spawn routing by role
359
359
 
360
- The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, and the one-shot admin jobs), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, the zero-tool public surface), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
360
+ The manager exposes three named spawn routes: `/rc-spawn` (a live `claude --remote-control` PTY — the operator sidebar, the channel admin, the one-shot admin jobs, and every public Telegram bot), `/public-spawn` (the renamed `/spawn` — `spawnClaudeSession`, whose public surface is empty), and the `rc-daemon` it drives. No route named `/spawn` remains; a manager boot line `[spawn-routes] live=[rc-spawn,public-spawn]` asserts this.
361
361
 
362
- **A public spawn may not name a specialist.** The zero-tool surface is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
362
+ **What a public spawn holds.** On WhatsApp and webchat, nothing. On Telegram, four message tools and nothing else: `telegram-card`, `telegram-ask`, `telegram-media-send` and `telegram-media-fetch`, granted on `/rc-spawn` when the spawn carries a bot and chat to pin them to. The bot and the chat come from the spawn, never from the turn, so a visitor's message cannot steer a send into another person's conversation or act as another bot on the account.
363
+
364
+ **A public spawn may not name a specialist.** The ringfence is built from four levers, and two of them — the `--allowed-tools` push and the resolved permission mode — branch on whether the spawn is a specialist rather than on whether it is public, so a specialist named on a public spawn would skip the allowlist entirely and resolve the caller's mode instead of the fail-closed `dontAsk`. Only the per-spawn `permissions.deny` and `--strict-mcp-config` bind on the public role alone. Neither production issuer sends the pairing: the channel bridge is the only caller whose role can be public and it carries no specialist field, while the cookie-auth session wrapper is admin-only. So the pairing is refused rather than reshaped — `/public-spawn` answers `400 specialist-not-permitted-on-public`, and `spawnClaudeSession` refuses it again with `reason=public-specialist-refused` at the single chokepoint every spawn route passes through. Refusing rather than narrowing the levers is deliberate: a narrowed lever would leave a specialist running silently on a one-tool surface. Every spawn that reaches `spawnClaudeSession` — which is every `/public-spawn`, that route being its only caller — logs the three deciding inputs together as `[spawn-lockdown] role=<role> specialist=<name|none> permissionMode=<mode>`. A refusal at either layer logs `op=public-specialist-refused` instead, told apart by `site=`.
363
365
 
364
366
  The channel PTY-bridge (`ensureEntry`) routes each inbound by role: an **admin** WhatsApp/Telegram inbound spawns on `/rc-spawn` (keyed by a deterministic per-sender sessionId so the thread resumes across restarts) and drives every turn via `/<id>/input`; a **non-admin** inbound spawns on `/public-spawn`. Each dispatch logs `[<channel>-adaptor] route role=<role> target=<rc-spawn|public-spawn> senderId=…`. LinkedIn ingest and the public session-end review also run on `/rc-spawn`, carrying their prompt as `initialMessage` with `closeAfterTurn` so the PTY stops after one assistant turn.
365
367
 
@@ -146,6 +146,8 @@ Ask {{productName}}: "What messages has the bot received?" or "Show recent Teleg
146
146
 
147
147
  **Messages not arriving:** Make sure the bot hasn't been blocked. Try sending `/start` to the bot directly.
148
148
 
149
+ **A scheduled routine never reaches you on Telegram:** Your numeric ID being on more than one account's admin list is fine. The routine goes out on the bot belonging to the account that owns the routine. It is refused only when **two bots on that same account** both list you, because nothing in the routine says which of the two should carry it. Take yourself off one of them, or point the routine at an ID that only one bot lists.
150
+
149
151
  ## Sending from the dashboard
150
152
 
151
153
  Open a Telegram conversation in the dashboard and you can type a reply straight
@@ -330,7 +330,7 @@ Written as one model turn instead — "check whether it is signed yet and, if it
330
330
 
331
331
  **Gate check vocabulary.** A **`mail`** check answers whether a UID strictly above the stored watermark exists in the folder, optionally narrowed by `subjectPrefixes`. It is not "is there mail" — an empty answer on a full mailbox is the normal quiet state. The IMAP range `UID <n+1>:*` still yields the folder's last message when `n` is at or above the highest assigned UID (RFC 3501 §6.4.8), so the probe drops anything at or below the watermark before deciding; `[scheduling-gate] op=mail-probe … returned=<n> aboveWatermark=<n>` reports both counts, and `returned` exceeding `aboveWatermark` by exactly one is the steady state. A UIDVALIDITY change reports work, because the stored UID then names a different message. The watermark is keyed `<mailbox>|<folder>` with the folder lower-cased, because `INBOX` is case-insensitive by RFC 3501 §5.1: a binding that writes `"folder": "inbox"` and one that writes `"INBOX"` address one entry, so changing the case of an existing binding does not reset the position. The mailbox segment keeps its case, because a local part is case-sensitive. Keys already stored in mixed case fold on read, highest `uid` winning, and `[scheduling-gate] op=watermark-fold … kept=<key> droppedUid=<n>` names what the repair discarded.
332
332
 
333
- A **`telegram`** check answers whether any of the account's Telegram conversations holds an inbound message whose `createdAt` is strictly above the stored one. Inbound is `origin === 'inbound'`, so an agent reply or an operator-typed message never counts as work, and update rows (a transcription, an edit, a deletion) never do either — they patch a message that already arrived. The position is the store's own ISO `createdAt`, not Telegram's `telegramDate`: that field is absent from every row written before it was introduced, so a check reading it would report work for ever on a conversation of older rows. `inbound` is the only scope, because Telegram is a webhook and has no connection for a `status` twin to read, and a scope other than `inbound` is refused when the gate is written. An account with no inbound row at all reports no work and no position, so it appears in `op=commit skipped=` rather than advancing onto nothing.
333
+ A **`telegram`** check answers whether any of the account's Telegram conversations holds an inbound message whose `createdAt` is strictly above the stored one. Inbound is `origin === 'inbound'`, so an agent reply or an operator-typed message never counts as work, and update rows (a transcription, an edit, a deletion) never do either — they patch a message that already arrived. The position is the store's own ISO `createdAt`, not Telegram's `telegramDate`: that field is absent from every row written before it was introduced, so a check reading it would report work for ever on a conversation of older rows. `inbound` is the only scope, because Telegram is a webhook and has no connection for a `status` twin to read, and a scope other than `inbound` is refused when the gate is written. An account with no inbound row at all reports no work and no position, so it contributes no key to `observed` and nothing advances for it rather than advancing onto nothing.
334
334
 
335
335
  **Name `botId` to watch one bot.** Without it the check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it, and the turn then filters away work it was woken for. `botId` is the bot's numeric id as it appears in a conversation's `<botId>:<senderId>` key, never a bot token: a token is a credential and would land in the event's stored gate arguments and in every log line that prints them. An id the account does not hold is **refused by the probe and counts as work**, never as quiet — a gate that can never fire is the failure that loses a booking, and it would leave no error anywhere. Each scope keeps its own position, so narrowing an existing gate to one bot starts that bot fresh rather than inheriting a mark taken across all of them.
336
336
 
@@ -338,15 +338,15 @@ A **`telegram`** check answers whether any of the account's Telegram conversatio
338
338
 
339
339
  **A check type outside that vocabulary is refused when the gate is written**, on create and on update, logging `[schedule-authoring] op=gate-refused … reason=unknown-check-type checks=<csv>`. Nothing inspected the type before this guard existed: such a gate stored cleanly, then threw inside the tool on every fire, and the dispatcher's fail-open spent a full model turn each time while `schedule-list` and `/routines` both read "gated". A row bound earlier now reports `[scheduling-gate] op=check-error kind=<type> treatedAs=has-work` instead of throwing out of the tool with no line at all.
340
340
 
341
- **The write proves the gate.** Every refusal above judges the gate's shape, and a gate naming a database that is not registered, a mailbox whose host does not resolve, or an account whose socket is down is well-formed and passes all of them. So the write runs the gate once, with `commit: false`, and refuses it when any check throws, quoting the source's own message — the `HTTP 403`, the `getaddrinfo EAI_AGAIN`, the `fetch failed`. `hasWork` is not judged: both answers are correct at bind time, and refusing on `true` would refuse every gate bound while work is pending. A source that breaks *after* a proven bind still wakes the model, unchanged, because fail-open at dispatch is deliberate. Acceptance leaves `[schedule-authoring] op=gate-accepted eventId=… route=probed checks=…` naming every kind the gate carries, and refusal leaves `op=gate-refused eventId=… reason=check-unreachable checks=…` naming only the kinds that failed. The probe carries no timeout, matching the fire.
341
+ **The write proves the gate.** Every refusal above judges the gate's shape, and a gate naming a database that is not registered, a mailbox whose host does not resolve, or an account whose socket is down is well-formed and passes all of them. So the write runs the gate once and refuses it when any check throws, quoting the source's own message — the `HTTP 403`, the `getaddrinfo EAI_AGAIN`, the `fetch failed`. `hasWork` is not judged: both answers are correct at bind time, and refusing on `true` would refuse every gate bound while work is pending. A source that breaks *after* a proven bind still wakes the model, unchanged, because fail-open at dispatch is deliberate. Acceptance leaves `[schedule-authoring] op=gate-accepted eventId=… route=probed checks=…` naming every kind the gate carries, and refusal leaves `op=gate-refused eventId=… reason=check-unreachable checks=…` naming only the kinds that failed. The probe carries no timeout, matching the fire.
342
342
 
343
- **Watermarked checks need a commit.** `mail`, `calendar`, `telegram`, and `whatsapp` in `inbound` scope compare against a stored position, so until something commits that position they report work on every fire and the gate saves nothing. A gate carrying one is refused on create **and** on update unless the commit is arranged by one of two routes. `d1` and `whatsapp` in `status` scope read a current value and need no commit. Because `d1` holds no position, its statement must count only the rows that arrived since the previous fire — a running total or `SELECT COALESCE(MAX(id),0)` can never reach zero, so the gate passes on every fire and saves nothing. A commit names every such check in `op=commit … skipped=`, and `[schedule-audit] op=gate-never-gates` reports any gate that has gated none of its last 24 fires. The commit writes the position the GATE read, recorded at gate time in a sibling `<eventId>.observed.json`, not the one its own probe reads at the end of the turn — otherwise a message arriving mid-turn lands below the new watermark and no later fire reports it. A commit issued with no gate call before it advances nothing, and `op=commit … positions=` names what each advanced check actually wrote.
343
+ **The platform advances the watermark, never the model.** `mail`, `calendar`, `telegram`, and `whatsapp` in `inbound` scope compare against a stored position. The dispatcher advances that position itself, immediately after the inject route accepts the wake it decided on, using the positions the gate returned in `observed`. A refused wake (`httpStatus` not 200) and a fail-open advance nothing, so work the model never received stays above the mark and the next fire reports it again. `d1` and `whatsapp` in `status` scope hold no position and nothing advances for them; because `d1` holds none, its statement must count only the rows that arrived since the previous fire — a running total or `SELECT COALESCE(MAX(id),0)` can never reach zero, so the gate passes on every fire and saves nothing.
344
344
 
345
- Route one, **the prompt commits**: the routine's prompt carries a `scheduling-gate` call whose arguments include `"commit":true` and this event's id, as its last step. Roster templates write `<<gateCommit>>` and the seed expands it into the full argument object with the row's id; a hand-written prompt writes that object out. Naming the tool in prose is not a commit: the guard reads the JSON key, not the tool name, so a prompt saying "do not call `scheduling-gate` yourself" is refused.
345
+ Nothing is asked of the routine's prompt. There is no `commit` parameter, no write-time refusal for a gate carrying a watermarked check, and a prompt naming the tool does nothing. An earlier design made the agent's own turn the only writer of the mark, and a model that forgot the call, or made it against the eight-character prefix of its event id, left the routine waking every minute against a source that had not moved.
346
346
 
347
- Route two, **a bound action event commits**: a separate scheduled action-mode event on the same account calls `scheduling-gate` with `commit: true` and this event's `eventId`. That advances the watermark with no model in the path, which is the better pattern where it fits, and the routine's own prompt then needs no commit line. Because the id only exists once the row does, this route is reachable from `schedule-update` and never from `schedule-event`: create the routine, bind the action event, then attach the gate.
347
+ The position written is the one the GATE read, carried back in the result rather than re-probed at advance time. A message arriving between the gate call and the advance therefore stays ABOVE the mark and the next fire reports it.
348
348
 
349
- Each decision leaves a line. `[schedule-authoring] op=gate-accepted eventId=… route=token|action-event checks=…` on acceptance, naming which route carried it, and `[schedule-authoring] op=gate-refused eventId=… reason=no-commit-route checks=…` before the throw. `eventId=-` on the create path, where the id is minted after the guard runs.
349
+ Three lines record it. `[schedule-gate] op=mark-advanced eventId=… advanced=… positions=…` per accepted wake, `op=mark-not-advanced eventId=… reason=no-observation|watermark-unreadable|write-failed` when nothing moved, and the standing `[schedule-audit] op=gate-mark-stalled acct=… count=… eventIds=[…]`, which names any gated event with three or more accepted wakes since its mark last moved. That last one is the check for the failure that emits nothing at all: a promote that runs, writes nothing, and leaves every surface reading normally. `op=gate-watermark-age` measures the same mark against the clock and so reads a weekly routine as stale; this one measures it against the routine's own wakes. A watermark file that exists and is not a watermark object is named by `[scheduling-gate] op=watermark-unreadable eventId=… reason=…` on every read of it, and is never overwritten, so its positions survive for an operator to look at; a missing file stays silent, because that is a first fire. `reason=` names the shape found: a body holding a JSON array reads `an array, not a watermark object`, because an array is an object to `typeof` and so passed the guard, was promoted into, and was then written back by `JSON.stringify` with every promoted position dropped.
350
350
 
351
351
  **Recurring only.** A one-time agent event is never gated — its row is already `due` by the time the dispatcher sees it, so a skip there would drop the routine for good — and it is therefore outside the refusal. `schedule-update` takes no waiver either: an existing routine keeps what it has until it is edited.
352
352
 
@@ -376,10 +376,9 @@ eagerTool(server, "schedule-update", "Update an event's properties or append a n
376
376
  // ---------------------------------------------------------------------------
377
377
  // scheduling-gate (Task 2378)
378
378
  // ---------------------------------------------------------------------------
379
- eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine: answers whether any of the named sources has new work, without running a turn. The dispatcher calls this headlessly before firing a gated routine and reads structuredContent.hasWork. Call it yourself with commit=true as the LAST step of a successful routine run, with the same eventId and checks, to advance the watermarks past what you just handled. Never call commit=true on a run that failed or that you did not finish the work would be marked consumed and the next fire would skip it.", {
379
+ eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine: answers whether any of the named sources has new work, without running a turn. The dispatcher calls this headlessly before firing a gated routine and reads structuredContent.hasWork. It writes nothing. The platform advances the watermarks itself, after the wake it decided on was accepted, so a routine's own turn never has to record what it handled and never can get it wrong.", {
380
380
  eventId: z.string().describe("The gated routine's event ID. Names the watermark file, so it must match the binding."),
381
- checks: z.array(z.record(z.unknown())).describe("Checks to run. mail {type,mailbox,folder?,subjectPrefixes?} · d1 {type,database,sql} · whatsapp {type,scope:'inbound'|'status'} · calendar {type,connector} · telegram {type,scope:'inbound',botId?}. Any other type, and any field not listed here, is refused when the gate is written. Name botId to watch ONE bot: without it a telegram check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it. A botId the account does not hold is refused by the probe and counts as work, never as quiet. hasWork is true when ANY check is true. A d1 statement must count only the rows that arrived since the previous fire: this check holds no stored position and a commit advances nothing for it, so a statement whose count cannot reach zero — a running total, or MAX(id) — makes the gate pass on every fire for ever."),
382
- commit: z.boolean().optional().describe("Advance every watermark named in checks to the position the gate call recorded before this turn started, not to what the sources hold now — 'now' is the end of your turn and already includes anything that arrived while it ran. Only the routine's own turn sets this, at the end of a successful run. A commit with no gate call before it advances nothing, which leaves the work above the watermark for the next fire."),
381
+ checks: z.array(z.record(z.unknown())).describe("Checks to run. mail {type,mailbox,folder?,subjectPrefixes?} · d1 {type,database,sql} · whatsapp {type,scope:'inbound'|'status'} · calendar {type,connector} · telegram {type,scope:'inbound',botId?}. Any other type, and any field not listed here, is refused when the gate is written. Name botId to watch ONE bot: without it a telegram check answers for every bot on the account, so a routine watching a booking bot also wakes for a relay bot beside it. A botId the account does not hold is refused by the probe and counts as work, never as quiet. hasWork is true when ANY check is true. A d1 statement must count only the rows that arrived since the previous fire: this check holds no stored position and nothing advances for it, so a statement whose count cannot reach zero — a running total, or MAX(id) — makes the gate pass on every fire for ever."),
383
382
  }, async (params) => {
384
383
  if (!accountId)
385
384
  return refuseNoAccount("scheduling-gate");
@@ -394,7 +393,7 @@ eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine
394
393
  };
395
394
  }
396
395
  try {
397
- const result = await runSchedulingGate({ eventId: params.eventId, checks: params.checks, commit: params.commit }, accountId, platformRoot);
396
+ const result = await runSchedulingGate({ eventId: params.eventId, checks: params.checks }, accountId, platformRoot);
398
397
  // structuredContent is what the dispatcher reads; the text is for a human
399
398
  // or an agent reading the transcript and is never parsed for control flow.
400
399
  // No outputSchema is declared: the MCP server validates structuredContent
@@ -404,14 +403,7 @@ eagerTool(server, "scheduling-gate", "Precondition check for a scheduled routine
404
403
  content: [
405
404
  {
406
405
  type: "text",
407
- // Task 2633 — `skipped` is rendered beside `advanced` because an
408
- // agent read `advanced: []` from a commit over four d1 checks and
409
- // inferred a broken watermark, when the true reason was that a d1
410
- // check holds no position at all.
411
- text: result.advanced
412
- ? `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}] ` +
413
- `advanced=[${result.advanced.join(", ")}] skipped=[${(result.skipped ?? []).join(", ")}]`
414
- : `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}]`,
406
+ text: `hasWork=${result.hasWork} reasons=[${result.reasons.join(", ")}]`,
415
407
  },
416
408
  ],
417
409
  structuredContent: result,