@rubytech/create-maxy-code 0.1.476 → 0.1.478
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.
- package/package.json +1 -1
- package/payload/platform/docs/superpowers/plans/2026-07-20-task-1704-data-portal-standing-audit.md +673 -0
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1704-data-portal-standing-audit-design.md +177 -0
- package/payload/platform/docs/superpowers/specs/2026-07-20-task-1820-cpu-triage-admin-tools-design.md +97 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js +44 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.d.ts +56 -0
- package/payload/platform/lib/storage-broker/dist/audit.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/audit.js +34 -0
- package/payload/platform/lib/storage-broker/dist/audit.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/__tests__/audit.test.ts +70 -1
- package/payload/platform/lib/storage-broker/src/audit.ts +111 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +7 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +72 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.d.ts +94 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.js +229 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/cpu-triage.js.map +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/email/PLUGIN.md +2 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.js +92 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/confirm-sent-copy.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js +112 -12
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-send.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.js +54 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/email-send-sent-copy.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +170 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.js +86 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-note.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.js +164 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-copy-sweep.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.js +82 -0
- package/payload/platform/plugins/email/mcp/dist/__tests__/sent-ledger.test.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +95 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js +223 -0
- package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.d.ts +18 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.js +59 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-note.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.d.ts +48 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.js +79 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-copy-sweep.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.d.ts +44 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.js +63 -0
- package/payload/platform/plugins/email/mcp/dist/lib/sent-ledger.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.d.ts +2 -0
- package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.d.ts.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.js +55 -0
- package/payload/platform/plugins/email/mcp/dist/scripts/sent-copy-sweep.js.map +1 -0
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js +64 -13
- package/payload/platform/plugins/email/mcp/dist/tools/email-draft-send.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +11 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +16 -3
- package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -1
- package/payload/platform/plugins/email/references/email-reference.md +36 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.js +18 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/sent-sweep-throttle.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js +150 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js +248 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +90 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +105 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.d.ts +13 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.js +10 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/sent-sweep-throttle.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +53 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +88 -10
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
- package/payload/platform/scripts/cpu-triage-run.sh +117 -0
- package/payload/platform/scripts/cpu-triage.sh +332 -0
- package/payload/platform/services/claude-session-manager/dist/activity-range.d.ts +40 -0
- package/payload/platform/services/claude-session-manager/dist/activity-range.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/activity-range.js +68 -0
- package/payload/platform/services/claude-session-manager/dist/activity-range.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +40 -8
- package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js +74 -7
- package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +2 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +9 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/server/{chunk-56WJMBQQ.js → chunk-3XLLTG6R.js} +14 -0
- package/payload/server/{chunk-LBCMFD4O.js → chunk-XGNRSM57.js} +129 -37
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/activity.html +6 -6
- package/payload/server/public/assets/{AdminLoginScreens-DximwPlS.js → AdminLoginScreens-DR5eLF-a.js} +1 -1
- package/payload/server/public/assets/AdminShell-D9zaUxPd.js +2 -0
- package/payload/server/public/assets/{Checkbox-DM-eHqOS.js → Checkbox-DcbbAIe5.js} +1 -1
- package/payload/server/public/assets/activity-C9P5NjEZ.js +1 -0
- package/payload/server/public/assets/{admin-CAkDnGdk.js → admin-D2KLZnQW.js} +1 -1
- package/payload/server/public/assets/{browser-DXl8hOoi.js → browser-CDWqEiCD.js} +1 -1
- package/payload/server/public/assets/{calendar-DP6hn4-6.js → calendar-BG7fOpbB.js} +1 -1
- package/payload/server/public/assets/chat-RyH-WYQC.js +1 -0
- package/payload/server/public/assets/chevron-left-DmXCr6nB.js +1 -0
- package/payload/server/public/assets/data-BaY_LkLR.js +1 -0
- package/payload/server/public/assets/{graph-CHcYoEJ5.js → graph-DRloNic4.js} +1 -1
- package/payload/server/public/assets/{graph-labels-CZykslZM.js → graph-labels-DD-GqS4v.js} +1 -1
- package/payload/server/public/assets/{maximize-2-31AZEcMS.js → maximize-2-CzDaBugs.js} +1 -1
- package/payload/server/public/assets/{operator-BGGpdsO_.js → operator-BZeeyait.js} +1 -1
- package/payload/server/public/assets/{page-BloC6ygA.js → page-B0obcg3b.js} +1 -1
- package/payload/server/public/assets/{page-DOeiiqbR.js → page-ef-6rRPL.js} +1 -1
- package/payload/server/public/assets/{public-CGgO6IZv.js → public-9D3MMOkC.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BlAi6iFg.js → rotate-ccw-DXEKUhXP.js} +1 -1
- package/payload/server/public/assets/tasks-BB0L7e5a.js +1 -0
- package/payload/server/public/assets/{time-entry-format-CiUUQdq7.js → time-entry-format-CsYAjplS.js} +1 -1
- package/payload/server/public/assets/{triangle-alert-CVqKuLoa.js → triangle-alert-0lSBIUg-.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-ksyUe_g1.js → useCopyFeedback-jTBQ2h0V.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BPrBkdTd.js → useSelectionMode-BooArySZ.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-D9knHOKq.css +1 -0
- package/payload/server/public/assets/{useVoiceRecorder-CTXP8oTW.js → useVoiceRecorder-PUT8q_sm.js} +1 -1
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +6 -6
- package/payload/server/public/chat.html +12 -12
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +11 -11
- package/payload/server/public/index.html +14 -14
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +12 -12
- package/payload/server/public/tasks.html +5 -5
- package/payload/server/server.js +325 -77
- package/payload/server/{src-JYPKMWJR.js → src-XQ63FPRE.js} +3 -1
- package/payload/server/public/assets/AdminShell-BehbH-Oa.js +0 -2
- package/payload/server/public/assets/activity-hDwUeQd6.js +0 -1
- package/payload/server/public/assets/chat-DhOfVGYM.js +0 -1
- package/payload/server/public/assets/chevron-left-DYNBoLii.js +0 -1
- package/payload/server/public/assets/data-bq8fTo_s.js +0 -1
- package/payload/server/public/assets/tasks-C1giFRRL.js +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-K4kYeN6i.css +0 -1
- /package/payload/server/public/assets/{useSubAccountSwitcher-DzgzTRRn.js → useSubAccountSwitcher-BZnzc5C3.js} +0 -0
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Task 1811 — the block write path against a real SQLite database built from
|
|
2
|
+
// the calendar-site template's own schema.sql.
|
|
3
|
+
//
|
|
4
|
+
// The mutation check this suite exists for: a dispatcher that deletes all
|
|
5
|
+
// accepted rows passes the write and cleanup assertions and destroys every
|
|
6
|
+
// live booking. `realBookingsSurvive` is the assertion that catches it, and
|
|
7
|
+
// the "cannot reach a real booking" case runs the destructive statement
|
|
8
|
+
// explicitly to prove the guard is live rather than vacuous.
|
|
9
|
+
import { describe, it, expect } from "vitest";
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { promisify } from "node:util";
|
|
12
|
+
import { mkdtemp } from "node:fs/promises";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { resolve, dirname } from "node:path";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { BLOCK_ROWS_SELECT, BLOCK_ROW_INSERT, BLOCK_ROW_DELETE, ELIGIBLE_BOOKING_SELECT, blockInsertParams, diffBlockRows, selectBlockedSlots, } from "../booking-reconcile.js";
|
|
17
|
+
const run = promisify(execFile);
|
|
18
|
+
const TEMPLATE_SCHEMA = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../../cloudflare/skills/calendar-site/template/schema.sql");
|
|
19
|
+
const NOW_ISO = "2026-07-20T06:00:00.000Z";
|
|
20
|
+
const NOW = Date.parse(NOW_ISO);
|
|
21
|
+
const slot = (iso) => ({
|
|
22
|
+
start: iso,
|
|
23
|
+
end: new Date(Date.parse(iso) + 30 * 60_000).toISOString().replace(/\.\d{3}Z$/, ".000Z"),
|
|
24
|
+
});
|
|
25
|
+
/** A real SQLite database carrying the live maxy population: 24 genuine
|
|
26
|
+
* bookings, 1 admin block (kind='booking', deliberately not backfilled by
|
|
27
|
+
* 1806), and a published availability snapshot. */
|
|
28
|
+
async function db() {
|
|
29
|
+
const root = await mkdtemp(resolve(tmpdir(), "booking-block-"));
|
|
30
|
+
const path = resolve(root, "bookings.db");
|
|
31
|
+
await run("sqlite3", [path, `.read ${TEMPLATE_SCHEMA}`]);
|
|
32
|
+
const exec = async (sql, params = []) => {
|
|
33
|
+
// Positional ?1..?n, bound the way d1Query binds them.
|
|
34
|
+
let bound = sql;
|
|
35
|
+
params.forEach((v, i) => {
|
|
36
|
+
bound = bound.replace(new RegExp(`\\?${i + 1}\\b`, "g"), `'${v.replace(/'/g, "''")}'`);
|
|
37
|
+
});
|
|
38
|
+
try {
|
|
39
|
+
return (await run("sqlite3", [path, bound])).stdout.trim();
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
throw new Error(String(e.stderr ?? e.message).trim());
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const rows = [];
|
|
46
|
+
for (let i = 0; i < 24; i++) {
|
|
47
|
+
rows.push(`('josh-${i}','2026-07-2${i % 8}T14:00:00.000Z','2026-07-2${i % 8}T14:30:00.000Z','Josh Goff','josh@x.test','','accepted','booking','t')`);
|
|
48
|
+
}
|
|
49
|
+
rows.push(`('admin-0','2026-07-25T09:00:00.000Z','2026-07-25T09:30:00.000Z','Joel Smalley','joel@x.test','Blocked by admin','accepted','booking','t')`);
|
|
50
|
+
await exec(`INSERT INTO bookings (bookingId,slotStart,slotEnd,name,email,note,status,kind,createdAt) VALUES ${rows.join(",")};`);
|
|
51
|
+
await exec(`INSERT INTO availability_snapshot (id,payload,updatedAt) VALUES (1,'{"slots":[]}','${NOW_ISO}');`);
|
|
52
|
+
return { exec };
|
|
53
|
+
}
|
|
54
|
+
/** Read the held block rows the way the dispatcher does. */
|
|
55
|
+
async function heldBlocks(d) {
|
|
56
|
+
const out = await d.exec(`${BLOCK_ROWS_SELECT};`);
|
|
57
|
+
if (!out)
|
|
58
|
+
return [];
|
|
59
|
+
return out.split("\n").map((line) => {
|
|
60
|
+
const [bookingId, slotStart] = line.split("|");
|
|
61
|
+
return { bookingId, slotStart };
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** The invariant every case asserts: the 24 genuine bookings and the admin
|
|
65
|
+
* block are all still present and still eligible. */
|
|
66
|
+
async function realBookingsSurvive(d) {
|
|
67
|
+
const eligible = await d.exec(`${ELIGIBLE_BOOKING_SELECT};`);
|
|
68
|
+
const ids = eligible
|
|
69
|
+
.split("\n")
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.map((l) => l.split("|")[0]);
|
|
72
|
+
expect(ids).toHaveLength(25);
|
|
73
|
+
expect(ids).toContain("josh-0");
|
|
74
|
+
expect(ids).toContain("admin-0");
|
|
75
|
+
}
|
|
76
|
+
describe("block rows against the real template schema", () => {
|
|
77
|
+
it("writes a block row for each conflicting slot, and real bookings are untouched", async () => {
|
|
78
|
+
const d = await db();
|
|
79
|
+
const published = [slot("2026-07-21T09:30:00.000Z"), slot("2026-07-21T10:00:00.000Z")];
|
|
80
|
+
const busy = [{ start: "2026-07-21T09:30:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
81
|
+
const desired = selectBlockedSlots(published, busy, new Set(), NOW);
|
|
82
|
+
const diff = diffBlockRows(desired, await heldBlocks(d));
|
|
83
|
+
for (const s of diff.toInsert) {
|
|
84
|
+
await d.exec(BLOCK_ROW_INSERT + ";", blockInsertParams(s, `blk-${s.start}`, NOW_ISO));
|
|
85
|
+
}
|
|
86
|
+
const held = await heldBlocks(d);
|
|
87
|
+
expect(held.map((r) => r.slotStart).sort()).toEqual([
|
|
88
|
+
"2026-07-21T09:30:00.000Z",
|
|
89
|
+
"2026-07-21T10:00:00.000Z",
|
|
90
|
+
]);
|
|
91
|
+
// kind is what the sweep and audit qualify on — assert it landed as 'block'.
|
|
92
|
+
expect(await d.exec("SELECT DISTINCT kind FROM bookings WHERE bookingId LIKE 'blk-%';")).toBe("block");
|
|
93
|
+
await realBookingsSurvive(d);
|
|
94
|
+
});
|
|
95
|
+
it("removes a block row whose slot is no longer busy, and real bookings are untouched", async () => {
|
|
96
|
+
const d = await db();
|
|
97
|
+
await d.exec(BLOCK_ROW_INSERT + ";", blockInsertParams(slot("2026-07-21T09:30:00.000Z"), "blk-stale", NOW_ISO));
|
|
98
|
+
expect(await heldBlocks(d)).toHaveLength(1);
|
|
99
|
+
// The calendar cleared: the slot is published and no longer busy.
|
|
100
|
+
const desired = selectBlockedSlots([slot("2026-07-21T09:30:00.000Z")], [{ start: "2026-07-28T09:00:00.000Z", end: "2026-07-28T10:00:00.000Z" }], new Set(), NOW);
|
|
101
|
+
const diff = diffBlockRows(desired, await heldBlocks(d));
|
|
102
|
+
for (const id of diff.toDelete)
|
|
103
|
+
await d.exec(BLOCK_ROW_DELETE + ";", [id]);
|
|
104
|
+
expect(await heldBlocks(d)).toEqual([]);
|
|
105
|
+
await realBookingsSurvive(d);
|
|
106
|
+
});
|
|
107
|
+
it("converges to the same held set when run twice, writing nothing the second time", async () => {
|
|
108
|
+
const d = await db();
|
|
109
|
+
const published = [slot("2026-07-21T09:30:00.000Z")];
|
|
110
|
+
const busy = [{ start: "2026-07-21T09:00:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
111
|
+
for (const pass of [1, 2]) {
|
|
112
|
+
const desired = selectBlockedSlots(published, busy, new Set(), NOW);
|
|
113
|
+
const diff = diffBlockRows(desired, await heldBlocks(d));
|
|
114
|
+
if (pass === 2) {
|
|
115
|
+
expect(diff.toInsert).toEqual([]);
|
|
116
|
+
expect(diff.toDelete).toEqual([]);
|
|
117
|
+
}
|
|
118
|
+
for (const id of diff.toDelete)
|
|
119
|
+
await d.exec(BLOCK_ROW_DELETE + ";", [id]);
|
|
120
|
+
for (const s of diff.toInsert) {
|
|
121
|
+
await d.exec(BLOCK_ROW_INSERT + ";", blockInsertParams(s, `blk-${pass}`, NOW_ISO));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
expect(await heldBlocks(d)).toHaveLength(1);
|
|
125
|
+
await realBookingsSurvive(d);
|
|
126
|
+
});
|
|
127
|
+
it("the delete statement cannot reach a real booking even when handed its id", async () => {
|
|
128
|
+
// The mutation check, run as a live statement rather than asserted from
|
|
129
|
+
// the SQL text: without `AND kind='block'` this deletes a genuine booking.
|
|
130
|
+
const d = await db();
|
|
131
|
+
await d.exec(BLOCK_ROW_DELETE + ";", ["josh-0"]);
|
|
132
|
+
await d.exec(BLOCK_ROW_DELETE + ";", ["admin-0"]);
|
|
133
|
+
await realBookingsSurvive(d);
|
|
134
|
+
});
|
|
135
|
+
it("the availability snapshot is never touched by a blocking run", async () => {
|
|
136
|
+
const d = await db();
|
|
137
|
+
const before = await d.exec("SELECT payload, updatedAt FROM availability_snapshot WHERE id=1;");
|
|
138
|
+
await d.exec(BLOCK_ROW_INSERT + ";", blockInsertParams(slot("2026-07-21T09:30:00.000Z"), "blk-1", NOW_ISO));
|
|
139
|
+
await d.exec(BLOCK_ROW_DELETE + ";", ["blk-1"]);
|
|
140
|
+
expect(await d.exec("SELECT payload, updatedAt FROM availability_snapshot WHERE id=1;")).toBe(before);
|
|
141
|
+
});
|
|
142
|
+
it("a block row is excluded from the eligible population, so the sweep never reconciles it", async () => {
|
|
143
|
+
const d = await db();
|
|
144
|
+
await d.exec(BLOCK_ROW_INSERT + ";", blockInsertParams(slot("2026-07-21T09:30:00.000Z"), "blk-1", NOW_ISO));
|
|
145
|
+
const eligible = await d.exec(`${ELIGIBLE_BOOKING_SELECT};`);
|
|
146
|
+
expect(eligible).not.toContain("blk-1");
|
|
147
|
+
await realBookingsSurvive(d);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=booking-block-sqlite.test.js.map
|
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block-sqlite.test.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"booking-block-sqlite.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/booking-block-sqlite.test.ts"],"names":[],"mappings":"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"}
|
package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-block.test.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"booking-block.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/booking-block.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// Task 1811 — which published booking slots the connector-busy set blocks.
|
|
2
|
+
//
|
|
3
|
+
// The blocking key is the published slot's START STRING, not the busy
|
|
4
|
+
// interval: the edge free/busy Function subtracts taken slots with an exact
|
|
5
|
+
// `slotStart` string match, so a row keyed on a busy-interval boundary blocks
|
|
6
|
+
// nothing. These tests pin that the returned slots are drawn from `published`
|
|
7
|
+
// verbatim and never synthesised from `busy`.
|
|
8
|
+
import { describe, it, expect } from "vitest";
|
|
9
|
+
import { selectBlockedSlots, diffBlockRows, BLOCK_ROWS_SELECT, BLOCK_ROW_INSERT, BLOCK_ROW_DELETE, blockInsertParams, planBlockWrites, } from "../booking-reconcile.js";
|
|
10
|
+
const NOW = Date.parse("2026-07-20T00:00:00.000Z");
|
|
11
|
+
/** A half-hour published slot starting at `iso`. */
|
|
12
|
+
const slot = (iso) => ({
|
|
13
|
+
start: iso,
|
|
14
|
+
end: new Date(Date.parse(iso) + 30 * 60_000).toISOString().replace(/\.\d{3}Z$/, ".000Z"),
|
|
15
|
+
});
|
|
16
|
+
describe("selectBlockedSlots", () => {
|
|
17
|
+
it("blocks a published slot overlapping a busy interval, returning the published slot verbatim", () => {
|
|
18
|
+
const published = [slot("2026-07-21T09:30:00.000Z"), slot("2026-07-21T14:00:00.000Z")];
|
|
19
|
+
const busy = [{ start: "2026-07-21T09:30:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
20
|
+
const out = selectBlockedSlots(published, busy, new Set(), NOW);
|
|
21
|
+
expect(out).toEqual([published[0]]);
|
|
22
|
+
});
|
|
23
|
+
it("blocks every published slot the busy interval spans", () => {
|
|
24
|
+
// The live case: 'Billy Harrison — SiteDesk' 10:30-12:00 BST = 09:30-11:00Z
|
|
25
|
+
// covers the 09:30, 10:00 and 10:30 slots. gcal-sync.py blocked exactly these.
|
|
26
|
+
const published = [
|
|
27
|
+
slot("2026-07-21T09:30:00.000Z"),
|
|
28
|
+
slot("2026-07-21T10:00:00.000Z"),
|
|
29
|
+
slot("2026-07-21T10:30:00.000Z"),
|
|
30
|
+
slot("2026-07-21T11:00:00.000Z"),
|
|
31
|
+
];
|
|
32
|
+
const busy = [{ start: "2026-07-21T09:30:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
33
|
+
const out = selectBlockedSlots(published, busy, new Set(), NOW);
|
|
34
|
+
expect(out.map((s) => s.start)).toEqual([
|
|
35
|
+
"2026-07-21T09:30:00.000Z",
|
|
36
|
+
"2026-07-21T10:00:00.000Z",
|
|
37
|
+
"2026-07-21T10:30:00.000Z",
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
it("does not block an edge-touching slot", () => {
|
|
41
|
+
const published = [slot("2026-07-21T11:00:00.000Z")];
|
|
42
|
+
const busy = [{ start: "2026-07-21T09:30:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
43
|
+
expect(selectBlockedSlots(published, busy, new Set(), NOW)).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
it("skips a slot already taken by a real booking", () => {
|
|
46
|
+
const published = [slot("2026-07-21T09:30:00.000Z")];
|
|
47
|
+
const busy = [{ start: "2026-07-21T09:00:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
48
|
+
const taken = new Set(["2026-07-21T09:30:00.000Z"]);
|
|
49
|
+
expect(selectBlockedSlots(published, busy, taken, NOW)).toEqual([]);
|
|
50
|
+
});
|
|
51
|
+
it("skips a slot that has already started", () => {
|
|
52
|
+
const published = [slot("2026-07-19T09:30:00.000Z")];
|
|
53
|
+
const busy = [{ start: "2026-07-19T09:00:00.000Z", end: "2026-07-19T11:00:00.000Z" }];
|
|
54
|
+
expect(selectBlockedSlots(published, busy, new Set(), NOW)).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
it("blocks nothing when the busy set is empty", () => {
|
|
57
|
+
const published = [slot("2026-07-21T09:30:00.000Z")];
|
|
58
|
+
expect(selectBlockedSlots(published, [], new Set(), NOW)).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
it("never blocks on an unparseable bound", () => {
|
|
61
|
+
const published = [{ start: "not-a-date", end: "also-not" }];
|
|
62
|
+
const busy = [{ start: "2026-07-21T09:00:00.000Z", end: "2026-07-21T11:00:00.000Z" }];
|
|
63
|
+
expect(selectBlockedSlots(published, busy, new Set(), NOW)).toEqual([]);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe("diffBlockRows", () => {
|
|
67
|
+
it("inserts a desired slot with no row", () => {
|
|
68
|
+
const desired = [slot("2026-07-21T09:30:00.000Z")];
|
|
69
|
+
const d = diffBlockRows(desired, []);
|
|
70
|
+
expect(d.toInsert).toEqual(desired);
|
|
71
|
+
expect(d.toDelete).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
it("deletes a row whose slot is no longer busy", () => {
|
|
74
|
+
const current = [{ bookingId: "b-1", slotStart: "2026-07-21T09:30:00.000Z" }];
|
|
75
|
+
const d = diffBlockRows([], current);
|
|
76
|
+
expect(d.toInsert).toEqual([]);
|
|
77
|
+
expect(d.toDelete).toEqual(["b-1"]);
|
|
78
|
+
});
|
|
79
|
+
it("writes nothing when the held set already matches — the steady state", () => {
|
|
80
|
+
const desired = [slot("2026-07-21T09:30:00.000Z")];
|
|
81
|
+
const current = [{ bookingId: "b-1", slotStart: "2026-07-21T09:30:00.000Z" }];
|
|
82
|
+
const d = diffBlockRows(desired, current);
|
|
83
|
+
expect(d.toInsert).toEqual([]);
|
|
84
|
+
expect(d.toDelete).toEqual([]);
|
|
85
|
+
});
|
|
86
|
+
it("converges a duplicated row down to one", () => {
|
|
87
|
+
// Two rows for one slot can exist after an interrupted run. Keeping both
|
|
88
|
+
// would never converge, so the extra is deleted and one is retained.
|
|
89
|
+
const desired = [slot("2026-07-21T09:30:00.000Z")];
|
|
90
|
+
const current = [
|
|
91
|
+
{ bookingId: "b-1", slotStart: "2026-07-21T09:30:00.000Z" },
|
|
92
|
+
{ bookingId: "b-2", slotStart: "2026-07-21T09:30:00.000Z" },
|
|
93
|
+
];
|
|
94
|
+
const d = diffBlockRows(desired, current);
|
|
95
|
+
expect(d.toInsert).toEqual([]);
|
|
96
|
+
expect(d.toDelete).toEqual(["b-2"]);
|
|
97
|
+
});
|
|
98
|
+
it("handles a mixed add and remove in one pass", () => {
|
|
99
|
+
const desired = [slot("2026-07-22T09:30:00.000Z")];
|
|
100
|
+
const current = [{ bookingId: "b-old", slotStart: "2026-07-21T09:30:00.000Z" }];
|
|
101
|
+
const d = diffBlockRows(desired, current);
|
|
102
|
+
expect(d.toInsert.map((s) => s.start)).toEqual(["2026-07-22T09:30:00.000Z"]);
|
|
103
|
+
expect(d.toDelete).toEqual(["b-old"]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("block row statements", () => {
|
|
107
|
+
it("select and delete both qualify on kind, so neither can reach a real booking", () => {
|
|
108
|
+
expect(BLOCK_ROWS_SELECT).toContain("kind='block'");
|
|
109
|
+
expect(BLOCK_ROW_DELETE).toContain("kind='block'");
|
|
110
|
+
});
|
|
111
|
+
it("the insert binds every value and carries no free-text marker", () => {
|
|
112
|
+
expect(BLOCK_ROW_INSERT).toContain("?1");
|
|
113
|
+
expect(BLOCK_ROW_INSERT).not.toContain("Auto-block");
|
|
114
|
+
// The row must be `accepted` or the edge will not subtract it, and `block`
|
|
115
|
+
// or 1806's sweep would reconcile it into a meeting on the admin calendar.
|
|
116
|
+
expect(BLOCK_ROW_INSERT).toContain("'accepted'");
|
|
117
|
+
expect(BLOCK_ROW_INSERT).toContain("'block'");
|
|
118
|
+
});
|
|
119
|
+
it("insert params are positional and carry the published slot bounds verbatim", () => {
|
|
120
|
+
const s = slot("2026-07-21T09:30:00.000Z");
|
|
121
|
+
const p = blockInsertParams(s, "uuid-1", "2026-07-20T06:00:00.000Z");
|
|
122
|
+
expect(p[0]).toBe("uuid-1");
|
|
123
|
+
expect(p[1]).toBe(s.start);
|
|
124
|
+
expect(p[2]).toBe(s.end);
|
|
125
|
+
expect(p[p.length - 1]).toBe("2026-07-20T06:00:00.000Z");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("planBlockWrites — the safety gate", () => {
|
|
129
|
+
// Three rows already held. Every degraded outcome must leave all three
|
|
130
|
+
// alone: an unblocked busy slot is a double-booked customer, whereas a
|
|
131
|
+
// stale block is recoverable by the operator.
|
|
132
|
+
const held = [
|
|
133
|
+
{ bookingId: "b-1", slotStart: "2026-07-21T09:30:00.000Z" },
|
|
134
|
+
{ bookingId: "b-2", slotStart: "2026-07-21T10:00:00.000Z" },
|
|
135
|
+
{ bookingId: "b-3", slotStart: "2026-07-21T10:30:00.000Z" },
|
|
136
|
+
];
|
|
137
|
+
const base = {
|
|
138
|
+
publishedReadable: true,
|
|
139
|
+
busyReadable: true,
|
|
140
|
+
published: [slot("2026-07-21T09:30:00.000Z")],
|
|
141
|
+
busy: [{ start: "2026-07-21T09:00:00.000Z", end: "2026-07-21T11:00:00.000Z" }],
|
|
142
|
+
taken: new Set(),
|
|
143
|
+
current: held,
|
|
144
|
+
nowMs: NOW,
|
|
145
|
+
};
|
|
146
|
+
it("writes on verified", () => {
|
|
147
|
+
const p = planBlockWrites(base);
|
|
148
|
+
expect(p.outcome).toBe("verified");
|
|
149
|
+
// b-1 matches a still-busy slot and is kept; b-2 and b-3 are no longer
|
|
150
|
+
// desired, so this is also the convergence path.
|
|
151
|
+
expect(p.diff.toDelete).toEqual(["b-2", "b-3"]);
|
|
152
|
+
});
|
|
153
|
+
it("an EMPTY busy set deletes nothing — the rule a broken sync must not defeat", () => {
|
|
154
|
+
const p = planBlockWrites({ ...base, busy: [] });
|
|
155
|
+
expect(p.outcome).toBe("no-busy-data");
|
|
156
|
+
expect(p.diff).toEqual({ toInsert: [], toDelete: [] });
|
|
157
|
+
});
|
|
158
|
+
it("an UNPARSEABLE busy set deletes nothing — length alone is not liveness", () => {
|
|
159
|
+
// Without the usable-interval test this reaches `verified`, overlaps
|
|
160
|
+
// nothing, computes an empty desired set and deletes all three rows.
|
|
161
|
+
const p = planBlockWrites({
|
|
162
|
+
...base,
|
|
163
|
+
busy: [{ start: "not-a-date", end: "also-not" }, { start: "", end: "" }],
|
|
164
|
+
});
|
|
165
|
+
expect(p.outcome).toBe("no-busy-data");
|
|
166
|
+
expect(p.diff.toDelete).toEqual([]);
|
|
167
|
+
});
|
|
168
|
+
it("an inverted busy interval is not usable", () => {
|
|
169
|
+
const p = planBlockWrites({
|
|
170
|
+
...base,
|
|
171
|
+
busy: [{ start: "2026-07-21T11:00:00.000Z", end: "2026-07-21T09:00:00.000Z" }],
|
|
172
|
+
});
|
|
173
|
+
expect(p.outcome).toBe("no-busy-data");
|
|
174
|
+
expect(p.diff.toDelete).toEqual([]);
|
|
175
|
+
});
|
|
176
|
+
it("an unreadable snapshot deletes nothing", () => {
|
|
177
|
+
const p = planBlockWrites({ ...base, publishedReadable: false });
|
|
178
|
+
expect(p.outcome).toBe("snapshot-unreadable");
|
|
179
|
+
expect(p.diff.toDelete).toEqual([]);
|
|
180
|
+
});
|
|
181
|
+
it("an unreadable busy set reports error and deletes nothing", () => {
|
|
182
|
+
// The graph read threw. busy=[] here is absence of a measurement, not a
|
|
183
|
+
// measured empty set, so it must not read as `no-busy-data`.
|
|
184
|
+
const p = planBlockWrites({ ...base, busyReadable: false, busy: [] });
|
|
185
|
+
expect(p.outcome).toBe("error");
|
|
186
|
+
expect(p.diff.toDelete).toEqual([]);
|
|
187
|
+
});
|
|
188
|
+
it("a snapshot holding no slots deletes nothing", () => {
|
|
189
|
+
const p = planBlockWrites({ ...base, published: [] });
|
|
190
|
+
expect(p.outcome).toBe("no-published-slots");
|
|
191
|
+
expect(p.diff.toDelete).toEqual([]);
|
|
192
|
+
});
|
|
193
|
+
it("blocks a slot starting exactly now, matching what the edge still offers", () => {
|
|
194
|
+
// The edge serves `t >= lower` with lower = now, so this slot is offered.
|
|
195
|
+
const now = Date.parse("2026-07-21T09:30:00.000Z");
|
|
196
|
+
const p = planBlockWrites({ ...base, current: [], nowMs: now });
|
|
197
|
+
expect(p.diff.toInsert.map((s) => s.start)).toEqual(["2026-07-21T09:30:00.000Z"]);
|
|
198
|
+
});
|
|
199
|
+
it("excludes a published slot whose end is unparseable", () => {
|
|
200
|
+
const p = planBlockWrites({
|
|
201
|
+
...base,
|
|
202
|
+
current: [],
|
|
203
|
+
published: [{ start: "2026-07-21T09:30:00.000Z", end: "not-a-date" }],
|
|
204
|
+
});
|
|
205
|
+
expect(p.diff.toInsert).toEqual([]);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe("the op=cal-block line is emitted from exactly one place", () => {
|
|
209
|
+
// reconcileAccount resolves its config dir at module load and cannot be
|
|
210
|
+
// imported, so the emit-once property is not reachable by a behavioural
|
|
211
|
+
// test. It is pinned as a source invariant instead, mirroring the 1806
|
|
212
|
+
// check on the migration marker.
|
|
213
|
+
//
|
|
214
|
+
// The defect this guards: an earlier revision logged the error case from
|
|
215
|
+
// inside the catch and suppressed the summary line for `outcome=error`,
|
|
216
|
+
// so a tick whose drift step threw emitted NO cal-block line at all —
|
|
217
|
+
// the standing check silently absent, which is this task family's own
|
|
218
|
+
// defect class.
|
|
219
|
+
it("has one emit site, so no path can skip or double-report it", async () => {
|
|
220
|
+
const { readFileSync } = await import("node:fs");
|
|
221
|
+
const { resolve, dirname } = await import("node:path");
|
|
222
|
+
const { fileURLToPath } = await import("node:url");
|
|
223
|
+
const src = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../../scripts/reconcile-bookings.ts"), "utf-8");
|
|
224
|
+
const emits = src.match(/op=cal-block/g) ?? [];
|
|
225
|
+
expect(emits).toHaveLength(1);
|
|
226
|
+
// And it must be an unconditional statement. Walk back from the emit to
|
|
227
|
+
// the line opening the console.error call, then assert that line holds
|
|
228
|
+
// nothing but the call, and that the statement above it closes a block
|
|
229
|
+
// rather than opening a conditional.
|
|
230
|
+
const lines = src.split("\n");
|
|
231
|
+
const emitIdx = lines.findIndex((l) => l.includes("op=cal-block"));
|
|
232
|
+
expect(emitIdx).toBeGreaterThan(0);
|
|
233
|
+
let callIdx = emitIdx;
|
|
234
|
+
while (callIdx > 0 && !lines[callIdx].includes("console.error("))
|
|
235
|
+
callIdx--;
|
|
236
|
+
// ` console.error(` and nothing else — an `if (…) console.error(` or a
|
|
237
|
+
// `&&`/ternary prefix all fail here.
|
|
238
|
+
expect(lines[callIdx].trim()).toBe("console.error(");
|
|
239
|
+
// The nearest preceding code line must not open a conditional block.
|
|
240
|
+
let prevIdx = callIdx - 1;
|
|
241
|
+
while (prevIdx > 0 && (lines[prevIdx].trim() === "" || lines[prevIdx].trim().startsWith("//"))) {
|
|
242
|
+
prevIdx--;
|
|
243
|
+
}
|
|
244
|
+
expect(lines[prevIdx].trim()).not.toMatch(/^(if|else|\}\s*else)\b/);
|
|
245
|
+
expect(lines[prevIdx].trim()).toMatch(/^\}$/);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
//# sourceMappingURL=booking-block.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"booking-block.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/booking-block.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -127,4 +127,94 @@ export interface PublishedDrift {
|
|
|
127
127
|
* busy set is also empty: the site never publishing is the upstream condition.
|
|
128
128
|
*/
|
|
129
129
|
export declare function classifyPublishedDrift(published: BusyInterval[], busy: BusyInterval[]): PublishedDrift;
|
|
130
|
+
/** A slot as it appears in the published `availability_snapshot` payload. */
|
|
131
|
+
export interface PublishedSlot {
|
|
132
|
+
start: string;
|
|
133
|
+
end: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The published slots to block, given the connector-busy set.
|
|
137
|
+
*
|
|
138
|
+
* The returned slots are drawn from `published` verbatim, never synthesised
|
|
139
|
+
* from `busy`: the edge free/busy Function subtracts taken slots by an exact
|
|
140
|
+
* `slotStart` string match, so a block row keyed on a busy-interval boundary
|
|
141
|
+
* would block nothing.
|
|
142
|
+
*
|
|
143
|
+
* Two exclusions, both carried over from the out-of-tree script this replaces:
|
|
144
|
+
* a slot that has already started (the edge filters past slots anyway, so a
|
|
145
|
+
* row for one is inert churn), and a slot already taken by a real booking
|
|
146
|
+
* (already subtracted at the edge by that booking).
|
|
147
|
+
*/
|
|
148
|
+
export declare function selectBlockedSlots(published: PublishedSlot[], busy: BusyInterval[], taken: Set<string>, nowMs: number): PublishedSlot[];
|
|
149
|
+
/** A block row as held in D1. `bookingId` is the delete key. */
|
|
150
|
+
export interface BlockRow {
|
|
151
|
+
bookingId: string;
|
|
152
|
+
slotStart: string;
|
|
153
|
+
}
|
|
154
|
+
export interface BlockDiff {
|
|
155
|
+
toInsert: PublishedSlot[];
|
|
156
|
+
toDelete: string[];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Reconcile the held block rows to the desired set, keyed on slot start.
|
|
160
|
+
*
|
|
161
|
+
* This replaces the out-of-tree script's delete-and-reinsert. That form
|
|
162
|
+
* rewrote every row on every run and left a window in which a still-busy slot
|
|
163
|
+
* was unblocked; this one writes nothing in the steady state and never
|
|
164
|
+
* unblocks a slot that is staying blocked.
|
|
165
|
+
*
|
|
166
|
+
* A slot held by more than one row (possible after an interrupted run) keeps
|
|
167
|
+
* one and deletes the rest, so a duplicate converges instead of persisting.
|
|
168
|
+
*/
|
|
169
|
+
export declare function diffBlockRows(desired: PublishedSlot[], current: BlockRow[]): BlockDiff;
|
|
170
|
+
/** The block rows this dispatcher owns. `kind='block'` is the whole identity —
|
|
171
|
+
* no free-text marker is consulted, which is the defect Task 1811 removes. */
|
|
172
|
+
export declare const BLOCK_ROWS_SELECT = "SELECT bookingId, slotStart FROM bookings WHERE kind='block'";
|
|
173
|
+
/** `status='accepted'` so the edge free/busy Function subtracts the slot;
|
|
174
|
+
* `kind='block'` so 1806's sweep and audit both exclude it by construction. */
|
|
175
|
+
export declare const BLOCK_ROW_INSERT: string;
|
|
176
|
+
/** The `kind` qualifier is a safety belt, not a filter: even handed the id of a
|
|
177
|
+
* real booking this statement cannot delete it. */
|
|
178
|
+
export declare const BLOCK_ROW_DELETE = "DELETE FROM bookings WHERE bookingId=?1 AND kind='block'";
|
|
179
|
+
/** Positional parameters for BLOCK_ROW_INSERT. The slot bounds are copied from
|
|
180
|
+
* the published snapshot verbatim — the edge matches `slotStart` exactly. */
|
|
181
|
+
export declare function blockInsertParams(slot: PublishedSlot, bookingId: string, nowIso: string): string[];
|
|
182
|
+
/** The closed vocabulary of the `op=cal-block` outcome field. Deliberately the
|
|
183
|
+
* same tokens as `op=cal-drift` so an operator reads one vocabulary across the
|
|
184
|
+
* sibling lines. Typed so a mistyped literal fails the build. */
|
|
185
|
+
export type BlockOutcome = PublishedDriftOutcome | "snapshot-unreadable" | "error";
|
|
186
|
+
export interface BlockPlan {
|
|
187
|
+
outcome: BlockOutcome;
|
|
188
|
+
diff: BlockDiff;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Decide what the blocking step should write. Pure, so the safety rule below is
|
|
192
|
+
* testable without a live D1 or Neo4j — the rule is the highest-consequence
|
|
193
|
+
* line in this feature and was previously enforced only by an `if` at the call
|
|
194
|
+
* site that no test could reach.
|
|
195
|
+
*
|
|
196
|
+
* Writes happen ONLY on `verified`: the snapshot was read, it holds slots, and
|
|
197
|
+
* the busy set holds at least one usable interval. Every degraded outcome
|
|
198
|
+
* returns no writes, which means an absent or unreadable busy set RETAINS the
|
|
199
|
+
* rows already held rather than clearing them.
|
|
200
|
+
*
|
|
201
|
+
* That asymmetry is deliberate. An empty busy set is ambiguous between a
|
|
202
|
+
* genuinely clear calendar and a sync that failed, never ran, or was
|
|
203
|
+
* deauthorised — `syncConnectorBusy` writes an empty set on the documented
|
|
204
|
+
* deauthorise path. Over-blocking is recoverable by the operator; under-blocking
|
|
205
|
+
* double-books a customer against a real commitment. The retained rows are
|
|
206
|
+
* reported on the `op=cal-block` line so the condition is visible, not silent.
|
|
207
|
+
*/
|
|
208
|
+
export declare function planBlockWrites(input: {
|
|
209
|
+
/** False when the snapshot could not be read at all, as distinct from a
|
|
210
|
+
* snapshot that was read and holds no slots. */
|
|
211
|
+
publishedReadable: boolean;
|
|
212
|
+
/** False when the busy set could not be read at all (the graph read threw). */
|
|
213
|
+
busyReadable: boolean;
|
|
214
|
+
published: PublishedSlot[];
|
|
215
|
+
busy: BusyInterval[];
|
|
216
|
+
taken: Set<string>;
|
|
217
|
+
current: BlockRow[];
|
|
218
|
+
nowMs: number;
|
|
219
|
+
}): BlockPlan;
|
|
130
220
|
//# sourceMappingURL=booking-reconcile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-reconcile.d.ts","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAqD1B;AAMD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,yCAAyC,CAAC;AAEjF,gEAAgE;AAChE,eAAO,MAAM,uBAAuB,2IAC+F,CAAC;AAEpI;yDACyD;AACzD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMpG;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,IAAI,EAAE,CAAC,EAAE,EACT,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GACvB,CAAC,EAAE,CAEL;AAED,MAAM,WAAW,WAAW;IAC1B;;qFAEiF;IACjF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,WAAW,CAQrF;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,EAI5C,CAAC;AAEF;+CAC+C;AAC/C,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;4DAE4D;AAC5D,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE/D;AAMD;;qFAEqF;AACrF,eAAO,MAAM,qBAAqB,QAMmB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,aAAa,GAAG,qBAAqB,CAAC,CA4ChD;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAcD;;8DAE8D;AAC9D,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,cAAc,GAAG,oBAAoB,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,qBAAqB,CAAC;IAC/B,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb;gFAC4E;IAC5E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,cAAc,CAQtG"}
|
|
1
|
+
{"version":3,"file":"booking-reconcile.d.ts","sourceRoot":"","sources":["../../src/lib/booking-reconcile.ts"],"names":[],"mappings":"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"}
|