- Extract redeliver_missed(tx, db, log) helper into cluster_transport.rs - heal_region now removes partition then immediately ships any missed batch-log entries to the healed follower's channel - await_convergence refactored to call the same helper (no logic change) - tidal-server: reload_text_index before search in cluster mode - tidal-server: write_signal returns Result instead of panicking on unknown signal - tidal-server: leader shows lag_events=0 (writes directly, no receiver thread) - tidal-server: fix cluster mode error propagation (ServerError::from) - docs/runbooks/cluster.md: add full cluster operations runbook - docker/: add Dockerfile for containerised cluster deployment - README.md: add tidal-server HTTP API getting-started section - Split oversized source files per CODING_GUIDELINES §9 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
204 lines
8.9 KiB
Bash
204 lines
8.9 KiB
Bash
#!/bin/bash
|
|
# M5 Communication Brief — 10-persona integration test
|
|
set -euo pipefail
|
|
|
|
API="http://localhost:59521"
|
|
RESULTS_DIR="/tmp/brief-test-results"
|
|
rm -rf "$RESULTS_DIR"
|
|
mkdir -p "$RESULTS_DIR"
|
|
|
|
# Parse SSE stream into plain text
|
|
parse_sse() {
|
|
local output=""
|
|
while IFS= read -r line; do
|
|
line="${line%$'\r'}"
|
|
if [[ "$line" == "data: [DONE]" ]]; then break; fi
|
|
if [[ "$line" == data:* ]]; then
|
|
local json="${line#data: }"
|
|
local token
|
|
token=$(echo "$json" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('token',''),end='')" 2>/dev/null || true)
|
|
output+="$token"
|
|
fi
|
|
done
|
|
echo "$output"
|
|
}
|
|
|
|
# Send a multi-turn conversation
|
|
# Args: persona_name personId convId msg1 msg2 msg3 msg4 msg5
|
|
run_persona() {
|
|
local name="$1"
|
|
local pid="$2"
|
|
local cid="$3"
|
|
shift 3
|
|
local msgs=("$@")
|
|
|
|
echo "[$name] Starting (${pid:0:8}…)"
|
|
|
|
local history="[]"
|
|
|
|
for i in "${!msgs[@]}"; do
|
|
local msg="${msgs[$i]}"
|
|
# Add user message to history
|
|
history=$(echo "$history" | python3 -c "
|
|
import sys, json
|
|
h = json.load(sys.stdin)
|
|
h.append({'role': 'user', 'content': '''${msg//\'/\'\\\'\'}'''})
|
|
print(json.dumps(h))
|
|
")
|
|
|
|
# Send request and capture response
|
|
local response
|
|
response=$(curl -s -N -X POST "$API/api/chat" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$(python3 -c "
|
|
import json
|
|
h = json.loads('''$(echo "$history" | sed "s/'/\\\\'/g")''')
|
|
print(json.dumps({'messages': h, 'conversationId': '$cid', 'personId': '$pid'}))
|
|
")" \
|
|
--max-time 30 2>/dev/null | parse_sse)
|
|
|
|
if [[ -z "$response" ]]; then
|
|
echo "[$name] Turn $((i+1)): NO RESPONSE"
|
|
continue
|
|
fi
|
|
|
|
# Add assistant response to history
|
|
history=$(echo "$history" | python3 -c "
|
|
import sys, json
|
|
h = json.load(sys.stdin)
|
|
h.append({'role': 'assistant', 'content': '''${response//\'/\'\\\'\'}'''})
|
|
print(json.dumps(h))
|
|
")
|
|
|
|
echo "[$name] Turn $((i+1))/5: user='${msg:0:50}…' → resp='${response:0:60}…'"
|
|
|
|
# Small delay for observer to process
|
|
sleep 1
|
|
done
|
|
|
|
# Wait for observer signals to propagate
|
|
echo "[$name] Waiting for observer signals..."
|
|
sleep 3
|
|
|
|
# Fetch brief
|
|
echo "[$name] Fetching brief..."
|
|
curl -s "$API/api/brief/$pid" | python3 -m json.tool > "$RESULTS_DIR/${name}.json" 2>/dev/null || echo "{}" > "$RESULTS_DIR/${name}.json"
|
|
echo "[$name] Done → $RESULTS_DIR/${name}.json"
|
|
}
|
|
|
|
echo "=== M5 Communication Brief — 10 Persona Test ==="
|
|
echo ""
|
|
|
|
# Generate unique IDs
|
|
p1=$(uuidgen) c1=$(uuidgen)
|
|
p2=$(uuidgen) c2=$(uuidgen)
|
|
p3=$(uuidgen) c3=$(uuidgen)
|
|
p4=$(uuidgen) c4=$(uuidgen)
|
|
p5=$(uuidgen) c5=$(uuidgen)
|
|
p6=$(uuidgen) c6=$(uuidgen)
|
|
p7=$(uuidgen) c7=$(uuidgen)
|
|
p8=$(uuidgen) c8=$(uuidgen)
|
|
p9=$(uuidgen) c9=$(uuidgen)
|
|
p10=$(uuidgen) c10=$(uuidgen)
|
|
|
|
# Run all 10 personas sequentially
|
|
run_persona "casual-tech" "$p1" "$c1" \
|
|
"yo have you ever messed with rust? trying to figure out if its worth learning" \
|
|
"yeah but like the borrow checker seems insane. is it really that bad" \
|
|
"hmm ok what about async stuff. heard tokio is the move" \
|
|
"cool cool. i mostly do typescript rn so maybe its a big jump" \
|
|
"bet. might just start with some cli tools first"
|
|
|
|
run_persona "formal-academic" "$p2" "$c2" \
|
|
"I've been researching the implications of large language models on academic writing. What are your thoughts on the epistemological challenges they present?" \
|
|
"That is an interesting perspective. I am particularly concerned with the reproducibility crisis that may emerge when AI-generated text becomes indistinguishable from human-authored work." \
|
|
"Indeed. My current research examines citation integrity in the context of synthetic text generation. The methodological implications are quite significant." \
|
|
"I appreciate your engagement with this topic. Have you considered the role of institutional review boards in establishing guidelines for AI-assisted research?" \
|
|
"Precisely. I believe we need a comprehensive framework that addresses both the ethical and methodological dimensions of this paradigm shift."
|
|
|
|
run_persona "emotional" "$p3" "$c3" \
|
|
"hey... having kind of a rough day. do you ever just feel like nothing makes sense" \
|
|
"yeah i dont know. work stuff mostly. feeling like im not good enough" \
|
|
"thats actually really nice to hear. i guess i just compare myself to everyone" \
|
|
"youre right. i think i need to be easier on myself. its just hard sometimes" \
|
|
"thanks for listening. seriously. most people just say cheer up and move on"
|
|
|
|
run_persona "rapid-fire" "$p4" "$c4" \
|
|
"whats the best programming language" \
|
|
"ok but why not python? also whats your take on AI replacing developers" \
|
|
"interesting. what about quantum computing? will it change everything?" \
|
|
"sure but when? also do you think remote work is dying? and whats the deal with web3" \
|
|
"lol ok last one. tabs or spaces?"
|
|
|
|
run_persona "deep-diver" "$p5" "$c5" \
|
|
"been thinking a lot about consensus algorithms lately. raft vs paxos which do you think is more practical" \
|
|
"yeah rafts understandability is a huge win. but what about the leader bottleneck? in high-throughput scenarios it becomes a real issue" \
|
|
"exactly. thats why ive been looking at multi-raft where you shard the state machine. cockroachdb does this well" \
|
|
"the tricky part is cross-range transactions though. you need some form of 2PC or parallel commits. spanners truetime approach is elegant but impractical for most" \
|
|
"right. i think the future is deterministic databases like calvin where you pre-order transactions. eliminates coordination entirely"
|
|
|
|
run_persona "emoji-fan" "$p6" "$c6" \
|
|
"hiii just discovered this app and im obsessed already omg" \
|
|
"yes do you like music? im really into kpop rn" \
|
|
"blackpink is my absolute fave but also really vibing with newjeans lately" \
|
|
"yesss taste what about movies? seen anything good" \
|
|
"ooh ill check it out thanks bestie"
|
|
|
|
run_persona "skeptic" "$p7" "$c7" \
|
|
"AI chatbots are mostly hype. Change my mind." \
|
|
"Thats a surface-level argument. Most benchmarks are gamed and dont reflect real-world utility. The actual failure rate in production is much higher than reported." \
|
|
"Youre oversimplifying. The economic analysis doesnt support widespread adoption when you factor in inference costs, hallucination liability, and the need for human oversight." \
|
|
"Thats incorrect. The study youre likely referencing has significant methodological flaws. I can point to three counter-studies." \
|
|
"Ill concede that narrow applications show promise. But the general intelligence narrative is fundamentally misleading."
|
|
|
|
run_persona "creative-writer" "$p8" "$c8" \
|
|
"ive been working on a short story about a lighthouse keeper who discovers the light attracts something from the deep ocean. want to hear about it" \
|
|
"so the keeper notices the fish patterns change when the light hits a certain frequency. they start swimming in spirals. then one night something massive surfaces" \
|
|
"exactly that tension. i want the reader to feel the keepers isolation. she cant tell anyone because the coast guard would shut down the lighthouse" \
|
|
"ooh thats a great idea. what if the creature communicates through bioluminescence? like its been trying to respond to the lighthouse for centuries" \
|
|
"yes and the ending she has to choose between warning the world and protecting this ancient being. i think she chooses silence"
|
|
|
|
run_persona "shy-terse" "$p9" "$c9" \
|
|
"hi" \
|
|
"not much" \
|
|
"i guess i like reading" \
|
|
"fantasy mostly" \
|
|
"yeah sanderson is ok"
|
|
|
|
run_persona "multi-domain" "$p10" "$c10" \
|
|
"been learning to cook thai food this week. green curry from scratch is no joke" \
|
|
"oh totally different topic but have you been following the mars rover updates? they found something wild" \
|
|
"yeah the organic compounds thing. anyway do you play any instruments? i just started guitar" \
|
|
"haha yeah my fingers hurt. oh hey what do you think about intermittent fasting? friend keeps pushing it" \
|
|
"makes sense. alright one more random one whats your take on minimalism as a lifestyle"
|
|
|
|
echo ""
|
|
echo "=== All personas complete. Checking briefs... ==="
|
|
echo ""
|
|
|
|
# Summary
|
|
for f in "$RESULTS_DIR"/*.json; do
|
|
name=$(basename "$f" .json)
|
|
topics=$(python3 -c "
|
|
import json
|
|
with open('$f') as fh:
|
|
d = json.load(fh)
|
|
hot = d.get('topics',{}).get('hot',[])
|
|
style = d.get('style',{}).get('formality','?')
|
|
length = d.get('style',{}).get('length','?')
|
|
obs = len(d.get('observations',[]))
|
|
ms = d.get('assemblyMs', '?')
|
|
count = d.get('interactionCount', 0)
|
|
domains = d.get('topics',{}).get('domains',[])
|
|
cohort = 'active' if d.get('cohortPriors',{}).get('active') else 'inactive'
|
|
sentiment = d.get('patterns',{}).get('avgSentiment','?')
|
|
trend = d.get('patterns',{}).get('sentimentTrend','?')
|
|
print(f' style={style}/{length} | sentiment={sentiment} ({trend}) | topics={len(hot)} hot, domains={domains[:3]} | obs={obs} | cohort={cohort} | {ms}ms | {count} interactions')
|
|
" 2>/dev/null || echo " PARSE ERROR")
|
|
echo "[$name]"
|
|
echo "$topics"
|
|
done
|
|
|
|
echo ""
|
|
echo "=== Full briefs saved to $RESULTS_DIR/ ==="
|