@rubytech/create-maxy-code 0.1.488 → 0.1.489

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 (90) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-22-task-1899-reconcile-report-only.md +748 -0
  3. package/payload/platform/docs/superpowers/specs/2026-07-22-task-1899-reconcile-report-only-design.md +121 -0
  4. package/payload/platform/lib/active-rules/package-lock.json +12 -0
  5. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js +51 -0
  6. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js.map +1 -1
  7. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts +2 -2
  8. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts.map +1 -1
  9. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js +20 -4
  10. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js.map +1 -1
  11. package/payload/platform/lib/graph-mcp/src/__tests__/schema-cypher-parser.test.ts +55 -0
  12. package/payload/platform/lib/graph-mcp/src/schema-cypher-parser.ts +19 -4
  13. package/payload/platform/lib/graph-style/dist/index.d.ts +24 -0
  14. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  15. package/payload/platform/lib/graph-style/dist/index.js +25 -1
  16. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  17. package/payload/platform/lib/graph-style/src/__tests__/additional-base-labels.test.ts +22 -0
  18. package/payload/platform/lib/graph-style/src/index.ts +27 -0
  19. package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js +15 -0
  20. package/payload/platform/lib/storage-broker/dist/__tests__/audit.test.js.map +1 -1
  21. package/payload/platform/lib/storage-broker/dist/audit.d.ts +5 -0
  22. package/payload/platform/lib/storage-broker/dist/audit.d.ts.map +1 -1
  23. package/payload/platform/lib/storage-broker/dist/audit.js +3 -2
  24. package/payload/platform/lib/storage-broker/dist/audit.js.map +1 -1
  25. package/payload/platform/lib/storage-broker/src/__tests__/audit.test.ts +21 -0
  26. package/payload/platform/lib/storage-broker/src/audit.ts +8 -2
  27. package/payload/platform/neo4j/schema.cypher +105 -0
  28. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +8 -2
  29. package/payload/platform/plugins/cloudflare/PLUGIN.md +22 -2
  30. package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +30 -8
  31. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-directory-listing.test.ts +75 -13
  32. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +77 -9
  33. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-indexed-download.test.ts +38 -2
  34. package/payload/platform/plugins/cloudflare/mcp/__tests__/template-config.test.ts +72 -0
  35. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +43 -7
  36. package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +22 -7
  37. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/download.ts +14 -2
  38. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/files.ts +23 -5
  39. package/payload/platform/plugins/cloudflare/skills/data-portal/template/index.html +3 -0
  40. package/payload/platform/plugins/cloudflare/skills/data-portal/template/portal.js +46 -5
  41. package/payload/platform/plugins/docs/references/calendar-booking.md +5 -1
  42. package/payload/platform/plugins/docs/references/internals.md +2 -0
  43. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +61 -31
  44. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -1
  45. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  46. package/payload/platform/plugins/scheduling/mcp/dist/index.js +2 -2
  47. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  48. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +70 -5
  49. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
  50. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js +31 -6
  51. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js.map +1 -1
  52. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +31 -4
  53. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
  54. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +18 -7
  55. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
  56. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts +15 -6
  57. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts.map +1 -1
  58. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js +24 -11
  59. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js.map +1 -1
  60. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +84 -5
  61. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  62. package/payload/platform/scripts/__tests__/quarantine-restore.test.sh +143 -0
  63. package/payload/platform/scripts/quarantine-restore.mjs +175 -0
  64. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +24 -7
  65. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  66. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +52 -74
  67. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  68. package/payload/platform/services/claude-session-manager/dist/index.js +11 -8
  69. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  70. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +32 -0
  71. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  72. package/payload/platform/services/whatsapp-channel/dist/notification.js +32 -2
  73. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  74. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts +6 -1
  75. package/payload/platform/services/whatsapp-channel/dist/targets.d.ts.map +1 -1
  76. package/payload/platform/services/whatsapp-channel/dist/targets.js +6 -0
  77. package/payload/platform/services/whatsapp-channel/dist/targets.js.map +1 -1
  78. package/payload/platform/templates/account-schema/SCHEMA.md +7 -4
  79. package/payload/server/{chunk-REWXLAPC.js → chunk-UFXRUKXO.js} +4 -2
  80. package/payload/server/public/assets/{admin-CThbXaYH.js → admin-DvQPTxqe.js} +1 -1
  81. package/payload/server/public/assets/{data-D5dp6nj6.js → data-Bu-5SUmR.js} +1 -1
  82. package/payload/server/public/assets/{graph-CNgt7ygi.js → graph-Cyh6FWaV.js} +1 -1
  83. package/payload/server/public/assets/graph-labels-CUQtXFKW.js +1 -0
  84. package/payload/server/public/assets/{page-Bvx0A2jB.js → page-Cno8NNMk.js} +1 -1
  85. package/payload/server/public/data.html +3 -3
  86. package/payload/server/public/graph.html +2 -2
  87. package/payload/server/public/index.html +3 -3
  88. package/payload/server/server.js +1032 -787
  89. package/payload/server/{src-JJ6PHO5I.js → src-YJF3UJNR.js} +1 -1
  90. package/payload/server/public/assets/graph-labels-DA48HrRR.js +0 -1
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env bash
2
+ # Tests the one-shot quarantine restore (Task 1899): a free target is moved back,
3
+ # an occupied target is skipped with both copies surviving, an already-restored
4
+ # entry reports absent, a malformed line reports unparsable, and --dry-run
5
+ # changes nothing on disk.
6
+ set -uo pipefail
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ RESTORE="$SCRIPT_DIR/../quarantine-restore.mjs"
9
+ PASS=0; FAIL=0; FAILED=()
10
+ assert_grep() { if printf '%s' "$2" | grep -qF "$1"; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$3: expected to find [$1]"); fi; }
11
+ assert_nogrep() { if printf '%s' "$2" | grep -qF "$1"; then FAIL=$((FAIL+1)); FAILED+=("$3: expected NOT to find [$1]"); else PASS=$((PASS+1)); fi; }
12
+ assert_file() { if [ -e "$1" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$2: expected file [$1]"); fi; }
13
+ assert_nofile() { if [ -e "$1" ]; then FAIL=$((FAIL+1)); FAILED+=("$2: expected NO file [$1]"); else PASS=$((PASS+1)); fi; }
14
+ assert_eq() { if [ "$1" = "$2" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); FAILED+=("$3: expected [$2] got [$1]"); fi; }
15
+
16
+ # One accounts root with a single account whose manifest covers all four cases.
17
+ make_tree() {
18
+ local T; T="$(mktemp -d)"
19
+ local A="$T/acct-1"
20
+ mkdir -p "$A/.quarantine"
21
+ printf '{}' > "$A/account.json"
22
+
23
+ # (a) free target: quarantined copy exists, nothing at the root.
24
+ printf 'portal' > "$A/.quarantine/data-portal.json"
25
+ # (b) occupied target: quarantined copy AND a live copy the platform rewrote.
26
+ printf 'old' > "$A/.quarantine/wa-channel-bindings.json"
27
+ printf 'live' > "$A/wa-channel-bindings.json"
28
+ # (c) already restored by hand: manifest names a source that is gone.
29
+ printf 'restored' > "$A/session-titles.json"
30
+
31
+ cat > "$A/.quarantine/manifest.jsonl" <<'EOF'
32
+ {"name":"data-portal.json","originalPath":"data-portal.json","reason":"top-level","quarantinePath":".quarantine/data-portal.json","movedAt":"2026-07-21T19:16:05.216Z"}
33
+ {"name":"session-titles.json","originalPath":"session-titles.json","reason":"top-level","quarantinePath":".quarantine/session-titles.json","movedAt":"2026-07-21T19:20:00.000Z"}
34
+ not json at all
35
+ {"name":"wa-channel-bindings.json","originalPath":"wa-channel-bindings.json","reason":"top-level","quarantinePath":".quarantine/wa-channel-bindings.json","movedAt":"2026-07-21T20:45:00.000Z"}
36
+ EOF
37
+ printf '%s' "$T"
38
+ }
39
+
40
+ # --- dry run changes nothing -------------------------------------------------
41
+ T="$(make_tree)"; A="$T/acct-1"
42
+ OUT="$(node "$RESTORE" --accounts-root "$T" --dry-run 2>&1)"
43
+ assert_grep 'result=moved' "$OUT" "dry-run reports the move it would make"
44
+ assert_grep 'dry-run=1' "$OUT" "dry-run marks its lines"
45
+ assert_nofile "$A/data-portal.json" "dry-run leaves the root untouched"
46
+ assert_file "$A/.quarantine/data-portal.json" "dry-run leaves the quarantined copy"
47
+ assert_nofile "$A/.quarantine/restored.jsonl" "dry-run writes no restored.jsonl"
48
+ rm -rf "$T"
49
+
50
+ # --- real run ----------------------------------------------------------------
51
+ T="$(make_tree)"; A="$T/acct-1"
52
+ OUT="$(node "$RESTORE" --accounts-root "$T" 2>&1)"
53
+
54
+ assert_grep 'op=restore account=acct-1 name=data-portal.json result=moved' "$OUT" "free target moved"
55
+ assert_file "$A/data-portal.json" "free target is back at the root"
56
+ assert_nofile "$A/.quarantine/data-portal.json" "free target no longer in quarantine"
57
+
58
+ assert_grep 'name=wa-channel-bindings.json result=skipped-live-copy' "$OUT" "occupied target skipped"
59
+ assert_grep 'live' "$(cat "$A/wa-channel-bindings.json")" "live copy still wins"
60
+ assert_file "$A/.quarantine/wa-channel-bindings.json" "quarantined copy survives the skip"
61
+
62
+ assert_grep 'name=session-titles.json result=absent' "$OUT" "already-restored source reports absent"
63
+ assert_grep 'restored' "$(cat "$A/session-titles.json")" "hand-restored copy untouched"
64
+
65
+ assert_grep 'line=3 result=unparsable' "$OUT" "malformed manifest line is reported"
66
+
67
+ assert_file "$A/.quarantine/manifest.jsonl" "manifest is left intact"
68
+ RESTORED="$(cat "$A/.quarantine/restored.jsonl")"
69
+ assert_grep 'data-portal.json' "$RESTORED" "restored.jsonl records the move"
70
+ assert_nogrep 'wa-channel-bindings.json' "$RESTORED" "restored.jsonl records only moves"
71
+ assert_nogrep 'session-titles.json' "$RESTORED" "restored.jsonl records only moves"
72
+ rm -rf "$T"
73
+
74
+ # --- a name quarantined twice restores the NEWEST copy ------------------------
75
+ # The sweep took wa-channel-bindings.json up to four times on one live account,
76
+ # the platform rewriting it between each. The deleted quarantineDest() took the
77
+ # unsuffixed name first and appended .1 to the next collision, so .1 IS the newer
78
+ # copy. Walking the append-only manifest oldest-first would put the stalest copy
79
+ # back, and the newer record would then find the target occupied.
80
+ T="$(mktemp -d)"; A="$T/acct-2"
81
+ mkdir -p "$A/.quarantine"
82
+ printf '{}' > "$A/account.json"
83
+ printf 'OLDER' > "$A/.quarantine/data-portal.json"
84
+ printf 'NEWER' > "$A/.quarantine/data-portal.json.1"
85
+ cat > "$A/.quarantine/manifest.jsonl" <<'EOF'
86
+ {"name":"data-portal.json","originalPath":"data-portal.json","quarantinePath":".quarantine/data-portal.json","movedAt":"2026-07-21T19:16:05.216Z"}
87
+ {"name":"data-portal.json","originalPath":"data-portal.json","quarantinePath":".quarantine/data-portal.json.1","movedAt":"2026-07-21T20:45:00.000Z"}
88
+ EOF
89
+ OUT="$(node "$RESTORE" --accounts-root "$T" 2>&1)"
90
+ assert_grep 'NEWER' "$(cat "$A/data-portal.json")" "newest quarantined copy is the one restored"
91
+ # The target was created by THIS run, not by a live platform rewrite. Calling it
92
+ # skipped-live-copy would tell the operator the platform holds a current copy.
93
+ assert_grep 'result=skipped-superseded' "$OUT" "the older copy is superseded, not live"
94
+ assert_nogrep 'result=skipped-live-copy' "$OUT" "no live copy existed on this tree"
95
+ assert_file "$A/.quarantine/data-portal.json" "the older copy is left in quarantine, never deleted"
96
+ rm -rf "$T"
97
+
98
+ # --- a record pointing outside its account is refused -------------------------
99
+ # .quarantine is in the write guard's allowed-top-level set, so an account-scoped
100
+ # agent can append to its own manifest. This script runs as the platform user
101
+ # across every account, so an escaping path would move one account's live data
102
+ # into another.
103
+ T="$(mktemp -d)"
104
+ mkdir -p "$T/acct-a/.quarantine" "$T/acct-b"
105
+ printf '{}' > "$T/acct-a/account.json"
106
+ printf '{}' > "$T/acct-b/account.json"
107
+ printf 'LIVE' > "$T/acct-b/wa-channel-bindings.json"
108
+ printf 'x' > "$T/acct-a/.quarantine/evil.json"
109
+ cat > "$T/acct-a/.quarantine/manifest.jsonl" <<'EOF'
110
+ {"name":"evil.json","originalPath":"../acct-b/planted.json","quarantinePath":".quarantine/evil.json"}
111
+ {"name":"steal","originalPath":"stolen.json","quarantinePath":"../acct-b/wa-channel-bindings.json"}
112
+ EOF
113
+ OUT="$(node "$RESTORE" --accounts-root "$T" 2>&1)"; RC=$?
114
+ assert_grep 'result=refused-outside-account' "$OUT" "escaping record is refused"
115
+ assert_grep 'refused=2' "$OUT" "both escaping records are counted"
116
+ assert_nofile "$T/acct-b/planted.json" "nothing is planted in the other account"
117
+ assert_nofile "$T/acct-a/stolen.json" "nothing is stolen from the other account"
118
+ assert_file "$T/acct-b/wa-channel-bindings.json" "the other account's live file is untouched"
119
+ assert_eq "$RC" "1" "a refused record makes the run exit non-zero"
120
+ rm -rf "$T"
121
+
122
+ # --- a failed rename reaches the summary and the exit code --------------------
123
+ # A restore that cannot complete leaves data in quarantine. The operator runs
124
+ # this once and reads the tail line, so a clean summary with a silent stderr
125
+ # line would be the same silent-skip failure this task exists to end.
126
+ T="$(mktemp -d)"; A="$T/acct-3"
127
+ mkdir -p "$A/.quarantine"
128
+ printf '{}' > "$A/account.json"
129
+ printf 'x' > "$A/.quarantine/orphan.json"
130
+ # The target's parent bucket no longer exists, so the target itself is absent
131
+ # (not a live copy) and the rename fails with ENOENT.
132
+ cat > "$A/.quarantine/manifest.jsonl" <<'EOF'
133
+ {"name":"orphan.json","originalPath":"gone-bucket/orphan.json","quarantinePath":".quarantine/orphan.json","movedAt":"2026-07-21T19:16:05.216Z"}
134
+ EOF
135
+ OUT="$(node "$RESTORE" --accounts-root "$T" 2>&1)"; RC=$?
136
+ assert_grep 'result=failed' "$OUT" "the failed rename is reported"
137
+ assert_grep 'failed=1' "$OUT" "the failure reaches the summary line"
138
+ assert_eq "$RC" "1" "a failed restore makes the run exit non-zero"
139
+ rm -rf "$T"
140
+
141
+ # --- summary -----------------------------------------------------------------
142
+ echo "PASS=$PASS FAIL=$FAIL"
143
+ if [ "$FAIL" -gt 0 ]; then printf '%s\n' "${FAILED[@]}"; exit 1; fi
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+ // Task 1899 — one-shot restore of everything the account-dir schema reconcile
3
+ // moved into <account>/.quarantine/ before it was made report-only. The sweep's
4
+ // allowed-list never matched what the platform and its agents write at an
5
+ // account root, so it took live features and live data dark with no error: the
6
+ // portal config, live signed agreements, the channel bindings.
7
+ //
8
+ // Per account it walks .quarantine/manifest.jsonl NEWEST-FIRST (the manifest is
9
+ // append-only, so that is reverse file order). Newest-first is what makes the
10
+ // occupied case correct for a name quarantined more than once: the most recent
11
+ // copy is considered first, and every older copy of that name then finds the
12
+ // target occupied. The live copy always wins, because the platform rewrote it
13
+ // after the move — four wa-channel-bindings.json records on one account prove
14
+ // that happened.
15
+ //
16
+ // Never deletes. The manifest is left intact so the history of what moved and
17
+ // what came back both survive.
18
+ //
19
+ // Usage: node quarantine-restore.mjs --accounts-root <dir> [--dry-run]
20
+
21
+ import { existsSync, readdirSync, readFileSync, renameSync, appendFileSync } from 'node:fs'
22
+ import { join, resolve, sep } from 'node:path'
23
+
24
+ const TAG = '[quarantine-restore]'
25
+ const QUARANTINE_DIR = '.quarantine'
26
+
27
+ /** True when `path` is `root` itself or lives underneath it. Both arguments must
28
+ * already be absolute. */
29
+ function isInside(root, path) {
30
+ return path === root || path.startsWith(root + sep)
31
+ }
32
+
33
+ function parseArgs(argv) {
34
+ let accountsRoot = null
35
+ let dryRun = false
36
+ for (let i = 0; i < argv.length; i++) {
37
+ if (argv[i] === '--accounts-root') {
38
+ accountsRoot = argv[i + 1] ?? null
39
+ i++
40
+ } else if (argv[i] === '--dry-run') {
41
+ dryRun = true
42
+ }
43
+ }
44
+ return { accountsRoot, dryRun }
45
+ }
46
+
47
+ const { accountsRoot, dryRun } = parseArgs(process.argv.slice(2))
48
+ if (!accountsRoot) {
49
+ console.error(`${TAG} usage: quarantine-restore.mjs --accounts-root <dir> [--dry-run]`)
50
+ process.exit(1)
51
+ }
52
+ if (!existsSync(accountsRoot)) {
53
+ console.error(`${TAG} accounts root not found: ${accountsRoot}`)
54
+ process.exit(1)
55
+ }
56
+
57
+ const suffix = dryRun ? ' dry-run=1' : ''
58
+ const totals = {
59
+ moved: 0,
60
+ 'skipped-live-copy': 0,
61
+ 'skipped-superseded': 0,
62
+ absent: 0,
63
+ unparsable: 0,
64
+ refused: 0,
65
+ failed: 0,
66
+ }
67
+ let accounts = 0
68
+
69
+ for (const entry of readdirSync(accountsRoot)) {
70
+ const accountDir = join(accountsRoot, entry)
71
+ const accountRoot = resolve(accountDir)
72
+ const quarantineRoot = resolve(accountDir, QUARANTINE_DIR)
73
+ const manifestPath = join(accountDir, QUARANTINE_DIR, 'manifest.jsonl')
74
+ if (!existsSync(manifestPath)) continue
75
+ accounts++
76
+
77
+ // Names this run put back at the account root. A later record naming one of
78
+ // them found the target occupied by THIS run, not by a live copy the platform
79
+ // rewrote — two different states that must not share one outcome label.
80
+ const restoredThisRun = new Set()
81
+
82
+ let lines
83
+ try {
84
+ lines = readFileSync(manifestPath, 'utf-8').split('\n')
85
+ } catch (err) {
86
+ totals.failed++
87
+ console.error(
88
+ `${TAG} op=restore account=${entry} result=manifest-unreadable error=${err.message}`,
89
+ )
90
+ continue
91
+ }
92
+
93
+ // Newest-first: the manifest is append-only, so walk it backwards. The 1-based
94
+ // file line number is carried so an unparsable line can be pointed at.
95
+ const numbered = lines.map((text, i) => ({ text, lineNo: i + 1 })).filter((l) => l.text.trim())
96
+ for (const { text, lineNo } of numbered.reverse()) {
97
+ let rec
98
+ try {
99
+ rec = JSON.parse(text)
100
+ } catch {
101
+ rec = null
102
+ }
103
+ if (!rec || typeof rec.originalPath !== 'string' || typeof rec.quarantinePath !== 'string') {
104
+ // Reported, never silently skipped: a line dropped without a word is the
105
+ // exact failure class this task exists to end.
106
+ totals.unparsable++
107
+ console.log(`${TAG} op=restore account=${entry} line=${lineNo} result=unparsable${suffix}`)
108
+ continue
109
+ }
110
+
111
+ const source = resolve(accountDir, rec.quarantinePath)
112
+ const target = resolve(accountDir, rec.originalPath)
113
+ const name = rec.originalPath
114
+
115
+ // The manifest is a file inside the account, and .quarantine is in the write
116
+ // guard's allowed-top-level set, so an account-scoped agent can append to it.
117
+ // This script runs as the platform user across every account, so a record
118
+ // whose paths escape the account would move one account's live data into
119
+ // another. Every record the reconcile ever wrote was a bare basename plus a
120
+ // path under .quarantine/, so this refuses nothing genuine.
121
+ if (!isInside(quarantineRoot, source) || !isInside(accountRoot, target)) {
122
+ totals.refused++
123
+ console.error(
124
+ `${TAG} op=restore account=${entry} line=${lineNo} result=refused-outside-account${suffix}`,
125
+ )
126
+ continue
127
+ }
128
+
129
+ if (!existsSync(source)) {
130
+ totals.absent++
131
+ console.log(`${TAG} op=restore account=${entry} name=${name} result=absent${suffix}`)
132
+ continue
133
+ }
134
+ if (existsSync(target) || restoredThisRun.has(target)) {
135
+ // A target this run created is superseded, not live. Calling both
136
+ // skipped-live-copy would tell the operator the platform holds a current
137
+ // copy when what is really left is an older copy still in quarantine.
138
+ const outcome = restoredThisRun.has(target) ? 'skipped-superseded' : 'skipped-live-copy'
139
+ totals[outcome]++
140
+ console.log(`${TAG} op=restore account=${entry} name=${name} result=${outcome}${suffix}`)
141
+ continue
142
+ }
143
+
144
+ if (dryRun) {
145
+ totals.moved++
146
+ restoredThisRun.add(target)
147
+ console.log(`${TAG} op=restore account=${entry} name=${name} result=moved${suffix}`)
148
+ continue
149
+ }
150
+ try {
151
+ renameSync(source, target)
152
+ appendFileSync(
153
+ join(accountDir, QUARANTINE_DIR, 'restored.jsonl'),
154
+ JSON.stringify({ ...rec, restoredAt: new Date().toISOString() }) + '\n',
155
+ )
156
+ totals.moved++
157
+ restoredThisRun.add(target)
158
+ console.log(`${TAG} op=restore account=${entry} name=${name} result=moved`)
159
+ } catch (err) {
160
+ totals.failed++
161
+ console.error(
162
+ `${TAG} op=restore account=${entry} name=${name} result=failed error=${err.message}`,
163
+ )
164
+ }
165
+ }
166
+ }
167
+
168
+ console.log(
169
+ `${TAG} accounts=${accounts} moved=${totals.moved} skipped-live-copy=${totals['skipped-live-copy']} skipped-superseded=${totals['skipped-superseded']} absent=${totals.absent} unparsable=${totals.unparsable} refused=${totals.refused} failed=${totals.failed}${suffix}`,
170
+ )
171
+
172
+ // A rename that failed, a manifest that would not open, and a record refused for
173
+ // pointing outside its account all leave data in quarantine. The operator runs
174
+ // this once and reads the tail line, so the exit code has to say so too.
175
+ if (totals.failed > 0 || totals.refused > 0) process.exitCode = 1
@@ -1,9 +1,17 @@
1
1
  export interface ReconcileCounts {
2
2
  strayTopLevel: number;
3
3
  overDeep: number;
4
- quarantined: number;
5
4
  badName: number;
6
5
  }
6
+ export interface ReconcileResult extends ReconcileCounts {
7
+ /** The account-root entries counted as strays, by name — the same set
8
+ * strayTopLevel counts, so PROTECTED_TOP_LEVEL entries and dot-prefixed
9
+ * entries are absent from it, and an account that failed the SCHEMA.md
10
+ * fail-open check returns it empty. A count alone cannot distinguish six
11
+ * pieces of debris from a live plugin config; this list is what makes the
12
+ * report-only posture actionable. */
13
+ strayNames: string[];
14
+ }
7
15
  /** The single per-run summary line body. A non-zero count is the standing signal
8
16
  * that an agent authored folders the hard guards could not prevent. Pure
9
17
  * formatter so the emitter and its test share one wording. */
@@ -14,18 +22,27 @@ export declare function formatReconcileLine(c: ReconcileCounts): string;
14
22
  export declare function parseAllowedTopLevel(schemaText: string): Set<string>;
15
23
  /** Reconcile one account dir. Reads its SCHEMA.md allowed set; an absent/empty
16
24
  * set skips the account (fail open, like the hook — an un-seeded legacy account
17
- * must not have its whole root quarantined). Moves stray top-level entries to
18
- * .quarantine/ with a manifest line; counts over-deep files without moving. */
19
- export declare function reconcileAccount(accountDir: string, now: () => number): ReconcileCounts;
25
+ * must not have its whole root reported as stray). Counts and names stray
26
+ * top-level entries; counts over-deep files and bad names. Moves nothing. */
27
+ export declare function reconcileAccount(accountDir: string): ReconcileResult;
20
28
  export interface ReconcileDeps {
21
29
  accountsRoot: string;
22
30
  logger: (line: string) => void;
23
- now?: () => number;
24
31
  }
25
- /** One reconcile pass over every account under the accounts root, then emit the
32
+ /** One reconcile pass over every account under the accounts root: one op=strays
33
+ * line naming the unaccounted-for entries of each account that has any, then the
26
34
  * single summary line. An account is any child dir with an account.json (the
27
35
  * account marker the census uses). Per-account errors are swallowed so one bad
28
- * account never aborts the run. */
36
+ * account never aborts the run.
37
+ *
38
+ * The op=strays line is the standing signal. When a feature that reads an
39
+ * account-root file goes dark, seeing that file named here says the schema does
40
+ * not account for it and it is still on disk, so declare it. The absence of its
41
+ * name reads as "gone" only for a file that could have been named at all: an
42
+ * entry in PROTECTED_TOP_LEVEL, a dot-prefixed entry, and every entry of an
43
+ * account whose SCHEMA.md is missing or has an empty allowed block are never
44
+ * named whether they are present or not. Check the account root itself before
45
+ * concluding a file is gone. */
29
46
  export declare function runReconcile(deps: ReconcileDeps): void;
30
47
  export interface AccountDirSchemaReconcile {
31
48
  start(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"account-dir-schema-reconcile.d.ts","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"AA2FA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;+DAE+D;AAC/D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED;;8EAE8E;AAC9E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAcpE;AA0FD;;;gFAGgF;AAChF,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,MAAM,GAAG,eAAe,CA6DvF;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED;;;oCAGoC;AACpC,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAwBtD;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb;AAED;oDACoD;AACpD,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,aAAa,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3C,yBAAyB,CAiB3B"}
1
+ {"version":3,"file":"account-dir-schema-reconcile.d.ts","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"AAqFA,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD;;;;;0CAKsC;IACtC,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;+DAE+D;AAC/D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED;;8EAE8E;AAC9E,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAcpE;AA+ED;;;8EAG8E;AAC9E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAoCpE;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B;AAED;;;;;;;;;;;;;iCAaiC;AACjC,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAyBtD;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb;AAED;oDACoD;AACpD,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,aAAa,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3C,yBAAyB,CAiB3B"}
@@ -11,43 +11,45 @@
11
11
  // the flat operator-data buckets, mirroring fs-schema-guard.sh's own depth rule
12
12
  // exactly (projects/contacts/documents cap at 3 path segments; every other
13
13
  // tool-owned bucket is unbounded and not walked), and (c) bad-named folders and
14
- // files under those same buckets, mirroring the guard's name convention. Stray
15
- // top-level entries are QUARANTINED (moved to <account>/.quarantine/ with a
16
- // manifest recording the original path, reason, and quarantine path so the move
17
- // is auditable and reversible); over-deep files and bad names are counted only.
18
- // Nothing is deleted, nothing is silently rewritten, and re-filing quarantined
19
- // content or renaming a bad name to its schema-correct home is the data-manager
20
- // specialist's job on dispatch, not this pass.
14
+ // files under those same buckets, mirroring the guard's name convention. All
15
+ // three are REPORTED, never moved: the pass used to quarantine stray top-level
16
+ // entries, and because its allowed-list lagged what the platform and its agents
17
+ // actually write at an account root, a mismatch on an entry something still read
18
+ // took that feature or that data dark with no error anywhere (Task 1899 — the
19
+ // portal config, live signed agreements and the channel bindings all went for
20
+ // exactly that reason). Nothing is moved, nothing is
21
+ // deleted, nothing is silently rewritten; re-filing a stray to its schema-correct
22
+ // home is the data-manager specialist's job on dispatch, not this pass.
21
23
  //
22
24
  // Shape mirrors the standing-audit family (rootless-client-audit.ts): a pure
23
25
  // formatter (unit-tested) + an impure per-account collector + a start/stop
24
26
  // factory whose setInterval is unref'd. Purely filesystem — no Neo4j, no graph
25
27
  // writes, no deletes. Best-effort by construction: a per-account error is caught
26
28
  // so one bad account never aborts the run.
27
- import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, appendFileSync, statSync, } from 'node:fs';
29
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
28
30
  import { join, relative, sep } from 'node:path';
29
31
  const TAG = '[fs-reconcile]';
30
32
  const QUARANTINE_DIR = '.quarantine';
31
- /** Platform control-plane entries the reconcile NEVER quarantines, regardless of
32
- * what an account's SCHEMA.md allowed set says. provision-account-dir.sh makes
33
+ /** Platform control-plane entries the reconcile NEVER counts as strays, regardless
34
+ * of what an account's SCHEMA.md allowed set says. provision-account-dir.sh makes
33
35
  * the account dir a git root (`.git`) and writes its hook-enforcement settings
34
- * into `.claude/`, and the account's identity lives in account.json; moving any
35
- * of these into .quarantine would brick the account (lost git root, disabled
36
- * hooks, unresolvable identity). SCHEMA.md is refreshed on every provision, but
37
- * an account carrying a stale/older-template/hand-edited schema whose allowed
38
- * block omits one of these must not have it moved. This is a fail-SAFE belt on
39
- * the control plane, the mirror of the guard's fail-OPEN on a missing schema —
40
- * operator strays are still quarantined; the account's own machinery is not.
36
+ * into `.claude/`, and the account's identity lives in account.json. SCHEMA.md is
37
+ * refreshed on every provision, but an account carrying a stale/older-template/
38
+ * hand-edited schema whose allowed block omits one of these must not be reported
39
+ * on every run for machinery it is required to have.
41
40
  *
42
41
  * The second group is platform-written control-plane FILES the platform reads
43
42
  * and writes at the account root every run. Unlike the tool-owned buckets, no
44
- * plugin declares them into the SCHEMA.md allowed-top-level block, so without
45
- * this belt the sweep quarantines them and the feature that reads each one goes
46
- * dark: calendar-availability.json is the booking page's availability config (a
47
- * quarantine froze a live booking page, Task 1877 fix); wa/webchat/telegram
48
- * -channel-bindings.json route each channel's inbound; canonical-webchat-session
49
- * .json pins the webchat session; session-titles.json holds operator renames.
50
- * Each is `join(accountDir, <name>)` in platform code, none is operator data. */
43
+ * plugin declares them into the SCHEMA.md allowed-top-level block: calendar-
44
+ * availability.json is the booking page's availability config (quarantining it
45
+ * froze a live booking page, Task 1877 fix); wa/webchat/telegram-channel-
46
+ * bindings.json route each channel's inbound; canonical-webchat-session.json
47
+ * pins the webchat session; session-titles.json holds operator renames. Each is
48
+ * `join(accountDir, <name>)` in platform code, none is operator data.
49
+ *
50
+ * Since Task 1899 this belt no longer protects anything from being moved,
51
+ * because nothing moves. It keeps the account's own machinery out of the stray
52
+ * count so the standing op=strays line names only what an operator must act on. */
51
53
  const PROTECTED_TOP_LEVEL = new Set([
52
54
  '.git',
53
55
  '.claude',
@@ -79,7 +81,7 @@ const FILE_NAME_RE = /^[a-z0-9-]+(\.[a-z0-9-]+)*$/;
79
81
  * that an agent authored folders the hard guards could not prevent. Pure
80
82
  * formatter so the emitter and its test share one wording. */
81
83
  export function formatReconcileLine(c) {
82
- return `${TAG} stray-top-level=${c.strayTopLevel} over-deep=${c.overDeep} quarantined=${c.quarantined} bad-name=${c.badName}`;
84
+ return `${TAG} stray-top-level=${c.strayTopLevel} over-deep=${c.overDeep} bad-name=${c.badName}`;
83
85
  }
84
86
  /** Parse the fenced ```allowed-top-level block from an account's SCHEMA.md —
85
87
  * the same structured set fs-schema-guard.sh parses with awk. Returns the
@@ -189,22 +191,12 @@ function countBadNameEntries(accountDir, bucket) {
189
191
  walk(bucketRoot);
190
192
  return count;
191
193
  }
192
- /** Pick a non-colliding destination name inside .quarantine for a stray. */
193
- function quarantineDest(quarantineRoot, name) {
194
- let candidate = join(quarantineRoot, name);
195
- let n = 1;
196
- while (existsSync(candidate)) {
197
- candidate = join(quarantineRoot, `${name}.${n}`);
198
- n++;
199
- }
200
- return candidate;
201
- }
202
194
  /** Reconcile one account dir. Reads its SCHEMA.md allowed set; an absent/empty
203
195
  * set skips the account (fail open, like the hook — an un-seeded legacy account
204
- * must not have its whole root quarantined). Moves stray top-level entries to
205
- * .quarantine/ with a manifest line; counts over-deep files without moving. */
206
- export function reconcileAccount(accountDir, now) {
207
- const empty = { strayTopLevel: 0, overDeep: 0, quarantined: 0, badName: 0 };
196
+ * must not have its whole root reported as stray). Counts and names stray
197
+ * top-level entries; counts over-deep files and bad names. Moves nothing. */
198
+ export function reconcileAccount(accountDir) {
199
+ const empty = { strayTopLevel: 0, overDeep: 0, badName: 0, strayNames: [] };
208
200
  const schemaPath = join(accountDir, 'SCHEMA.md');
209
201
  if (!existsSync(schemaPath))
210
202
  return empty;
@@ -226,50 +218,34 @@ export function reconcileAccount(accountDir, now) {
226
218
  }
227
219
  // A dot-prefixed top-level entry is tool/system state, never operator data —
228
220
  // the same judgement countBadNameEntries applies when it skips dotfiles. The
229
- // stray check must agree, or it quarantines .remember/.superpowers/.wrangler
230
- // and breaks the tool that owns each (Task 1891). .git/.claude/.quarantine
231
- // stay covered by PROTECTED_TOP_LEVEL regardless.
221
+ // stray check must agree, or it reports .remember/.superpowers/.wrangler on
222
+ // every run (Task 1891). .git/.claude/.quarantine stay covered by
223
+ // PROTECTED_TOP_LEVEL regardless.
232
224
  const strays = rootEntries.filter((name) => !name.startsWith('.') && !PROTECTED_TOP_LEVEL.has(name) && !allowed.has(name));
233
- let quarantined = 0;
234
- if (strays.length > 0) {
235
- const quarantineRoot = join(accountDir, QUARANTINE_DIR);
236
- const manifestPath = join(quarantineRoot, 'manifest.jsonl');
237
- for (const name of strays) {
238
- try {
239
- mkdirSync(quarantineRoot, { recursive: true });
240
- const dest = quarantineDest(quarantineRoot, name);
241
- renameSync(join(accountDir, name), dest);
242
- const record = {
243
- name,
244
- originalPath: name,
245
- reason: 'top-level',
246
- quarantinePath: relative(accountDir, dest),
247
- movedAt: new Date(now()).toISOString(),
248
- };
249
- appendFileSync(manifestPath, JSON.stringify(record) + '\n');
250
- quarantined++;
251
- }
252
- catch {
253
- // Move failed (permissions, race). Counted as a detected stray below,
254
- // not as quarantined — the summary line stays honest.
255
- }
256
- }
257
- }
258
225
  let overDeep = 0;
259
226
  let badName = 0;
260
227
  for (const bucket of DEPTH_CHECKED_BUCKETS) {
261
228
  overDeep += countOverDeepFiles(accountDir, bucket);
262
229
  badName += countBadNameEntries(accountDir, bucket);
263
230
  }
264
- return { strayTopLevel: strays.length, overDeep, quarantined, badName };
231
+ return { strayTopLevel: strays.length, overDeep, badName, strayNames: strays };
265
232
  }
266
- /** One reconcile pass over every account under the accounts root, then emit the
233
+ /** One reconcile pass over every account under the accounts root: one op=strays
234
+ * line naming the unaccounted-for entries of each account that has any, then the
267
235
  * single summary line. An account is any child dir with an account.json (the
268
236
  * account marker the census uses). Per-account errors are swallowed so one bad
269
- * account never aborts the run. */
237
+ * account never aborts the run.
238
+ *
239
+ * The op=strays line is the standing signal. When a feature that reads an
240
+ * account-root file goes dark, seeing that file named here says the schema does
241
+ * not account for it and it is still on disk, so declare it. The absence of its
242
+ * name reads as "gone" only for a file that could have been named at all: an
243
+ * entry in PROTECTED_TOP_LEVEL, a dot-prefixed entry, and every entry of an
244
+ * account whose SCHEMA.md is missing or has an empty allowed block are never
245
+ * named whether they are present or not. Check the account root itself before
246
+ * concluding a file is gone. */
270
247
  export function runReconcile(deps) {
271
- const now = deps.now ?? (() => Date.now());
272
- const total = { strayTopLevel: 0, overDeep: 0, quarantined: 0, badName: 0 };
248
+ const total = { strayTopLevel: 0, overDeep: 0, badName: 0 };
273
249
  let entries;
274
250
  try {
275
251
  entries = readdirSync(deps.accountsRoot);
@@ -283,10 +259,12 @@ export function runReconcile(deps) {
283
259
  if (!existsSync(join(accountDir, 'account.json')))
284
260
  continue;
285
261
  try {
286
- const c = reconcileAccount(accountDir, now);
262
+ const c = reconcileAccount(accountDir);
263
+ if (c.strayNames.length > 0) {
264
+ deps.logger(`${TAG} op=strays account=${entry} names=${c.strayNames.join(',')}`);
265
+ }
287
266
  total.strayTopLevel += c.strayTopLevel;
288
267
  total.overDeep += c.overDeep;
289
- total.quarantined += c.quarantined;
290
268
  total.badName += c.badName;
291
269
  }
292
270
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"account-dir-schema-reconcile.js","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-dir-schema-reconcile.js","sourceRoot":"","sources":["../src/account-dir-schema-reconcile.ts"],"names":[],"mappings":"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"}
@@ -794,14 +794,17 @@ async function main() {
794
794
  logger: log,
795
795
  });
796
796
  xacctCensus.start();
797
- // Task 1877 — standing account-dir schema reconcile. The fs-schema-guard path
798
- // hook never sees Bash, and the immediate Bash hooks only catch strays a live
799
- // command newly creates; neither retroactively catches the backlog an agent
800
- // authored before the hooks existed. Folder creation through Bash is a
801
- // no-event failure, so this periodic filesystem pass is the only signal: it
802
- // quarantines stray top-level entries into <account>/.quarantine/ (manifest
803
- // recorded, nothing deleted) and counts over-deep files, emitting one
804
- // [fs-reconcile] metric line per run. Purely filesystem — no Neo4j.
797
+ // Task 1877 / Task 1899 — standing account-dir schema reconcile. The
798
+ // fs-schema-guard path hook never sees Bash, and the immediate Bash hooks only
799
+ // catch strays a live command newly creates; neither retroactively catches the
800
+ // backlog an agent authored before the hooks existed. Folder creation through
801
+ // Bash is a no-event failure, so this periodic filesystem pass is the only
802
+ // signal. It REPORTS and never moves: each run emits one [fs-reconcile]
803
+ // op=strays line per account carrying entries the schema does not account for,
804
+ // naming them, then one [fs-reconcile] summary line counting those entries
805
+ // alongside over-deep files and bad names. It used to quarantine
806
+ // strays, and because a closed allowed-list always lags what the platform
807
+ // writes, that turned a metric into data loss. Purely filesystem — no Neo4j.
805
808
  const schemaReconcile = createAccountDirSchemaReconcile({
806
809
  accountsRoot: dirname(config.accountDir),
807
810
  logger: log,