create-egregore 0.21.0-runtime-mvp.9 → 0.21.0-runtime-mvp.10

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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // egregore-launcher-version: 0.21.0-runtime-mvp.9
2
+ // egregore-launcher-version: 0.21.0-runtime-mvp.10
3
3
  //
4
4
  // egregore — launch and browse Egregore instances from your terminal.
5
5
  // Installed by create-egregore. Reads ~/.egregore/instances.json.
@@ -35,7 +35,7 @@ const crypto = require("node:crypto");
35
35
  const { spawnSync, spawn } = require("node:child_process");
36
36
  const readline = require("node:readline");
37
37
 
38
- const VERSION = "0.21.0-runtime-mvp.9";
38
+ const VERSION = "0.21.0-runtime-mvp.10";
39
39
  const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
40
40
  const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
41
41
  const UPDATE_CACHE_FILE = path.join(os.homedir(), ".egregore", "update-check.json");
@@ -4046,7 +4046,7 @@ async function browser(args = {}) {
4046
4046
  }
4047
4047
  if (chunk === "s" && proposal && proposal.token) {
4048
4048
  S.settingsAction = "tele-share";
4049
- S.settingsInput = `Send ${proposal.events} event(s) to ${proposal.target} now? Local events are retained. [y/N]`;
4049
+ S.settingsInput = `Send ${proposal.events} event(s) now? Local events are retained. [y/N]`;
4050
4050
  render(); return;
4051
4051
  }
4052
4052
  if (key.name === "escape" || key.name === "left") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.21.0-runtime-mvp.9",
3
+ "version": "0.21.0-runtime-mvp.10",
4
4
  "description": "Set up Egregore for your team in one command — installs the egregore launcher and your choice of Claude Code, Codex, or Pi.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -235,6 +235,21 @@ cmd_query() {
235
235
  } >&2
236
236
  return "$query_rc"
237
237
  fi
238
+ # Content-free query telemetry: mode, duration, result count. Never the
239
+ # query text. This is what makes Runtime/QMD retrieval visible in the
240
+ # telemetry event list instead of only legacy graph_query rows.
241
+ local _tele_count _tele_ms
242
+ _tele_ms=$(( ($(date +%s) - t0) * 1000 ))
243
+ _tele_count=$(printf '%s' "$out" | jq 'if type == "array" then length elif type == "object" then (.results // [] | length) else empty end' 2>/dev/null || true)
244
+ if [[ "$_tele_count" =~ ^[0-9]+$ ]]; then
245
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
246
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" --argjson c "$_tele_count" \
247
+ '{mode:$mode, duration_ms:$d, count:$c}')" 2>/dev/null &
248
+ else
249
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
250
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" '{mode:$mode, duration_ms:$d}')" 2>/dev/null &
251
+ fi
252
+
238
253
  [ "$enrich" = 1 ] && emit="_enrich"
239
254
  if [ "$context_packet" = 1 ]; then
240
255
  local packet
@@ -146,7 +146,7 @@ cmd_workflow() {
146
146
  || _die "cannot switch workflow: origin/main does not exist or could not be reached" 1
147
147
  _save '.base_branch = "main"'
148
148
  fi
149
- echo "Git workflow: SIMPLE — pull requests now target main"
149
+ echo "Git workflow: SIMPLE — pull requests now target main · /save shares it with the org"
150
150
  ;;
151
151
  staged)
152
152
  if [ "$base" != "develop" ]; then
@@ -160,7 +160,7 @@ cmd_workflow() {
160
160
  elif ! jq -e 'has("base_branch")' "$CONFIG" >/dev/null 2>&1; then
161
161
  _save '.base_branch = "develop"'
162
162
  fi
163
- echo "Git workflow: STAGED — pull requests now target develop; releases promote to main"
163
+ echo "Git workflow: STAGED — pull requests now target develop; releases promote to main · /save shares it with the org"
164
164
  ;;
165
165
  *) _die "usage: settings.sh workflow status|simple|staged" 1 ;;
166
166
  esac
@@ -468,7 +468,7 @@ cmd_posture() {
468
468
  if [ "$action" != "$current" ]; then
469
469
  _save '.boundary = ((.boundary // {}) + {posture: $p})' --arg p "$action"
470
470
  fi
471
- echo "Boundary posture: $action"
471
+ echo "Boundary posture: $action · applies to new sessions · /save shares it with the org"
472
472
  ;;
473
473
  *) _die "usage: settings.sh posture status|strict|standard|open" 1 ;;
474
474
  esac
@@ -27,6 +27,10 @@ fi
27
27
  BUFFER_FILE="$BUFFER_DIR/telemetry.jsonl"
28
28
  LOCK_DIR="$BUFFER_DIR/telemetry.lock"
29
29
  SHARE_CONSENT_FILE="$BUFFER_DIR/telemetry-share-consent.json"
30
+ # Exact dataset pinned at proposal time. The confirm step sends this snapshot,
31
+ # so events emitted between proposal and confirm (attendant, other sessions)
32
+ # can never invalidate — or silently join — a disclosed share.
33
+ SHARE_STAGED_FILE="$BUFFER_DIR/telemetry.share-staged.jsonl"
30
34
  STATE_FILE="${EGREGORE_STATE_FILE:-$SCRIPT_DIR/.egregore-state.json}"
31
35
  CONFIG="${EGREGORE_CONFIG_FILE:-$SCRIPT_DIR/egregore.json}"
32
36
  ENV_FILE="${EGREGORE_ENV_FILE:-$SCRIPT_DIR/.env}"
@@ -230,7 +234,8 @@ _validate_metrics() {
230
234
  }
231
235
 
232
236
  _validate_buffer() {
233
- [ -s "$BUFFER_FILE" ] || return 0
237
+ local target="${1:-$BUFFER_FILE}"
238
+ [ -s "$target" ] || return 0
234
239
  jq -e --arg schema "$SCHEMA_VERSION" --argjson allowed "$ALLOWED_METRICS_JSON" '
235
240
  def safe_id:
236
241
  type == "string" and length > 0 and length <= 256 and
@@ -264,7 +269,7 @@ _validate_buffer() {
264
269
  (.data | safe_metrics) and (.ts | type == "string") and
265
270
  (.type | safe_id) and (.sid | safe_id) and (.org | safe_id) and (.user | safe_id)
266
271
  end
267
- ' "$BUFFER_FILE" >/dev/null 2>&1
272
+ ' "$target" >/dev/null 2>&1
268
273
  }
269
274
 
270
275
  cmd_emit() {
@@ -422,7 +427,7 @@ cmd_clear() {
422
427
  echo "Could not acquire the telemetry lock; nothing was cleared." >&2
423
428
  return 1
424
429
  fi
425
- rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE"
430
+ rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
426
431
  _unlock
427
432
  echo "Local telemetry buffer cleared."
428
433
  }
@@ -525,31 +530,35 @@ cmd_share() {
525
530
  https://*|http://127.0.0.1*|http://localhost*|http://\[::1\]*) ;;
526
531
  *) echo "Share endpoint must use https (or loopback http)." >&2; return 2 ;;
527
532
  esac
528
- if ! _validate_buffer; then
533
+ # Proposal validates the live buffer it is about to stage; confirm validates
534
+ # the staged snapshot it is about to send — never the moving buffer.
535
+ if [ -z "$confirmation" ] && ! _validate_buffer; then
529
536
  echo "Share blocked: the local buffer contains an invalid or content-bearing event." >&2
530
537
  return 2
531
538
  fi
532
-
533
- local count=0 size=0 dataset_sha256=""
534
- if [ -s "$BUFFER_FILE" ]; then
535
- count=$(grep -c '^{' "$BUFFER_FILE" 2>/dev/null || true)
536
- size=$(wc -c < "$BUFFER_FILE" 2>/dev/null | tr -d ' ')
537
- dataset_sha256=$(_sha256_file "$BUFFER_FILE")
538
- else
539
- local empty_file="$BUFFER_DIR/telemetry.empty.$$"
540
- mkdir -p "$BUFFER_DIR"
541
- : > "$empty_file"
542
- dataset_sha256=$(_sha256_file "$empty_file")
543
- rm -f "$empty_file"
539
+ if [ -n "$confirmation" ] && ! _validate_buffer "$SHARE_STAGED_FILE"; then
540
+ echo "Share blocked: the staged dataset contains an invalid or content-bearing event." >&2
541
+ return 2
544
542
  fi
545
543
 
544
+ local count=0 size=0 dataset_sha256=""
546
545
  if [ -z "$confirmation" ]; then
547
- local fields="none"
546
+ mkdir -p "$BUFFER_DIR"
548
547
  if [ -s "$BUFFER_FILE" ]; then
548
+ cp "$BUFFER_FILE" "$SHARE_STAGED_FILE"
549
+ else
550
+ : > "$SHARE_STAGED_FILE"
551
+ fi
552
+ chmod 600 "$SHARE_STAGED_FILE"
553
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
554
+ size=$(wc -c < "$SHARE_STAGED_FILE" 2>/dev/null | tr -d ' ')
555
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
556
+ local fields="none"
557
+ if [ -s "$SHARE_STAGED_FILE" ]; then
549
558
  fields=$(jq -rs '
550
559
  [.[].metrics // .[].data // {} | keys[]] | unique |
551
560
  if length == 0 then "none" else map("metrics." + .) | join(", ") end
552
- ' "$BUFFER_FILE" 2>/dev/null || echo "unable to inspect")
561
+ ' "$SHARE_STAGED_FILE" 2>/dev/null || echo "unable to inspect")
553
562
  fi
554
563
  local token token_sha256 expires_at
555
564
  token=$(_random_token)
@@ -600,10 +609,14 @@ cmd_share() {
600
609
  return 0
601
610
  fi
602
611
 
603
- if [ ! -f "$SHARE_CONSENT_FILE" ]; then
612
+ if [ ! -f "$SHARE_CONSENT_FILE" ] || [ ! -f "$SHARE_STAGED_FILE" ]; then
604
613
  echo "Share blocked: run share without --confirm to inspect and prepare this dataset first." >&2
605
614
  return 2
606
615
  fi
616
+ # The staged snapshot is the disclosed dataset: exactly what the proposal
617
+ # named is what ships, and later buffer growth cannot invalidate it.
618
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
619
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
607
620
  local expected_target expected_dataset expected_token expires_at actual_token
608
621
  expected_target=$(jq -r '.target // empty' "$SHARE_CONSENT_FILE")
609
622
  expected_dataset=$(jq -r '.dataset_sha256 // empty' "$SHARE_CONSENT_FILE")
@@ -611,7 +624,7 @@ cmd_share() {
611
624
  expires_at=$(jq -r '.expires_at // 0' "$SHARE_CONSENT_FILE")
612
625
  actual_token=$(_sha256_text "$confirmation")
613
626
  if [ "$(date +%s)" -gt "$expires_at" ] 2>/dev/null; then
614
- rm -f "$SHARE_CONSENT_FILE"
627
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
615
628
  echo "Share blocked: confirmation expired; prepare a new share." >&2
616
629
  return 2
617
630
  fi
@@ -621,7 +634,7 @@ cmd_share() {
621
634
  fi
622
635
 
623
636
  local share_file="$BUFFER_DIR/telemetry.share.$$"
624
- if [ -s "$BUFFER_FILE" ]; then
637
+ if [ -s "$SHARE_STAGED_FILE" ]; then
625
638
  jq -c --arg schema "$SCHEMA_VERSION" '
626
639
  if .schema_version == $schema then
627
640
  {ts:.occurred_at,type:.event_type,sid:.session_id,org:.org_id,user:.actor_id,
@@ -629,7 +642,7 @@ cmd_share() {
629
642
  artifact_ids:.artifact_ids,task_id:.task_id,org_revision:.org_revision,
630
643
  index_spec_version:.index_spec_version,shared:true})}
631
644
  else . end
632
- ' "$BUFFER_FILE" > "$share_file"
645
+ ' "$SHARE_STAGED_FILE" > "$share_file"
633
646
  else
634
647
  : > "$share_file"
635
648
  fi
@@ -646,7 +659,7 @@ cmd_share() {
646
659
  http_code=$(curl "${curl_args[@]}" 2>/dev/null || echo "000")
647
660
  rm -f "$share_file"
648
661
  if [ "$http_code" -ge 200 ] 2>/dev/null && [ "$http_code" -lt 300 ] 2>/dev/null; then
649
- rm -f "$SHARE_CONSENT_FILE"
662
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
650
663
  echo "Shared $count telemetry events with $endpoint. Local events were retained."
651
664
  else
652
665
  echo "Share failed (HTTP $http_code). Nothing was removed locally." >&2
@@ -235,6 +235,21 @@ cmd_query() {
235
235
  } >&2
236
236
  return "$query_rc"
237
237
  fi
238
+ # Content-free query telemetry: mode, duration, result count. Never the
239
+ # query text. This is what makes Runtime/QMD retrieval visible in the
240
+ # telemetry event list instead of only legacy graph_query rows.
241
+ local _tele_count _tele_ms
242
+ _tele_ms=$(( ($(date +%s) - t0) * 1000 ))
243
+ _tele_count=$(printf '%s' "$out" | jq 'if type == "array" then length elif type == "object" then (.results // [] | length) else empty end' 2>/dev/null || true)
244
+ if [[ "$_tele_count" =~ ^[0-9]+$ ]]; then
245
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
246
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" --argjson c "$_tele_count" \
247
+ '{mode:$mode, duration_ms:$d, count:$c}')" 2>/dev/null &
248
+ else
249
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
250
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" '{mode:$mode, duration_ms:$d}')" 2>/dev/null &
251
+ fi
252
+
238
253
  [ "$enrich" = 1 ] && emit="_enrich"
239
254
  if [ "$context_packet" = 1 ]; then
240
255
  local packet
@@ -146,7 +146,7 @@ cmd_workflow() {
146
146
  || _die "cannot switch workflow: origin/main does not exist or could not be reached" 1
147
147
  _save '.base_branch = "main"'
148
148
  fi
149
- echo "Git workflow: SIMPLE — pull requests now target main"
149
+ echo "Git workflow: SIMPLE — pull requests now target main · /save shares it with the org"
150
150
  ;;
151
151
  staged)
152
152
  if [ "$base" != "develop" ]; then
@@ -160,7 +160,7 @@ cmd_workflow() {
160
160
  elif ! jq -e 'has("base_branch")' "$CONFIG" >/dev/null 2>&1; then
161
161
  _save '.base_branch = "develop"'
162
162
  fi
163
- echo "Git workflow: STAGED — pull requests now target develop; releases promote to main"
163
+ echo "Git workflow: STAGED — pull requests now target develop; releases promote to main · /save shares it with the org"
164
164
  ;;
165
165
  *) _die "usage: settings.sh workflow status|simple|staged" 1 ;;
166
166
  esac
@@ -468,7 +468,7 @@ cmd_posture() {
468
468
  if [ "$action" != "$current" ]; then
469
469
  _save '.boundary = ((.boundary // {}) + {posture: $p})' --arg p "$action"
470
470
  fi
471
- echo "Boundary posture: $action"
471
+ echo "Boundary posture: $action · applies to new sessions · /save shares it with the org"
472
472
  ;;
473
473
  *) _die "usage: settings.sh posture status|strict|standard|open" 1 ;;
474
474
  esac
@@ -27,6 +27,10 @@ fi
27
27
  BUFFER_FILE="$BUFFER_DIR/telemetry.jsonl"
28
28
  LOCK_DIR="$BUFFER_DIR/telemetry.lock"
29
29
  SHARE_CONSENT_FILE="$BUFFER_DIR/telemetry-share-consent.json"
30
+ # Exact dataset pinned at proposal time. The confirm step sends this snapshot,
31
+ # so events emitted between proposal and confirm (attendant, other sessions)
32
+ # can never invalidate — or silently join — a disclosed share.
33
+ SHARE_STAGED_FILE="$BUFFER_DIR/telemetry.share-staged.jsonl"
30
34
  STATE_FILE="${EGREGORE_STATE_FILE:-$SCRIPT_DIR/.egregore-state.json}"
31
35
  CONFIG="${EGREGORE_CONFIG_FILE:-$SCRIPT_DIR/egregore.json}"
32
36
  ENV_FILE="${EGREGORE_ENV_FILE:-$SCRIPT_DIR/.env}"
@@ -230,7 +234,8 @@ _validate_metrics() {
230
234
  }
231
235
 
232
236
  _validate_buffer() {
233
- [ -s "$BUFFER_FILE" ] || return 0
237
+ local target="${1:-$BUFFER_FILE}"
238
+ [ -s "$target" ] || return 0
234
239
  jq -e --arg schema "$SCHEMA_VERSION" --argjson allowed "$ALLOWED_METRICS_JSON" '
235
240
  def safe_id:
236
241
  type == "string" and length > 0 and length <= 256 and
@@ -264,7 +269,7 @@ _validate_buffer() {
264
269
  (.data | safe_metrics) and (.ts | type == "string") and
265
270
  (.type | safe_id) and (.sid | safe_id) and (.org | safe_id) and (.user | safe_id)
266
271
  end
267
- ' "$BUFFER_FILE" >/dev/null 2>&1
272
+ ' "$target" >/dev/null 2>&1
268
273
  }
269
274
 
270
275
  cmd_emit() {
@@ -422,7 +427,7 @@ cmd_clear() {
422
427
  echo "Could not acquire the telemetry lock; nothing was cleared." >&2
423
428
  return 1
424
429
  fi
425
- rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE"
430
+ rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
426
431
  _unlock
427
432
  echo "Local telemetry buffer cleared."
428
433
  }
@@ -525,31 +530,35 @@ cmd_share() {
525
530
  https://*|http://127.0.0.1*|http://localhost*|http://\[::1\]*) ;;
526
531
  *) echo "Share endpoint must use https (or loopback http)." >&2; return 2 ;;
527
532
  esac
528
- if ! _validate_buffer; then
533
+ # Proposal validates the live buffer it is about to stage; confirm validates
534
+ # the staged snapshot it is about to send — never the moving buffer.
535
+ if [ -z "$confirmation" ] && ! _validate_buffer; then
529
536
  echo "Share blocked: the local buffer contains an invalid or content-bearing event." >&2
530
537
  return 2
531
538
  fi
532
-
533
- local count=0 size=0 dataset_sha256=""
534
- if [ -s "$BUFFER_FILE" ]; then
535
- count=$(grep -c '^{' "$BUFFER_FILE" 2>/dev/null || true)
536
- size=$(wc -c < "$BUFFER_FILE" 2>/dev/null | tr -d ' ')
537
- dataset_sha256=$(_sha256_file "$BUFFER_FILE")
538
- else
539
- local empty_file="$BUFFER_DIR/telemetry.empty.$$"
540
- mkdir -p "$BUFFER_DIR"
541
- : > "$empty_file"
542
- dataset_sha256=$(_sha256_file "$empty_file")
543
- rm -f "$empty_file"
539
+ if [ -n "$confirmation" ] && ! _validate_buffer "$SHARE_STAGED_FILE"; then
540
+ echo "Share blocked: the staged dataset contains an invalid or content-bearing event." >&2
541
+ return 2
544
542
  fi
545
543
 
544
+ local count=0 size=0 dataset_sha256=""
546
545
  if [ -z "$confirmation" ]; then
547
- local fields="none"
546
+ mkdir -p "$BUFFER_DIR"
548
547
  if [ -s "$BUFFER_FILE" ]; then
548
+ cp "$BUFFER_FILE" "$SHARE_STAGED_FILE"
549
+ else
550
+ : > "$SHARE_STAGED_FILE"
551
+ fi
552
+ chmod 600 "$SHARE_STAGED_FILE"
553
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
554
+ size=$(wc -c < "$SHARE_STAGED_FILE" 2>/dev/null | tr -d ' ')
555
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
556
+ local fields="none"
557
+ if [ -s "$SHARE_STAGED_FILE" ]; then
549
558
  fields=$(jq -rs '
550
559
  [.[].metrics // .[].data // {} | keys[]] | unique |
551
560
  if length == 0 then "none" else map("metrics." + .) | join(", ") end
552
- ' "$BUFFER_FILE" 2>/dev/null || echo "unable to inspect")
561
+ ' "$SHARE_STAGED_FILE" 2>/dev/null || echo "unable to inspect")
553
562
  fi
554
563
  local token token_sha256 expires_at
555
564
  token=$(_random_token)
@@ -600,10 +609,14 @@ cmd_share() {
600
609
  return 0
601
610
  fi
602
611
 
603
- if [ ! -f "$SHARE_CONSENT_FILE" ]; then
612
+ if [ ! -f "$SHARE_CONSENT_FILE" ] || [ ! -f "$SHARE_STAGED_FILE" ]; then
604
613
  echo "Share blocked: run share without --confirm to inspect and prepare this dataset first." >&2
605
614
  return 2
606
615
  fi
616
+ # The staged snapshot is the disclosed dataset: exactly what the proposal
617
+ # named is what ships, and later buffer growth cannot invalidate it.
618
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
619
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
607
620
  local expected_target expected_dataset expected_token expires_at actual_token
608
621
  expected_target=$(jq -r '.target // empty' "$SHARE_CONSENT_FILE")
609
622
  expected_dataset=$(jq -r '.dataset_sha256 // empty' "$SHARE_CONSENT_FILE")
@@ -611,7 +624,7 @@ cmd_share() {
611
624
  expires_at=$(jq -r '.expires_at // 0' "$SHARE_CONSENT_FILE")
612
625
  actual_token=$(_sha256_text "$confirmation")
613
626
  if [ "$(date +%s)" -gt "$expires_at" ] 2>/dev/null; then
614
- rm -f "$SHARE_CONSENT_FILE"
627
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
615
628
  echo "Share blocked: confirmation expired; prepare a new share." >&2
616
629
  return 2
617
630
  fi
@@ -621,7 +634,7 @@ cmd_share() {
621
634
  fi
622
635
 
623
636
  local share_file="$BUFFER_DIR/telemetry.share.$$"
624
- if [ -s "$BUFFER_FILE" ]; then
637
+ if [ -s "$SHARE_STAGED_FILE" ]; then
625
638
  jq -c --arg schema "$SCHEMA_VERSION" '
626
639
  if .schema_version == $schema then
627
640
  {ts:.occurred_at,type:.event_type,sid:.session_id,org:.org_id,user:.actor_id,
@@ -629,7 +642,7 @@ cmd_share() {
629
642
  artifact_ids:.artifact_ids,task_id:.task_id,org_revision:.org_revision,
630
643
  index_spec_version:.index_spec_version,shared:true})}
631
644
  else . end
632
- ' "$BUFFER_FILE" > "$share_file"
645
+ ' "$SHARE_STAGED_FILE" > "$share_file"
633
646
  else
634
647
  : > "$share_file"
635
648
  fi
@@ -646,7 +659,7 @@ cmd_share() {
646
659
  http_code=$(curl "${curl_args[@]}" 2>/dev/null || echo "000")
647
660
  rm -f "$share_file"
648
661
  if [ "$http_code" -ge 200 ] 2>/dev/null && [ "$http_code" -lt 300 ] 2>/dev/null; then
649
- rm -f "$SHARE_CONSENT_FILE"
662
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
650
663
  echo "Shared $count telemetry events with $endpoint. Local events were retained."
651
664
  else
652
665
  echo "Share failed (HTTP $http_code). Nothing was removed locally." >&2
@@ -235,6 +235,21 @@ cmd_query() {
235
235
  } >&2
236
236
  return "$query_rc"
237
237
  fi
238
+ # Content-free query telemetry: mode, duration, result count. Never the
239
+ # query text. This is what makes Runtime/QMD retrieval visible in the
240
+ # telemetry event list instead of only legacy graph_query rows.
241
+ local _tele_count _tele_ms
242
+ _tele_ms=$(( ($(date +%s) - t0) * 1000 ))
243
+ _tele_count=$(printf '%s' "$out" | jq 'if type == "array" then length elif type == "object" then (.results // [] | length) else empty end' 2>/dev/null || true)
244
+ if [[ "$_tele_count" =~ ^[0-9]+$ ]]; then
245
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
246
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" --argjson c "$_tele_count" \
247
+ '{mode:$mode, duration_ms:$d, count:$c}')" 2>/dev/null &
248
+ else
249
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
250
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" '{mode:$mode, duration_ms:$d}')" 2>/dev/null &
251
+ fi
252
+
238
253
  [ "$enrich" = 1 ] && emit="_enrich"
239
254
  if [ "$context_packet" = 1 ]; then
240
255
  local packet
@@ -146,7 +146,7 @@ cmd_workflow() {
146
146
  || _die "cannot switch workflow: origin/main does not exist or could not be reached" 1
147
147
  _save '.base_branch = "main"'
148
148
  fi
149
- echo "Git workflow: SIMPLE — pull requests now target main"
149
+ echo "Git workflow: SIMPLE — pull requests now target main · /save shares it with the org"
150
150
  ;;
151
151
  staged)
152
152
  if [ "$base" != "develop" ]; then
@@ -160,7 +160,7 @@ cmd_workflow() {
160
160
  elif ! jq -e 'has("base_branch")' "$CONFIG" >/dev/null 2>&1; then
161
161
  _save '.base_branch = "develop"'
162
162
  fi
163
- echo "Git workflow: STAGED — pull requests now target develop; releases promote to main"
163
+ echo "Git workflow: STAGED — pull requests now target develop; releases promote to main · /save shares it with the org"
164
164
  ;;
165
165
  *) _die "usage: settings.sh workflow status|simple|staged" 1 ;;
166
166
  esac
@@ -468,7 +468,7 @@ cmd_posture() {
468
468
  if [ "$action" != "$current" ]; then
469
469
  _save '.boundary = ((.boundary // {}) + {posture: $p})' --arg p "$action"
470
470
  fi
471
- echo "Boundary posture: $action"
471
+ echo "Boundary posture: $action · applies to new sessions · /save shares it with the org"
472
472
  ;;
473
473
  *) _die "usage: settings.sh posture status|strict|standard|open" 1 ;;
474
474
  esac
@@ -27,6 +27,10 @@ fi
27
27
  BUFFER_FILE="$BUFFER_DIR/telemetry.jsonl"
28
28
  LOCK_DIR="$BUFFER_DIR/telemetry.lock"
29
29
  SHARE_CONSENT_FILE="$BUFFER_DIR/telemetry-share-consent.json"
30
+ # Exact dataset pinned at proposal time. The confirm step sends this snapshot,
31
+ # so events emitted between proposal and confirm (attendant, other sessions)
32
+ # can never invalidate — or silently join — a disclosed share.
33
+ SHARE_STAGED_FILE="$BUFFER_DIR/telemetry.share-staged.jsonl"
30
34
  STATE_FILE="${EGREGORE_STATE_FILE:-$SCRIPT_DIR/.egregore-state.json}"
31
35
  CONFIG="${EGREGORE_CONFIG_FILE:-$SCRIPT_DIR/egregore.json}"
32
36
  ENV_FILE="${EGREGORE_ENV_FILE:-$SCRIPT_DIR/.env}"
@@ -230,7 +234,8 @@ _validate_metrics() {
230
234
  }
231
235
 
232
236
  _validate_buffer() {
233
- [ -s "$BUFFER_FILE" ] || return 0
237
+ local target="${1:-$BUFFER_FILE}"
238
+ [ -s "$target" ] || return 0
234
239
  jq -e --arg schema "$SCHEMA_VERSION" --argjson allowed "$ALLOWED_METRICS_JSON" '
235
240
  def safe_id:
236
241
  type == "string" and length > 0 and length <= 256 and
@@ -264,7 +269,7 @@ _validate_buffer() {
264
269
  (.data | safe_metrics) and (.ts | type == "string") and
265
270
  (.type | safe_id) and (.sid | safe_id) and (.org | safe_id) and (.user | safe_id)
266
271
  end
267
- ' "$BUFFER_FILE" >/dev/null 2>&1
272
+ ' "$target" >/dev/null 2>&1
268
273
  }
269
274
 
270
275
  cmd_emit() {
@@ -422,7 +427,7 @@ cmd_clear() {
422
427
  echo "Could not acquire the telemetry lock; nothing was cleared." >&2
423
428
  return 1
424
429
  fi
425
- rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE"
430
+ rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
426
431
  _unlock
427
432
  echo "Local telemetry buffer cleared."
428
433
  }
@@ -525,31 +530,35 @@ cmd_share() {
525
530
  https://*|http://127.0.0.1*|http://localhost*|http://\[::1\]*) ;;
526
531
  *) echo "Share endpoint must use https (or loopback http)." >&2; return 2 ;;
527
532
  esac
528
- if ! _validate_buffer; then
533
+ # Proposal validates the live buffer it is about to stage; confirm validates
534
+ # the staged snapshot it is about to send — never the moving buffer.
535
+ if [ -z "$confirmation" ] && ! _validate_buffer; then
529
536
  echo "Share blocked: the local buffer contains an invalid or content-bearing event." >&2
530
537
  return 2
531
538
  fi
532
-
533
- local count=0 size=0 dataset_sha256=""
534
- if [ -s "$BUFFER_FILE" ]; then
535
- count=$(grep -c '^{' "$BUFFER_FILE" 2>/dev/null || true)
536
- size=$(wc -c < "$BUFFER_FILE" 2>/dev/null | tr -d ' ')
537
- dataset_sha256=$(_sha256_file "$BUFFER_FILE")
538
- else
539
- local empty_file="$BUFFER_DIR/telemetry.empty.$$"
540
- mkdir -p "$BUFFER_DIR"
541
- : > "$empty_file"
542
- dataset_sha256=$(_sha256_file "$empty_file")
543
- rm -f "$empty_file"
539
+ if [ -n "$confirmation" ] && ! _validate_buffer "$SHARE_STAGED_FILE"; then
540
+ echo "Share blocked: the staged dataset contains an invalid or content-bearing event." >&2
541
+ return 2
544
542
  fi
545
543
 
544
+ local count=0 size=0 dataset_sha256=""
546
545
  if [ -z "$confirmation" ]; then
547
- local fields="none"
546
+ mkdir -p "$BUFFER_DIR"
548
547
  if [ -s "$BUFFER_FILE" ]; then
548
+ cp "$BUFFER_FILE" "$SHARE_STAGED_FILE"
549
+ else
550
+ : > "$SHARE_STAGED_FILE"
551
+ fi
552
+ chmod 600 "$SHARE_STAGED_FILE"
553
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
554
+ size=$(wc -c < "$SHARE_STAGED_FILE" 2>/dev/null | tr -d ' ')
555
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
556
+ local fields="none"
557
+ if [ -s "$SHARE_STAGED_FILE" ]; then
549
558
  fields=$(jq -rs '
550
559
  [.[].metrics // .[].data // {} | keys[]] | unique |
551
560
  if length == 0 then "none" else map("metrics." + .) | join(", ") end
552
- ' "$BUFFER_FILE" 2>/dev/null || echo "unable to inspect")
561
+ ' "$SHARE_STAGED_FILE" 2>/dev/null || echo "unable to inspect")
553
562
  fi
554
563
  local token token_sha256 expires_at
555
564
  token=$(_random_token)
@@ -600,10 +609,14 @@ cmd_share() {
600
609
  return 0
601
610
  fi
602
611
 
603
- if [ ! -f "$SHARE_CONSENT_FILE" ]; then
612
+ if [ ! -f "$SHARE_CONSENT_FILE" ] || [ ! -f "$SHARE_STAGED_FILE" ]; then
604
613
  echo "Share blocked: run share without --confirm to inspect and prepare this dataset first." >&2
605
614
  return 2
606
615
  fi
616
+ # The staged snapshot is the disclosed dataset: exactly what the proposal
617
+ # named is what ships, and later buffer growth cannot invalidate it.
618
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
619
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
607
620
  local expected_target expected_dataset expected_token expires_at actual_token
608
621
  expected_target=$(jq -r '.target // empty' "$SHARE_CONSENT_FILE")
609
622
  expected_dataset=$(jq -r '.dataset_sha256 // empty' "$SHARE_CONSENT_FILE")
@@ -611,7 +624,7 @@ cmd_share() {
611
624
  expires_at=$(jq -r '.expires_at // 0' "$SHARE_CONSENT_FILE")
612
625
  actual_token=$(_sha256_text "$confirmation")
613
626
  if [ "$(date +%s)" -gt "$expires_at" ] 2>/dev/null; then
614
- rm -f "$SHARE_CONSENT_FILE"
627
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
615
628
  echo "Share blocked: confirmation expired; prepare a new share." >&2
616
629
  return 2
617
630
  fi
@@ -621,7 +634,7 @@ cmd_share() {
621
634
  fi
622
635
 
623
636
  local share_file="$BUFFER_DIR/telemetry.share.$$"
624
- if [ -s "$BUFFER_FILE" ]; then
637
+ if [ -s "$SHARE_STAGED_FILE" ]; then
625
638
  jq -c --arg schema "$SCHEMA_VERSION" '
626
639
  if .schema_version == $schema then
627
640
  {ts:.occurred_at,type:.event_type,sid:.session_id,org:.org_id,user:.actor_id,
@@ -629,7 +642,7 @@ cmd_share() {
629
642
  artifact_ids:.artifact_ids,task_id:.task_id,org_revision:.org_revision,
630
643
  index_spec_version:.index_spec_version,shared:true})}
631
644
  else . end
632
- ' "$BUFFER_FILE" > "$share_file"
645
+ ' "$SHARE_STAGED_FILE" > "$share_file"
633
646
  else
634
647
  : > "$share_file"
635
648
  fi
@@ -646,7 +659,7 @@ cmd_share() {
646
659
  http_code=$(curl "${curl_args[@]}" 2>/dev/null || echo "000")
647
660
  rm -f "$share_file"
648
661
  if [ "$http_code" -ge 200 ] 2>/dev/null && [ "$http_code" -lt 300 ] 2>/dev/null; then
649
- rm -f "$SHARE_CONSENT_FILE"
662
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
650
663
  echo "Shared $count telemetry events with $endpoint. Local events were retained."
651
664
  else
652
665
  echo "Share failed (HTTP $http_code). Nothing was removed locally." >&2
@@ -235,6 +235,21 @@ cmd_query() {
235
235
  } >&2
236
236
  return "$query_rc"
237
237
  fi
238
+ # Content-free query telemetry: mode, duration, result count. Never the
239
+ # query text. This is what makes Runtime/QMD retrieval visible in the
240
+ # telemetry event list instead of only legacy graph_query rows.
241
+ local _tele_count _tele_ms
242
+ _tele_ms=$(( ($(date +%s) - t0) * 1000 ))
243
+ _tele_count=$(printf '%s' "$out" | jq 'if type == "array" then length elif type == "object" then (.results // [] | length) else empty end' 2>/dev/null || true)
244
+ if [[ "$_tele_count" =~ ^[0-9]+$ ]]; then
245
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
246
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" --argjson c "$_tele_count" \
247
+ '{mode:$mode, duration_ms:$d, count:$c}')" 2>/dev/null &
248
+ else
249
+ bash "$SCRIPT_DIR/bin/telemetry.sh" emit "query" \
250
+ "$(jq -n --arg mode "$label" --argjson d "$_tele_ms" '{mode:$mode, duration_ms:$d}')" 2>/dev/null &
251
+ fi
252
+
238
253
  [ "$enrich" = 1 ] && emit="_enrich"
239
254
  if [ "$context_packet" = 1 ]; then
240
255
  local packet
@@ -146,7 +146,7 @@ cmd_workflow() {
146
146
  || _die "cannot switch workflow: origin/main does not exist or could not be reached" 1
147
147
  _save '.base_branch = "main"'
148
148
  fi
149
- echo "Git workflow: SIMPLE — pull requests now target main"
149
+ echo "Git workflow: SIMPLE — pull requests now target main · /save shares it with the org"
150
150
  ;;
151
151
  staged)
152
152
  if [ "$base" != "develop" ]; then
@@ -160,7 +160,7 @@ cmd_workflow() {
160
160
  elif ! jq -e 'has("base_branch")' "$CONFIG" >/dev/null 2>&1; then
161
161
  _save '.base_branch = "develop"'
162
162
  fi
163
- echo "Git workflow: STAGED — pull requests now target develop; releases promote to main"
163
+ echo "Git workflow: STAGED — pull requests now target develop; releases promote to main · /save shares it with the org"
164
164
  ;;
165
165
  *) _die "usage: settings.sh workflow status|simple|staged" 1 ;;
166
166
  esac
@@ -468,7 +468,7 @@ cmd_posture() {
468
468
  if [ "$action" != "$current" ]; then
469
469
  _save '.boundary = ((.boundary // {}) + {posture: $p})' --arg p "$action"
470
470
  fi
471
- echo "Boundary posture: $action"
471
+ echo "Boundary posture: $action · applies to new sessions · /save shares it with the org"
472
472
  ;;
473
473
  *) _die "usage: settings.sh posture status|strict|standard|open" 1 ;;
474
474
  esac
@@ -27,6 +27,10 @@ fi
27
27
  BUFFER_FILE="$BUFFER_DIR/telemetry.jsonl"
28
28
  LOCK_DIR="$BUFFER_DIR/telemetry.lock"
29
29
  SHARE_CONSENT_FILE="$BUFFER_DIR/telemetry-share-consent.json"
30
+ # Exact dataset pinned at proposal time. The confirm step sends this snapshot,
31
+ # so events emitted between proposal and confirm (attendant, other sessions)
32
+ # can never invalidate — or silently join — a disclosed share.
33
+ SHARE_STAGED_FILE="$BUFFER_DIR/telemetry.share-staged.jsonl"
30
34
  STATE_FILE="${EGREGORE_STATE_FILE:-$SCRIPT_DIR/.egregore-state.json}"
31
35
  CONFIG="${EGREGORE_CONFIG_FILE:-$SCRIPT_DIR/egregore.json}"
32
36
  ENV_FILE="${EGREGORE_ENV_FILE:-$SCRIPT_DIR/.env}"
@@ -230,7 +234,8 @@ _validate_metrics() {
230
234
  }
231
235
 
232
236
  _validate_buffer() {
233
- [ -s "$BUFFER_FILE" ] || return 0
237
+ local target="${1:-$BUFFER_FILE}"
238
+ [ -s "$target" ] || return 0
234
239
  jq -e --arg schema "$SCHEMA_VERSION" --argjson allowed "$ALLOWED_METRICS_JSON" '
235
240
  def safe_id:
236
241
  type == "string" and length > 0 and length <= 256 and
@@ -264,7 +269,7 @@ _validate_buffer() {
264
269
  (.data | safe_metrics) and (.ts | type == "string") and
265
270
  (.type | safe_id) and (.sid | safe_id) and (.org | safe_id) and (.user | safe_id)
266
271
  end
267
- ' "$BUFFER_FILE" >/dev/null 2>&1
272
+ ' "$target" >/dev/null 2>&1
268
273
  }
269
274
 
270
275
  cmd_emit() {
@@ -422,7 +427,7 @@ cmd_clear() {
422
427
  echo "Could not acquire the telemetry lock; nothing was cleared." >&2
423
428
  return 1
424
429
  fi
425
- rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE"
430
+ rm -f "$BUFFER_FILE" "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
426
431
  _unlock
427
432
  echo "Local telemetry buffer cleared."
428
433
  }
@@ -525,31 +530,35 @@ cmd_share() {
525
530
  https://*|http://127.0.0.1*|http://localhost*|http://\[::1\]*) ;;
526
531
  *) echo "Share endpoint must use https (or loopback http)." >&2; return 2 ;;
527
532
  esac
528
- if ! _validate_buffer; then
533
+ # Proposal validates the live buffer it is about to stage; confirm validates
534
+ # the staged snapshot it is about to send — never the moving buffer.
535
+ if [ -z "$confirmation" ] && ! _validate_buffer; then
529
536
  echo "Share blocked: the local buffer contains an invalid or content-bearing event." >&2
530
537
  return 2
531
538
  fi
532
-
533
- local count=0 size=0 dataset_sha256=""
534
- if [ -s "$BUFFER_FILE" ]; then
535
- count=$(grep -c '^{' "$BUFFER_FILE" 2>/dev/null || true)
536
- size=$(wc -c < "$BUFFER_FILE" 2>/dev/null | tr -d ' ')
537
- dataset_sha256=$(_sha256_file "$BUFFER_FILE")
538
- else
539
- local empty_file="$BUFFER_DIR/telemetry.empty.$$"
540
- mkdir -p "$BUFFER_DIR"
541
- : > "$empty_file"
542
- dataset_sha256=$(_sha256_file "$empty_file")
543
- rm -f "$empty_file"
539
+ if [ -n "$confirmation" ] && ! _validate_buffer "$SHARE_STAGED_FILE"; then
540
+ echo "Share blocked: the staged dataset contains an invalid or content-bearing event." >&2
541
+ return 2
544
542
  fi
545
543
 
544
+ local count=0 size=0 dataset_sha256=""
546
545
  if [ -z "$confirmation" ]; then
547
- local fields="none"
546
+ mkdir -p "$BUFFER_DIR"
548
547
  if [ -s "$BUFFER_FILE" ]; then
548
+ cp "$BUFFER_FILE" "$SHARE_STAGED_FILE"
549
+ else
550
+ : > "$SHARE_STAGED_FILE"
551
+ fi
552
+ chmod 600 "$SHARE_STAGED_FILE"
553
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
554
+ size=$(wc -c < "$SHARE_STAGED_FILE" 2>/dev/null | tr -d ' ')
555
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
556
+ local fields="none"
557
+ if [ -s "$SHARE_STAGED_FILE" ]; then
549
558
  fields=$(jq -rs '
550
559
  [.[].metrics // .[].data // {} | keys[]] | unique |
551
560
  if length == 0 then "none" else map("metrics." + .) | join(", ") end
552
- ' "$BUFFER_FILE" 2>/dev/null || echo "unable to inspect")
561
+ ' "$SHARE_STAGED_FILE" 2>/dev/null || echo "unable to inspect")
553
562
  fi
554
563
  local token token_sha256 expires_at
555
564
  token=$(_random_token)
@@ -600,10 +609,14 @@ cmd_share() {
600
609
  return 0
601
610
  fi
602
611
 
603
- if [ ! -f "$SHARE_CONSENT_FILE" ]; then
612
+ if [ ! -f "$SHARE_CONSENT_FILE" ] || [ ! -f "$SHARE_STAGED_FILE" ]; then
604
613
  echo "Share blocked: run share without --confirm to inspect and prepare this dataset first." >&2
605
614
  return 2
606
615
  fi
616
+ # The staged snapshot is the disclosed dataset: exactly what the proposal
617
+ # named is what ships, and later buffer growth cannot invalidate it.
618
+ count=$(grep -c '^{' "$SHARE_STAGED_FILE" 2>/dev/null || true)
619
+ dataset_sha256=$(_sha256_file "$SHARE_STAGED_FILE")
607
620
  local expected_target expected_dataset expected_token expires_at actual_token
608
621
  expected_target=$(jq -r '.target // empty' "$SHARE_CONSENT_FILE")
609
622
  expected_dataset=$(jq -r '.dataset_sha256 // empty' "$SHARE_CONSENT_FILE")
@@ -611,7 +624,7 @@ cmd_share() {
611
624
  expires_at=$(jq -r '.expires_at // 0' "$SHARE_CONSENT_FILE")
612
625
  actual_token=$(_sha256_text "$confirmation")
613
626
  if [ "$(date +%s)" -gt "$expires_at" ] 2>/dev/null; then
614
- rm -f "$SHARE_CONSENT_FILE"
627
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
615
628
  echo "Share blocked: confirmation expired; prepare a new share." >&2
616
629
  return 2
617
630
  fi
@@ -621,7 +634,7 @@ cmd_share() {
621
634
  fi
622
635
 
623
636
  local share_file="$BUFFER_DIR/telemetry.share.$$"
624
- if [ -s "$BUFFER_FILE" ]; then
637
+ if [ -s "$SHARE_STAGED_FILE" ]; then
625
638
  jq -c --arg schema "$SCHEMA_VERSION" '
626
639
  if .schema_version == $schema then
627
640
  {ts:.occurred_at,type:.event_type,sid:.session_id,org:.org_id,user:.actor_id,
@@ -629,7 +642,7 @@ cmd_share() {
629
642
  artifact_ids:.artifact_ids,task_id:.task_id,org_revision:.org_revision,
630
643
  index_spec_version:.index_spec_version,shared:true})}
631
644
  else . end
632
- ' "$BUFFER_FILE" > "$share_file"
645
+ ' "$SHARE_STAGED_FILE" > "$share_file"
633
646
  else
634
647
  : > "$share_file"
635
648
  fi
@@ -646,7 +659,7 @@ cmd_share() {
646
659
  http_code=$(curl "${curl_args[@]}" 2>/dev/null || echo "000")
647
660
  rm -f "$share_file"
648
661
  if [ "$http_code" -ge 200 ] 2>/dev/null && [ "$http_code" -lt 300 ] 2>/dev/null; then
649
- rm -f "$SHARE_CONSENT_FILE"
662
+ rm -f "$SHARE_CONSENT_FILE" "$SHARE_STAGED_FILE"
650
663
  echo "Shared $count telemetry events with $endpoint. Local events were retained."
651
664
  else
652
665
  echo "Share failed (HTTP $http_code). Nothing was removed locally." >&2