@rubytech/create-maxy 1.0.884 → 1.0.886

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.
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env bash
2
- # Task 671 — bash harness for logs-read.sh two-shape preflush resolution.
2
+ # Task 1006 — bash harness for logs-read.sh single-shape resolution.
3
3
  #
4
- # Covers the four cases from the task brief:
5
- # 1. Full-UUID file present → matched_shape=full
6
- # 2. Preflush file present, full absent matched_shape=preflush
7
- # 3. Neither present trailer lists both filenames, exit 1
8
- # 4. Both present (promotion race) → full wins + stale-preflush signal to server.log
4
+ # Covers the three cases the new contract demands:
5
+ # 1. sessionKey-named file present → bytes returned, exit 0.
6
+ # 2. No file exit 1 + missing-on-resolve appended to server.log.
7
+ # 3. Ambiguous prefix (multiple matches) exit 1, never picks silently.
9
8
  #
10
9
  # MIRROR: see platform/ui/app/lib/logs-read-resolve.ts for the canonical
11
- # two-shape contract and its TS unit tests.
10
+ # single-shape contract and its TS unit tests.
12
11
  set -euo pipefail
13
12
 
14
13
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -18,28 +17,17 @@ if [[ ! -x "$LOGS_READ" ]]; then
18
17
  exit 1
19
18
  fi
20
19
 
21
- CONV_ID="8c264cfb-441f-48bf-9811-9fa3ad3b51dc"
22
- PREFLUSH_SLICE="8c264cfb-441"
23
- FULL_NAME="claude-agent-stream-${CONV_ID}.log"
24
- PREFLUSH_NAME="claude-agent-stream-preflush-${PREFLUSH_SLICE}.log"
25
- # Task 998 — miss trailer now lists glob patterns, not literal filenames,
26
- # because Pass 1 / Pass 2 prefix-glob `${prefix}${conv_id}*.log`.
27
- FULL_GLOB="claude-agent-stream-${CONV_ID}*.log"
28
- PREFLUSH_GLOB="claude-agent-stream-preflush-${PREFLUSH_SLICE}*.log"
20
+ SESSION_KEY="8c264cfb-441f-48bf-9811-9fa3ad3b51dc"
21
+ FILE_NAME="claude-agent-stream-${SESSION_KEY}.log"
29
22
 
30
23
  PASS=0
31
24
  FAIL=0
32
25
 
33
- # logs-read.sh resolves PLATFORM_ROOT from the script location, and uses
34
- # INSTALL_DIR = $PLATFORM_ROOT/.. and ACCOUNTS_DIR = $INSTALL_DIR/data/accounts.
35
- # The test creates a fake install tree with the real script symlinked in.
36
26
  setup_install_tree() {
37
27
  local root="$1"
38
28
  mkdir -p "$root/platform/scripts"
39
29
  mkdir -p "$root/data/accounts/acct-test/logs"
40
30
  mkdir -p "$HOME/.$(basename "$root")/logs"
41
- # Symlink the script under test into the fake tree so PLATFORM_ROOT resolves
42
- # to $root/platform and the account logs are discovered.
43
31
  ln -sf "$LOGS_READ" "$root/platform/scripts/logs-read.sh"
44
32
  echo "$root/platform/scripts/logs-read.sh"
45
33
  }
@@ -50,8 +38,6 @@ cleanup_install_tree() {
50
38
  rm -rf "$HOME/.$(basename "$root")"
51
39
  }
52
40
 
53
- # Each case uses its own ephemeral install tree. Install-tree basename is
54
- # unique so configDir (~/.{installDir}) does not collide.
55
41
  run_case() {
56
42
  local name="$1"
57
43
  shift
@@ -66,16 +52,16 @@ run_case() {
66
52
  fi
67
53
  }
68
54
 
69
- # --- Case 1: full only ---
70
- case_full_only() {
55
+ # --- Case 1: sessionKey-named file present → exit 0 ---
56
+ case_file_present() {
71
57
  local root="/tmp/maxy-logs-read-test-1-$$"
72
58
  local script
73
59
  script=$(setup_install_tree "$root")
74
60
  local logdir="$root/data/accounts/acct-test/logs"
75
- echo "full-content-sentinel" > "$logdir/$FULL_NAME"
61
+ echo "sessionkey-content-sentinel" > "$logdir/$FILE_NAME"
76
62
 
77
63
  local stdout stderr rc
78
- stdout=$("$script" "$CONV_ID" system 2>/tmp/maxy-logs-read-stderr-1-$$) || rc=$?
64
+ stdout=$("$script" "$SESSION_KEY" system 2>/tmp/maxy-logs-read-stderr-1-$$) || rc=$?
79
65
  rc=${rc:-0}
80
66
  stderr=$(cat /tmp/maxy-logs-read-stderr-1-$$)
81
67
  rm -f /tmp/maxy-logs-read-stderr-1-$$
@@ -86,56 +72,66 @@ case_full_only() {
86
72
  echo " expected exit 0, got $rc"
87
73
  return 1
88
74
  fi
89
- if [[ "$stdout" != *"full-content-sentinel"* ]]; then
75
+ if [[ "$stdout" != *"sessionkey-content-sentinel"* ]]; then
90
76
  echo " stdout missing sentinel"
91
77
  return 1
92
78
  fi
93
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
94
- echo " stderr missing matched_shape=full: $stderr"
79
+ if [[ "$stderr" != *"matched=1"* ]]; then
80
+ echo " stderr missing matched=1: $stderr"
95
81
  return 1
96
82
  fi
97
83
  return 0
98
84
  }
99
85
 
100
- # --- Case 2: preflush only ---
101
- case_preflush_only() {
86
+ # --- Case 2: no file → exit 1 + missing-on-resolve in server.log ---
87
+ case_missing() {
102
88
  local root="/tmp/maxy-logs-read-test-2-$$"
103
89
  local script
104
90
  script=$(setup_install_tree "$root")
105
- local logdir="$root/data/accounts/acct-test/logs"
106
- echo "preflush-content-sentinel" > "$logdir/$PREFLUSH_NAME"
91
+ local server_log="$HOME/.$(basename "$root")/logs/server.log"
92
+ : > "$server_log"
107
93
 
108
- local stdout stderr rc
109
- stdout=$("$script" "$CONV_ID" system 2>/tmp/maxy-logs-read-stderr-2-$$) || rc=$?
110
- rc=${rc:-0}
94
+ local rc=0
95
+ "$script" "$SESSION_KEY" system >/dev/null 2>/tmp/maxy-logs-read-stderr-2-$$ || rc=$?
96
+ local stderr
111
97
  stderr=$(cat /tmp/maxy-logs-read-stderr-2-$$)
112
98
  rm -f /tmp/maxy-logs-read-stderr-2-$$
99
+ local server_log_contents
100
+ server_log_contents=$(cat "$server_log" 2>/dev/null || echo "")
113
101
 
114
102
  cleanup_install_tree "$root"
115
103
 
116
- if [[ $rc -ne 0 ]]; then
117
- echo " expected exit 0, got $rc"
104
+ if [[ $rc -ne 1 ]]; then
105
+ echo " expected exit 1, got $rc"
118
106
  return 1
119
107
  fi
120
- if [[ "$stdout" != *"preflush-content-sentinel"* ]]; then
121
- echo " stdout missing sentinel"
108
+ if [[ "$stderr" != *"reason=file-not-found"* ]]; then
109
+ echo " stderr missing reason=file-not-found: $stderr"
122
110
  return 1
123
111
  fi
124
- if [[ "$stderr" != *"matched_shape=preflush"* ]]; then
125
- echo " stderr missing matched_shape=preflush: $stderr"
112
+ if [[ "$server_log_contents" != *"missing-on-resolve"* ]]; then
113
+ echo " server.log missing missing-on-resolve emission: $server_log_contents"
114
+ return 1
115
+ fi
116
+ if [[ "$server_log_contents" != *"surface=logs-read-sh"* ]]; then
117
+ echo " server.log emission missing surface tag"
126
118
  return 1
127
119
  fi
128
120
  return 0
129
121
  }
130
122
 
131
- # --- Case 3: neither presentmiss trailer ---
132
- case_neither() {
123
+ # --- Case 3: ambiguous prefixexit 1 without picking ---
124
+ case_ambiguous() {
133
125
  local root="/tmp/maxy-logs-read-test-3-$$"
134
126
  local script
135
127
  script=$(setup_install_tree "$root")
128
+ local logdir="$root/data/accounts/acct-test/logs"
129
+ echo "a" > "$logdir/claude-agent-stream-deadbeef-aaaa.log"
130
+ echo "b" > "$logdir/claude-agent-stream-deadbeef-bbbb.log"
136
131
 
137
- local stdout stderr rc=0
138
- stdout=$("$script" "$CONV_ID" system 2>/tmp/maxy-logs-read-stderr-3-$$) || rc=$?
132
+ local rc=0
133
+ "$script" "deadbeef" system >/dev/null 2>/tmp/maxy-logs-read-stderr-3-$$ || rc=$?
134
+ local stderr
139
135
  stderr=$(cat /tmp/maxy-logs-read-stderr-3-$$)
140
136
  rm -f /tmp/maxy-logs-read-stderr-3-$$
141
137
 
@@ -145,69 +141,16 @@ case_neither() {
145
141
  echo " expected exit 1, got $rc"
146
142
  return 1
147
143
  fi
148
- if [[ "$stderr" != *"tried=[${FULL_GLOB}, ${PREFLUSH_GLOB}]"* ]]; then
149
- echo " stderr missing tried=[…,…] glob patterns: $stderr"
150
- return 1
151
- fi
152
- if [[ "$stderr" != *"reason=file-not-found-in-either-shape"* ]]; then
153
- echo " stderr missing reason=file-not-found-in-either-shape: $stderr"
154
- return 1
155
- fi
156
- return 0
157
- }
158
-
159
- # --- Case 4: both present (promotion race) → full wins + stale signal ---
160
- case_both_present() {
161
- local root="/tmp/maxy-logs-read-test-4-$$"
162
- local script
163
- script=$(setup_install_tree "$root")
164
- local logdir="$root/data/accounts/acct-test/logs"
165
- echo "full-content-sentinel-4" > "$logdir/$FULL_NAME"
166
- echo "preflush-content-sentinel-4" > "$logdir/$PREFLUSH_NAME"
167
- local server_log="$HOME/.$(basename "$root")/logs/server.log"
168
- : > "$server_log"
169
-
170
- local stdout stderr rc=0
171
- stdout=$("$script" "$CONV_ID" system 2>/tmp/maxy-logs-read-stderr-4-$$) || rc=$?
172
- stderr=$(cat /tmp/maxy-logs-read-stderr-4-$$)
173
- rm -f /tmp/maxy-logs-read-stderr-4-$$
174
-
175
- local server_log_contents
176
- server_log_contents=$(cat "$server_log" 2>/dev/null || echo "")
177
-
178
- cleanup_install_tree "$root"
179
-
180
- if [[ $rc -ne 0 ]]; then
181
- echo " expected exit 0, got $rc"
182
- return 1
183
- fi
184
- if [[ "$stdout" != *"full-content-sentinel-4"* ]]; then
185
- echo " stdout missing full sentinel (full must win): $stdout"
186
- return 1
187
- fi
188
- if [[ "$stdout" == *"preflush-content-sentinel-4"* ]]; then
189
- echo " stdout contained preflush sentinel — preflush must be ignored when full exists"
190
- return 1
191
- fi
192
- if [[ "$stderr" != *"matched_shape=full"* ]]; then
193
- echo " stderr missing matched_shape=full"
194
- return 1
195
- fi
196
- if [[ "$server_log_contents" != *"stale-preflush-detected"* ]]; then
197
- echo " server.log missing stale-preflush-detected signal: $server_log_contents"
198
- return 1
199
- fi
200
- if [[ "$server_log_contents" != *"$PREFLUSH_NAME"* ]]; then
201
- echo " server.log stale signal missing preflush path"
144
+ if [[ "$stderr" != *"reason=ambiguous-prefix"* ]]; then
145
+ echo " stderr missing ambiguous-prefix trailer: $stderr"
202
146
  return 1
203
147
  fi
204
148
  return 0
205
149
  }
206
150
 
207
- run_case "full onlymatched_shape=full" case_full_only
208
- run_case "preflush onlymatched_shape=preflush" case_preflush_only
209
- run_case "neithertrailer enumerates both filenames" case_neither
210
- run_case "both present → full wins + stale signal" case_both_present
151
+ run_case "sessionKey file present exit 0" case_file_present
152
+ run_case "no fileexit 1 + missing-on-resolve" case_missing
153
+ run_case "ambiguous prefix exit 1, refuses to pick" case_ambiguous
211
154
 
212
155
  echo ""
213
156
  echo "================================================"
@@ -490,6 +490,52 @@ fi
490
490
 
491
491
  echo "$SCHEMA_CYPHER" | "$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI"
492
492
 
493
+ # ------------------------------------------------------------------
494
+ # Task 1007 — sessionKey backfill (idempotent, runs every seed pass).
495
+ #
496
+ # Conversation and Message rows minted before Task 985 carry only
497
+ # `conversationId`. The new canonical identifier is `sessionKey` (same
498
+ # UUID shape). This block copies conversationId → sessionKey on every
499
+ # row where sessionKey is still null, leaving rows that already carry
500
+ # sessionKey untouched. Re-runs are no-ops. The legacy
501
+ # `conversation_id_unique` constraint and `m.conversationId` index
502
+ # stay until the full code-rename slice lands and no path reads the
503
+ # legacy field; the drop happens in Task 1007's open completion scope.
504
+ # ------------------------------------------------------------------
505
+ echo "==> Backfilling sessionKey on :Conversation and :Message..."
506
+ BACKFILL_RESULT=$("$CYPHER_SHELL" -u "$NEO4J_USER" -p "$NEO4J_PASSWORD" -a "$NEO4J_URI" --format plain << 'BACKFILL_EOF'
507
+ MATCH (c:Conversation)
508
+ WHERE c.sessionKey IS NULL AND c.conversationId IS NOT NULL
509
+ SET c.sessionKey = c.conversationId
510
+ RETURN count(c) AS conversations_backfilled;
511
+ MATCH (m:Message)
512
+ WHERE m.sessionKey IS NULL AND m.conversationId IS NOT NULL
513
+ SET m.sessionKey = m.conversationId
514
+ RETURN count(m) AS messages_backfilled;
515
+ MATCH (c:Conversation) WHERE c.sessionKey IS NULL RETURN count(c) AS conversations_null_after;
516
+ MATCH (m:Message) WHERE m.sessionKey IS NULL RETURN count(m) AS messages_null_after;
517
+ BACKFILL_EOF
518
+ )
519
+ # Emit the migration-1007 adherence lines on stderr so they land in server.log
520
+ # the same as every other log line. Non-zero null counts after backfill are P0:
521
+ # they indicate orphan rows that carry neither identifier and need operator
522
+ # attention before the constraint flip in Task 1011.
523
+ echo "$BACKFILL_RESULT" | python3 -c "
524
+ import sys, re
525
+ rows = [r.strip() for r in sys.stdin.read().splitlines() if r.strip() and not r.strip().startswith(('conversations_', 'messages_'))]
526
+ nums = [int(r) for r in rows if re.fullmatch(r'\d+', r)]
527
+ if len(nums) >= 4:
528
+ conv_bf, msg_bf, conv_null, msg_null = nums[0], nums[1], nums[2], nums[3]
529
+ print(f'[migration-1007] conversation-row-backfill rows={conv_bf} outcome=ok', file=sys.stderr)
530
+ print(f'[migration-1007] message-row-backfill rows={msg_bf} outcome=ok', file=sys.stderr)
531
+ print(f'[migration-1007] adherence-check label=Conversation rows-with-null-sessionkey={conv_null}', file=sys.stderr)
532
+ print(f'[migration-1007] adherence-check label=Message rows-with-null-sessionkey={msg_null}', file=sys.stderr)
533
+ if conv_null > 0 or msg_null > 0:
534
+ print(f'[migration-1007] adherence-check P0=true reason=null-sessionkey-after-backfill', file=sys.stderr)
535
+ else:
536
+ print(f'[migration-1007] backfill output unparseable rows={len(nums)}', file=sys.stderr)
537
+ "
538
+
493
539
  # ------------------------------------------------------------------
494
540
  # 3. Create AdminUser node + ADMIN_OF relationship
495
541
  # ------------------------------------------------------------------
@@ -17,7 +17,7 @@ plugins:
17
17
 
18
18
  # Real Agency
19
19
 
20
- Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all 11 sub-plugins, each independently activatable via `enabledPlugins`. When the bundle is auto-delivered at admin session startup (or explicitly via `premium-deliver`), every sub-plugin in the `plugins:` list above is stamped into `account.json` `enabledPlugins` in one idempotent set-union — delivery implies enablement, so `mcp__loop__*` tools and the other sub-plugin surfaces are visible to the agent from the first turn after install. Disable individual sub-plugins with `plugin-toggle-enabled`. The bundle also delivers three specialist roles negotiator, valuer, and compliance that embed domain knowledge from the sub-plugins and operate autonomously with Loop CRM tools.
20
+ Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all 11 sub-plugins, each independently activatable via `enabledPlugins`. Every admin boot reconciles `account.json` `enabledPlugins` against on-disk presence: any sub-plugin from the `plugins:` list above whose `platform/plugins/<sub>/PLUGIN.md` exists gets stamped via an idempotent set-union, so `mcp__loop__*` tools and the other sub-plugin surfaces are visible to the admin agent from the first turn after install — and on first boot post-deploy for accounts that already had the bundle on disk from a prior install. Disable individual sub-plugins with `plugin-toggle-enabled`. The bundle also delivers three specialist roles (negotiator, valuer, and compliance) that embed domain knowledge from the sub-plugins and operate autonomously with Loop CRM tools.
21
21
 
22
22
  ## Specialist Roles
23
23