qualia-framework 6.2.10 → 6.3.0

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 (58) hide show
  1. package/AGENTS.md +1 -0
  2. package/CLAUDE.md +1 -0
  3. package/README.md +16 -23
  4. package/bin/cli.js +49 -2
  5. package/bin/command-surface.js +71 -0
  6. package/bin/harness-eval.js +296 -0
  7. package/bin/install.js +17 -20
  8. package/bin/knowledge-flush.js +21 -10
  9. package/bin/knowledge.js +1 -1
  10. package/bin/project-snapshot.js +20 -0
  11. package/bin/report-payload.js +18 -0
  12. package/bin/runtime-manifest.js +3 -0
  13. package/bin/state.js +31 -0
  14. package/bin/trust-score.js +3 -11
  15. package/bin/work-packet.js +228 -0
  16. package/docs/erp-contract.md +81 -1
  17. package/docs/onboarding.html +0 -11
  18. package/guide.md +14 -15
  19. package/hooks/fawzi-approval-guard.js +143 -0
  20. package/hooks/pre-deploy-gate.js +74 -1
  21. package/hooks/session-start.js +29 -1
  22. package/package.json +1 -1
  23. package/qualia-design/frontend.md +2 -2
  24. package/rules/codex-goal.md +1 -1
  25. package/rules/one-opinion.md +2 -2
  26. package/rules/speed.md +0 -1
  27. package/skills/qualia/SKILL.md +4 -4
  28. package/skills/qualia-feature/SKILL.md +1 -1
  29. package/skills/qualia-fix/SKILL.md +4 -4
  30. package/skills/qualia-learn/SKILL.md +1 -1
  31. package/skills/qualia-polish/REFERENCE.md +1 -1
  32. package/skills/qualia-polish/SKILL.md +19 -4
  33. package/skills/{qualia-vibe/scripts/extract.mjs → qualia-polish/scripts/vibe-extract.mjs} +4 -4
  34. package/skills/{qualia-vibe/scripts/tokens.mjs → qualia-polish/scripts/vibe-tokens.mjs} +6 -6
  35. package/skills/qualia-road/SKILL.md +15 -20
  36. package/skills/qualia-ship/SKILL.md +12 -5
  37. package/skills/qualia-verify/SKILL.md +9 -1
  38. package/templates/help.html +1 -12
  39. package/tests/bin.test.sh +144 -72
  40. package/tests/hooks.test.sh +81 -1
  41. package/tests/install-smoke.test.sh +13 -3
  42. package/tests/lib.test.sh +145 -3
  43. package/tests/published-install-smoke.test.sh +4 -3
  44. package/tests/refs.test.sh +9 -4
  45. package/tests/runner.js +29 -28
  46. package/tests/state.test.sh +68 -0
  47. package/skills/qualia-debug/SKILL.md +0 -193
  48. package/skills/qualia-flush/SKILL.md +0 -198
  49. package/skills/qualia-help/SKILL.md +0 -74
  50. package/skills/qualia-hook-gen/SKILL.md +0 -206
  51. package/skills/qualia-idk/SKILL.md +0 -166
  52. package/skills/qualia-issues/SKILL.md +0 -151
  53. package/skills/qualia-pause/SKILL.md +0 -68
  54. package/skills/qualia-resume/SKILL.md +0 -52
  55. package/skills/qualia-skill-new/SKILL.md +0 -173
  56. package/skills/qualia-triage/SKILL.md +0 -152
  57. package/skills/qualia-vibe/SKILL.md +0 -229
  58. package/skills/qualia-zoom/SKILL.md +0 -51
package/tests/bin.test.sh CHANGED
@@ -137,7 +137,7 @@ TMP=$(mktmp)
137
137
  mkdir -p "$TMP/.claude"
138
138
  cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
139
139
  {
140
- "code": "QS-FAWZI-01",
140
+ "code": "QS-FAWZI-11",
141
141
  "installed_by": "Fawzi Goussous",
142
142
  "role": "OWNER",
143
143
  "version": "2.8.1",
@@ -421,7 +421,7 @@ TMP=$(mktmp)
421
421
  mkdir -p "$TMP/.claude"
422
422
  cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
423
423
  {
424
- "code": "QS-FAWZI-01",
424
+ "code": "QS-FAWZI-11",
425
425
  "installed_by": "Fawzi Goussous",
426
426
  "role": "OWNER",
427
427
  "version": "2.8.1",
@@ -446,29 +446,32 @@ echo "install.js:"
446
446
 
447
447
  # 28. Happy path: valid code installs everything
448
448
  TMP=$(mktmp)
449
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
449
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
450
450
  EXIT=$?
451
451
  if [ "$EXIT" -eq 0 ] \
452
452
  && [ -f "$TMP/.claude/skills/qualia/SKILL.md" ] \
453
453
  && [ -f "$TMP/.claude/hooks/session-start.js" ] \
454
454
  && [ -f "$TMP/.claude/bin/state.js" ] \
455
455
  && [ -f "$TMP/.claude/bin/runtime-manifest.js" ] \
456
+ && [ -f "$TMP/.claude/bin/command-surface.js" ] \
456
457
  && [ -f "$TMP/.claude/bin/host-adapters.js" ] \
457
458
  && [ -f "$TMP/.claude/bin/qualia-ui.js" ] \
458
459
  && [ -f "$TMP/.claude/bin/statusline.js" ] \
459
460
  && [ -f "$TMP/.claude/bin/state-ledger.js" ] \
460
461
  && [ -f "$TMP/.claude/bin/contract-runner.js" ] \
462
+ && [ -f "$TMP/.claude/bin/harness-eval.js" ] \
461
463
  && [ -f "$TMP/.claude/bin/trust-score.js" ] \
464
+ && [ -f "$TMP/.claude/bin/work-packet.js" ] \
462
465
  && [ -f "$TMP/.claude/bin/project-snapshot.js" ] \
463
466
  && [ -f "$TMP/.claude/bin/planning-hygiene.js" ] \
464
467
  && [ -f "$TMP/.claude/.qualia-config.json" ]; then
465
- pass "QS-FAWZI-01 → installs skills, hooks, bin/, config"
468
+ pass "QS-FAWZI-11 → installs skills, hooks, bin/, config"
466
469
  else
467
- fail_case "QS-FAWZI-01 happy path" "exit=$EXIT"
470
+ fail_case "QS-FAWZI-11 happy path" "exit=$EXIT"
468
471
  fi
469
472
 
470
473
  # 29. Config JSON has correct fields after happy path
471
- if grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json" \
474
+ if grep -q '"code": "QS-FAWZI-11"' "$TMP/.claude/.qualia-config.json" \
472
475
  && grep -q '"installed_by": "Fawzi Goussous"' "$TMP/.claude/.qualia-config.json" \
473
476
  && grep -q '"role": "OWNER"' "$TMP/.claude/.qualia-config.json"; then
474
477
  pass "config JSON has code, installed_by, role=OWNER"
@@ -484,13 +487,13 @@ else
484
487
  fail_case "CLAUDE.md role substitution"
485
488
  fi
486
489
 
487
- # 31. All 11 hooks installed (block-env-edit removed in v3.2.0;
490
+ # 31. All 12 hooks installed (block-env-edit removed in v3.2.0;
488
491
  # git-guardrails + stop-session-log added in v4.2.0;
489
492
  # vercel-account-guard + env-empty-guard + supabase-destructive-guard added in v5.0.0;
490
- # pre-compact removed in v6.2.0)
493
+ # pre-compact removed in v6.2.0; fawzi-approval-guard added in v6.2.11)
491
494
  HOOK_COUNT=$(ls "$TMP/.claude/hooks/"*.js 2>/dev/null | wc -l)
492
- if [ "$HOOK_COUNT" -eq 11 ]; then
493
- pass "11 hooks installed in hooks/"
495
+ if [ "$HOOK_COUNT" -eq 12 ]; then
496
+ pass "12 hooks installed in hooks/"
494
497
  else
495
498
  fail_case "hook count" "got $HOOK_COUNT"
496
499
  fi
@@ -506,7 +509,7 @@ else
506
509
  fail_case "settings.json contents"
507
510
  fi
508
511
 
509
- # 33. settings.json contains all 11 hooks wired correctly
512
+ # 33. settings.json contains all 12 hooks wired correctly
510
513
  # pre-compact.js was removed in v6.2.0 — verify it's NOT in settings.json.
511
514
  if grep -q 'branch-guard.js' "$TMP/.claude/settings.json" \
512
515
  && grep -q 'migration-guard.js' "$TMP/.claude/settings.json" \
@@ -517,33 +520,34 @@ if grep -q 'branch-guard.js' "$TMP/.claude/settings.json" \
517
520
  && grep -q 'git-guardrails.js' "$TMP/.claude/settings.json" \
518
521
  && grep -q 'stop-session-log.js' "$TMP/.claude/settings.json" \
519
522
  && grep -q 'vercel-account-guard.js' "$TMP/.claude/settings.json" \
523
+ && grep -q 'fawzi-approval-guard.js' "$TMP/.claude/settings.json" \
520
524
  && grep -q 'env-empty-guard.js' "$TMP/.claude/settings.json" \
521
525
  && grep -q 'supabase-destructive-guard.js' "$TMP/.claude/settings.json" \
522
526
  && ! grep -q 'pre-compact.js' "$TMP/.claude/settings.json"; then
523
- pass "settings.json has all 11 hooks wired (no pre-compact)"
527
+ pass "settings.json has all 12 hooks wired (no pre-compact)"
524
528
  else
525
529
  fail_case "settings.json hooks misconfigured (check for stale pre-compact entry)"
526
530
  fi
527
531
 
528
532
  # 34. Lowercase code works (resolveTeamCode normalizes)
529
533
  TMP=$(mktmp)
530
- echo "qs-fawzi-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
534
+ echo "qs-fawzi-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
531
535
  EXIT=$?
532
536
  if [ "$EXIT" -eq 0 ] \
533
537
  && [ -f "$TMP/.claude/.qualia-config.json" ] \
534
- && grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
535
- pass "lowercase 'qs-fawzi-01' → canonical 'QS-FAWZI-01'"
538
+ && grep -q '"code": "QS-FAWZI-11"' "$TMP/.claude/.qualia-config.json"; then
539
+ pass "lowercase 'qs-fawzi-11' → canonical 'QS-FAWZI-11'"
536
540
  else
537
541
  fail_case "lowercase normalization" "exit=$EXIT"
538
542
  fi
539
543
 
540
- # 34. O/0 typo tolerance — letter O in suffix normalized to digit 0
544
+ # 34b. O/0 typo tolerance — letter O in suffix normalized to digit 0
541
545
  TMP=$(mktmp)
542
- echo "QS-FAWZI-O1" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
546
+ echo "QS-HASAN-O2" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
543
547
  EXIT=$?
544
548
  if [ "$EXIT" -eq 0 ] \
545
549
  && [ -f "$TMP/.claude/.qualia-config.json" ] \
546
- && grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
550
+ && grep -q '"code": "QS-HASAN-02"' "$TMP/.claude/.qualia-config.json"; then
547
551
  pass "letter 'O' in suffix → normalized to digit '0'"
548
552
  else
549
553
  fail_case "O/0 fuzzy match" "exit=$EXIT"
@@ -598,10 +602,10 @@ fi
598
602
 
599
603
  # 39. Code with surrounding whitespace is accepted
600
604
  TMP=$(mktmp)
601
- printf ' QS-FAWZI-01 \n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
605
+ printf ' QS-FAWZI-11 \n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
602
606
  EXIT=$?
603
607
  if [ "$EXIT" -eq 0 ] \
604
- && grep -q '"code": "QS-FAWZI-01"' "$TMP/.claude/.qualia-config.json"; then
608
+ && grep -q '"code": "QS-FAWZI-11"' "$TMP/.claude/.qualia-config.json"; then
605
609
  pass "whitespace-padded code → accepted and trimmed"
606
610
  else
607
611
  fail_case "whitespace trim" "exit=$EXIT"
@@ -618,7 +622,7 @@ cat > "$TMP/.claude/settings.json" <<'EOF'
618
622
  }
619
623
  }
620
624
  EOF
621
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
625
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
622
626
  EXIT=$?
623
627
  MERGED=$($NODE -e 'const s=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log([s.customKey,s.env&&s.env.MY_CUSTOM_VAR,s.env&&s.env.CLAUDE_CODE_NO_FLICKER,!!s.hooks,!!s.statusLine].join("|"))' "$TMP/.claude/settings.json" 2>/dev/null)
624
628
  if [ "$EXIT" -eq 0 ] \
@@ -630,7 +634,7 @@ fi
630
634
 
631
635
  # 41. Knowledge files created on first install
632
636
  TMP=$(mktmp)
633
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
637
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
634
638
  EXIT=$?
635
639
  if [ "$EXIT" -eq 0 ] \
636
640
  && [ -f "$TMP/.claude/knowledge/learned-patterns.md" ] \
@@ -643,7 +647,7 @@ fi
643
647
 
644
648
  # 42. Idempotent re-install preserves user edits to knowledge files
645
649
  printf '\n## CUSTOM LEARNING — DO NOT OVERWRITE\n' >> "$TMP/.claude/knowledge/learned-patterns.md"
646
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out2.log" 2>&1
650
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out2.log" 2>&1
647
651
  EXIT=$?
648
652
  if [ "$EXIT" -eq 0 ] \
649
653
  && grep -q "CUSTOM LEARNING" "$TMP/.claude/knowledge/learned-patterns.md"; then
@@ -658,7 +662,7 @@ if [ ! -f "$TMP/.claude/.erp-api-key" ] && [ "$CONFIG_ENABLED" = "disabled" ]; t
658
662
  echo " ✓ ERP disabled when no API key is provided"
659
663
  PASS=$((PASS + 1))
660
664
  echo "custom-erp-key" > "$TMP/.claude/.erp-api-key"
661
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out3.log" 2>&1
665
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out3.log" 2>&1
662
666
  if grep -q "custom-erp-key" "$TMP/.claude/.erp-api-key"; then
663
667
  pass ".erp-api-key preserved on re-install"
664
668
  else
@@ -670,7 +674,7 @@ fi
670
674
 
671
675
  # 44. Templates copied to qualia-templates/
672
676
  TMP=$(mktmp)
673
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
677
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/out.log" 2>&1
674
678
  EXIT=$?
675
679
  TMPL_COUNT=$(ls "$TMP/.claude/qualia-templates/" 2>/dev/null | wc -l)
676
680
  if [ "$EXIT" -eq 0 ] && [ "$TMPL_COUNT" -gt 0 ]; then
@@ -719,13 +723,14 @@ fi
719
723
  echo ""
720
724
  echo "--- v4.2.0 phase 3 (flush + forks + model matrix) ---"
721
725
 
722
- # 61. qualia-flush skill installs
726
+ # 61. qualia-flush is retired from the default slash-command surface
723
727
  TMP=$(mktmp)
724
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
725
- if [ -f "$TMP/.claude/skills/qualia-flush/SKILL.md" ]; then
726
- pass "qualia-flush skill installs"
728
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
729
+ if [ ! -f "$TMP/.claude/skills/qualia-flush/SKILL.md" ] \
730
+ && [ -f "$TMP/.claude/bin/knowledge-flush.js" ]; then
731
+ pass "qualia-flush retired; knowledge-flush.js remains installed"
727
732
  else
728
- fail_case "qualia-flush skill missing after install"
733
+ fail_case "qualia-flush retirement/install state"
729
734
  fi
730
735
 
731
736
  # 62. CLAUDE_AGENT_FORK_ENABLED=1 in settings.json
@@ -966,7 +971,7 @@ fi
966
971
 
967
972
  # 70. qualia-postmortem skill installs
968
973
  TMP=$(mktmp)
969
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
974
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
970
975
  if [ -f "$TMP/.claude/skills/qualia-postmortem/SKILL.md" ]; then
971
976
  pass "qualia-postmortem skill installs"
972
977
  else
@@ -1043,7 +1048,7 @@ echo "--- v5.0.0 (alignment substrate + new skills) ---"
1043
1048
 
1044
1049
  # 79. CONTEXT.md template installs to qualia-templates/
1045
1050
  TMP=$(mktmp)
1046
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1051
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1047
1052
  if [ -f "$TMP/.claude/qualia-templates/CONTEXT.md" ]; then
1048
1053
  pass "CONTEXT.md template installs to qualia-templates/"
1049
1054
  else
@@ -1057,12 +1062,17 @@ else
1057
1062
  fail_case "decisions/ADR-template.md missing"
1058
1063
  fi
1059
1064
 
1060
- # 81-84. The 4 new v5 skills install with their SKILL.md
1061
- for SKILL in qualia-zoom qualia-road qualia-issues qualia-triage; do
1062
- if [ -f "$TMP/.claude/skills/$SKILL/SKILL.md" ]; then
1063
- pass "$SKILL skill installs"
1065
+ # 81-84. v6.3 keeps road active and retires queue/zoom helper commands
1066
+ if [ -f "$TMP/.claude/skills/qualia-road/SKILL.md" ]; then
1067
+ pass "qualia-road skill installs"
1068
+ else
1069
+ fail_case "qualia-road skill missing after install"
1070
+ fi
1071
+ for SKILL in qualia-zoom qualia-issues qualia-triage; do
1072
+ if [ ! -f "$TMP/.claude/skills/$SKILL/SKILL.md" ]; then
1073
+ pass "$SKILL retired from default install"
1064
1074
  else
1065
- fail_case "$SKILL skill missing after install"
1075
+ fail_case "$SKILL should be retired from default install"
1066
1076
  fi
1067
1077
  done
1068
1078
 
@@ -1109,12 +1119,11 @@ else
1109
1119
  fail_case "builder.md missing Trust boundary block"
1110
1120
  fi
1111
1121
 
1112
- # 91. qualia-issues uses --body-file (not vulnerable heredoc) for gh issue create
1113
- if grep -q -- "--body-file" "$TMP/.claude/skills/qualia-issues/SKILL.md" \
1114
- && ! grep -q "gh issue create.*--body \"\$(cat <<" "$TMP/.claude/skills/qualia-issues/SKILL.md"; then
1115
- pass "qualia-issues uses --body-file (no heredoc shell injection)"
1122
+ # 91. qualia-issues source is removed from the shipped command surface
1123
+ if [ ! -d "$FRAMEWORK_DIR/skills/qualia-issues" ]; then
1124
+ pass "qualia-issues source removed from shipped command surface"
1116
1125
  else
1117
- fail_case "qualia-issues still uses heredoc for gh issue body"
1126
+ fail_case "qualia-issues source directory should not be shipped"
1118
1127
  fi
1119
1128
 
1120
1129
  # 92-94. v5.0 insights-driven hooks parse as valid Node and install
@@ -1174,7 +1183,7 @@ echo "--- v5.0.0 (visual-polish loop addendum) ---"
1174
1183
 
1175
1184
  # 99. qualia-polish SKILL.md installs (v5.8: polish-loop consolidated into --loop flag)
1176
1185
  TMP=$(mktmp)
1177
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1186
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1178
1187
  if [ -f "$TMP/.claude/skills/qualia-polish/SKILL.md" ]; then
1179
1188
  pass "qualia-polish SKILL.md installs"
1180
1189
  else
@@ -1353,7 +1362,7 @@ echo "--- v5.1.0 (multi-target install: Claude / Codex / Both) ---"
1353
1362
 
1354
1363
  # 118. Target=1 (Claude only) installs to ~/.claude/, not ~/.codex/
1355
1364
  TMP=$(mktmp)
1356
- printf 'QS-FAWZI-01\n1\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1365
+ printf 'QS-FAWZI-11\n1\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1357
1366
  EXIT=$?
1358
1367
  if [ "$EXIT" -eq 0 ] \
1359
1368
  && [ -f "$TMP/.claude/.qualia-config.json" ] \
@@ -1365,7 +1374,7 @@ fi
1365
1374
 
1366
1375
  # 119. Target=2 (Codex only) writes native Codex runtime files, skips ~/.claude/
1367
1376
  TMP=$(mktmp)
1368
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1377
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1369
1378
  EXIT=$?
1370
1379
  if [ "$EXIT" -eq 0 ] \
1371
1380
  && [ -f "$TMP/.codex/AGENTS.md" ] \
@@ -1373,11 +1382,14 @@ if [ "$EXIT" -eq 0 ] \
1373
1382
  && [ -f "$TMP/.codex/config.toml" ] \
1374
1383
  && [ -f "$TMP/.codex/hooks.json" ] \
1375
1384
  && [ -f "$TMP/.codex/bin/runtime-manifest.js" ] \
1385
+ && [ -f "$TMP/.codex/bin/command-surface.js" ] \
1376
1386
  && [ -f "$TMP/.codex/bin/host-adapters.js" ] \
1377
1387
  && [ -f "$TMP/.codex/bin/statusline.js" ] \
1378
1388
  && [ -f "$TMP/.codex/bin/state-ledger.js" ] \
1379
1389
  && [ -f "$TMP/.codex/bin/contract-runner.js" ] \
1390
+ && [ -f "$TMP/.codex/bin/harness-eval.js" ] \
1380
1391
  && [ -f "$TMP/.codex/bin/trust-score.js" ] \
1392
+ && [ -f "$TMP/.codex/bin/work-packet.js" ] \
1381
1393
  && [ -f "$TMP/.codex/bin/project-snapshot.js" ] \
1382
1394
  && [ -f "$TMP/.codex/bin/planning-hygiene.js" ] \
1383
1395
  && [ -f "$TMP/.codex/agents/planner.toml" ] \
@@ -1418,7 +1430,7 @@ fi
1418
1430
 
1419
1431
  # 120. Target=3 (Both) populates both directories with the right artifacts
1420
1432
  TMP=$(mktmp)
1421
- printf 'QS-FAWZI-01\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1433
+ printf 'QS-FAWZI-11\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1422
1434
  EXIT=$?
1423
1435
  if [ "$EXIT" -eq 0 ] \
1424
1436
  && [ -f "$TMP/.claude/.qualia-config.json" ] \
@@ -1437,7 +1449,7 @@ fi
1437
1449
  # 121. Backward compat: legacy single-line piped install (no target line)
1438
1450
  # defaults to Claude only. Same exact invocation as pre-v5.1.
1439
1451
  TMP=$(mktmp)
1440
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1452
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1441
1453
  EXIT=$?
1442
1454
  if [ "$EXIT" -eq 0 ] \
1443
1455
  && [ -f "$TMP/.claude/.qualia-config.json" ] \
@@ -1452,7 +1464,7 @@ fi
1452
1464
  TMP=$(mktmp)
1453
1465
  mkdir -p "$TMP/.codex"
1454
1466
  echo "OLD USER CONTENT" > "$TMP/.codex/AGENTS.md"
1455
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1467
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1456
1468
  EXIT=$?
1457
1469
  BAK_COUNT=$(ls "$TMP/.codex/"AGENTS.md.bak.* 2>/dev/null | wc -l)
1458
1470
  if [ "$EXIT" -eq 0 ] \
@@ -1467,9 +1479,9 @@ fi
1467
1479
  # 123. Codex install with same content does NOT create a redundant .bak
1468
1480
  # (the v5.0 CLAUDE.md backup discipline only backs up if content differs).
1469
1481
  TMP=$(mktmp)
1470
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1482
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1471
1483
  # Re-run with same input — content should be identical, no new backup.
1472
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log2.txt" 2>&1
1484
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log2.txt" 2>&1
1473
1485
  BAK_COUNT=$(ls "$TMP/.codex/"AGENTS.md.bak.* 2>/dev/null | wc -l)
1474
1486
  if [ "$BAK_COUNT" -eq 0 ]; then
1475
1487
  pass "Codex re-install with identical content → no redundant .bak"
@@ -1494,7 +1506,7 @@ cat > "$TMP/.codex/hooks.json" <<'JSON'
1494
1506
  }
1495
1507
  }
1496
1508
  JSON
1497
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1509
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1498
1510
  if grep -q "custom-session-hook.js" "$TMP/.codex/hooks.json" \
1499
1511
  && grep -q "session-start.js" "$TMP/.codex/hooks.json"; then
1500
1512
  pass "Codex hooks.json merge preserves non-Qualia hooks"
@@ -1520,7 +1532,7 @@ cat > "$TMP/.codex/hooks.json" <<'JSON'
1520
1532
  }
1521
1533
  }
1522
1534
  JSON
1523
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1535
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1524
1536
  EXIT=0; HOME="$TMP" $NODE "$CLI_JS" uninstall --yes > "$TMP/uninstall.log" 2>&1 || EXIT=$?
1525
1537
  if [ "$EXIT" -eq 0 ] \
1526
1538
  && [ -f "$TMP/.codex/AGENTS.md" ] \
@@ -1540,7 +1552,7 @@ fi
1540
1552
 
1541
1553
  # 123d. Team management writes to Codex-only installs without creating ~/.claude.
1542
1554
  TMP=$(mktmp)
1543
- printf 'QS-FAWZI-01\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1555
+ printf 'QS-FAWZI-11\n2\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1544
1556
  EXIT=0; HOME="$TMP" $NODE "$CLI_JS" team add --code QS-TEST-99 --name "Test User" > "$TMP/team.log" 2>&1 || EXIT=$?
1545
1557
  if [ "$EXIT" -eq 0 ] \
1546
1558
  && [ -f "$TMP/.codex/.qualia-team.json" ] \
@@ -1555,7 +1567,7 @@ fi
1555
1567
  # sequences (\r, \x1b[?25l/h hide-cursor, \x1b[2K clear-line). Spinner +
1556
1568
  # overwrite primitives must degrade cleanly when output is piped.
1557
1569
  TMP=$(mktmp)
1558
- printf 'QS-FAWZI-01\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1570
+ printf 'QS-FAWZI-11\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1559
1571
  # Look for any of: bare CR, hide-cursor (?25), clear-line (\x1b[2K).
1560
1572
  if [ -s "$TMP/log.txt" ] \
1561
1573
  && ! grep -q $'\r' "$TMP/log.txt" \
@@ -1568,7 +1580,7 @@ fi
1568
1580
 
1569
1581
  # 125. Final summary card includes the new "Targets" + "Time" rows
1570
1582
  TMP=$(mktmp)
1571
- printf 'QS-FAWZI-01\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1583
+ printf 'QS-FAWZI-11\n3\n' | HOME="$TMP" $NODE "$INSTALL_JS" > "$TMP/log.txt" 2>&1
1572
1584
  CLEAN=$(strip_ansi < "$TMP/log.txt")
1573
1585
  if echo "$CLEAN" | grep -q "Targets" \
1574
1586
  && echo "$CLEAN" | grep -q "Claude Code · Codex" \
@@ -1676,7 +1688,7 @@ echo "--- v5.3.0 (Matt Pocock gaps: prd, hook-gen, parallel-interface) ---"
1676
1688
 
1677
1689
  # Re-install for v5.3 assertions (TMP from #99 may have v5.1 state)
1678
1690
  TMP=$(mktmp)
1679
- echo "QS-FAWZI-01" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1691
+ echo "QS-FAWZI-11" | HOME="$TMP" $NODE "$INSTALL_JS" >/dev/null 2>&1
1680
1692
 
1681
1693
  # 135-137. /qualia-prd removed in v5.8.0 (was deprecated, overlapped /qualia-discuss).
1682
1694
  # Assert non-existence so the framework cannot accidentally re-ship it.
@@ -1706,28 +1718,28 @@ else
1706
1718
  fail_case "qualia-feature missing after install"
1707
1719
  fi
1708
1720
 
1709
- # 138. qualia-hook-gen skill installs
1710
- if [ -f "$TMP/.claude/skills/qualia-hook-gen/SKILL.md" ]; then
1711
- pass "qualia-hook-gen skill installs"
1721
+ # 138. qualia-hook-gen is removed from source and retired from default install
1722
+ if [ ! -f "$TMP/.claude/skills/qualia-hook-gen/SKILL.md" ] \
1723
+ && [ ! -d "$FRAMEWORK_DIR/skills/qualia-hook-gen" ]; then
1724
+ pass "qualia-hook-gen removed from source and default install"
1712
1725
  else
1713
- fail_case "qualia-hook-gen SKILL.md missing after install"
1726
+ fail_case "qualia-hook-gen should be absent from source and install"
1714
1727
  fi
1715
1728
 
1716
- # 139. qualia-hook-gen documents the three enforcement patterns (block/rewrite/warn)
1717
- if grep -q "Block" "$TMP/.claude/skills/qualia-hook-gen/SKILL.md" \
1718
- && grep -q "Rewrite" "$TMP/.claude/skills/qualia-hook-gen/SKILL.md" \
1719
- && grep -q "Warn" "$TMP/.claude/skills/qualia-hook-gen/SKILL.md"; then
1720
- pass "qualia-hook-gen documents block/rewrite/warn patterns"
1729
+ # 139. hook generation knowledge moved out of slash-command source
1730
+ if grep -q "proxy_owner_approval_claim" "$FRAMEWORK_DIR/hooks/fawzi-approval-guard.js" \
1731
+ && grep -q "/api/v1/policy-events" "$FRAMEWORK_DIR/hooks/fawzi-approval-guard.js"; then
1732
+ pass "hook enforcement lives in runtime hooks, not qualia-hook-gen"
1721
1733
  else
1722
- fail_case "qualia-hook-gen missing one of block/rewrite/warn patterns"
1734
+ fail_case "runtime hook enforcement guard missing"
1723
1735
  fi
1724
1736
 
1725
- # 140. qualia-hook-gen mandates Node hooks (cross-platform), not .sh scripts
1726
- if grep -q "pure Node\|pure-node\|cross-platform" "$TMP/.claude/skills/qualia-hook-gen/SKILL.md" \
1727
- && grep -q "No \`.sh\`\|No \\.sh\|exit 0/2\|exit 2 to" "$TMP/.claude/skills/qualia-hook-gen/SKILL.md"; then
1728
- pass "qualia-hook-gen mandates pure-Node hooks (cross-platform discipline)"
1737
+ # 140. retired hook-gen behavior remains covered by Node hook files
1738
+ if find "$FRAMEWORK_DIR/hooks" -maxdepth 1 -name "*.js" -print | grep -q . \
1739
+ && ! find "$FRAMEWORK_DIR/hooks" -maxdepth 1 -name "*.sh" -print | grep -q .; then
1740
+ pass "runtime hooks are pure Node files"
1729
1741
  else
1730
- fail_case "qualia-hook-gen missing pure-Node mandate"
1742
+ fail_case "runtime hooks should remain pure Node"
1731
1743
  fi
1732
1744
 
1733
1745
  # 141. qualia-optimize SKILL.md adds Step 5b (parallel-interface design)
@@ -1892,13 +1904,63 @@ else
1892
1904
  fail_case "report-payload UUID pass-through failed" "$OUT"
1893
1905
  fi
1894
1906
 
1907
+ # 148b. work-packet links flow into report payloads
1908
+ TMP_PACKET=$(mktmp)
1909
+ OUT=$(FRAMEWORK_DIR="$FRAMEWORK_DIR" TMP_PACKET="$TMP_PACKET" $NODE <<'NODE' 2>&1
1910
+ const assert = require("assert/strict");
1911
+ const fs = require("fs");
1912
+ const path = require("path");
1913
+ const { buildPayload } = require(path.join(process.env.FRAMEWORK_DIR, "bin", "report-payload.js"));
1914
+ const { readLocalWorkPacket } = require(path.join(process.env.FRAMEWORK_DIR, "bin", "work-packet.js"));
1915
+
1916
+ const root = process.env.TMP_PACKET;
1917
+ const cwd = path.join(root, "project");
1918
+ const home = path.join(root, "home");
1919
+ fs.mkdirSync(path.join(cwd, ".planning"), { recursive: true });
1920
+ fs.mkdirSync(path.join(home, ".claude"), { recursive: true });
1921
+ fs.writeFileSync(path.join(home, ".claude", ".qualia-config.json"), JSON.stringify({ version: "test-version" }));
1922
+ fs.writeFileSync(path.join(cwd, ".planning", "tracking.json"), JSON.stringify({
1923
+ project: "acme-portal",
1924
+ project_id: "qs-acme-portal",
1925
+ erp_project_id: "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
1926
+ phase: 1,
1927
+ status: "built"
1928
+ }));
1929
+ fs.writeFileSync(path.join(cwd, ".planning", "work-packet.json"), JSON.stringify({
1930
+ id: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
1931
+ project_id: "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
1932
+ assignment_id: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
1933
+ deadline_date: "2026-06-01",
1934
+ next_command: "/qualia-verify"
1935
+ }));
1936
+
1937
+ const packet = readLocalWorkPacket(cwd);
1938
+ assert.equal(packet.next_command, "/qualia-verify");
1939
+ const payload = buildPayload({
1940
+ cwd,
1941
+ home,
1942
+ env: { SUBMITTED_BY: "Fawzi Goussous", SUBMITTED_AT: "2026-05-21T01:30:00Z" },
1943
+ });
1944
+ assert.equal(payload.work_packet_id, "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa");
1945
+ assert.equal(payload.assignment_id, "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb");
1946
+ assert.equal(payload.assignment_deadline, "2026-06-01");
1947
+ NODE
1948
+ )
1949
+ EXIT=$?
1950
+ if [ "$EXIT" -eq 0 ]; then
1951
+ pass "work-packet links flow into report payloads"
1952
+ else
1953
+ fail_case "work-packet report payload link failed" "$OUT"
1954
+ fi
1955
+
1895
1956
  # 149. Installer ships the payload builder used by /qualia-report
1896
1957
  TMP_INSTALL=$(mktmp)
1897
- echo "QS-FAWZI-01" | HOME="$TMP_INSTALL" $NODE "$INSTALL_JS" > "$TMP_INSTALL/out.log" 2>&1
1958
+ echo "QS-FAWZI-11" | HOME="$TMP_INSTALL" $NODE "$INSTALL_JS" > "$TMP_INSTALL/out.log" 2>&1
1898
1959
  EXIT=$?
1899
1960
  if [ "$EXIT" -eq 0 ] \
1900
1961
  && [ -f "$TMP_INSTALL/.claude/bin/report-payload.js" ] \
1901
1962
  && [ -f "$TMP_INSTALL/.claude/bin/project-snapshot.js" ] \
1963
+ && [ -f "$TMP_INSTALL/.claude/bin/work-packet.js" ] \
1902
1964
  && grep -q "report-payload.js" "$TMP_INSTALL/.claude/skills/qualia-report/SKILL.md"; then
1903
1965
  pass "installer ships ERP report/snapshot helpers"
1904
1966
  else
@@ -1954,12 +2016,22 @@ fs.writeFileSync(path.join(cwd, ".planning", "tracking.json"), JSON.stringify({
1954
2016
  last_closed_milestone: 1
1955
2017
  }
1956
2018
  }));
2019
+ fs.writeFileSync(path.join(cwd, ".planning", "work-packet.json"), JSON.stringify({
2020
+ id: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
2021
+ project_id: "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
2022
+ assignment_id: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
2023
+ deadline_date: "2026-06-01",
2024
+ next_command: "/qualia-verify"
2025
+ }));
1957
2026
 
1958
2027
  const snapshot = buildSnapshot({ cwd, home, now: "2026-05-21T00:00:00.000Z" });
1959
2028
  assert.equal(snapshot.snapshot_version, 1);
1960
2029
  assert.equal(snapshot.framework_version, "test-version");
1961
2030
  assert.equal(snapshot.identifiers.project_id, "qs-acme-portal");
1962
2031
  assert.equal(snapshot.identifiers.erp_project_id, "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef");
2032
+ assert.equal(snapshot.identifiers.work_packet_id, "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa");
2033
+ assert.equal(snapshot.identifiers.assignment_id, "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb");
2034
+ assert.equal(snapshot.identifiers.assignment_deadline, "2026-06-01");
1963
2035
  assert.equal(snapshot.project.progress_percent, 42);
1964
2036
  assert.equal(snapshot.current.gap_cycles, 1);
1965
2037
  assert.equal(snapshot.journey.total_milestones, 3);
@@ -154,6 +154,46 @@ echo '{"role":""}' > "$TMP/.claude/.qualia-config.json"
154
154
  assert_exit "empty role field → blocked" 2 $?
155
155
  rm -rf "$TMP"
156
156
 
157
+ # --- fawzi-approval-guard.js ---
158
+ echo ""
159
+ echo "fawzi-approval-guard:"
160
+
161
+ TMP=$(mktemp -d)
162
+ mkdir -p "$TMP/.claude"
163
+ cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
164
+ {"code":"QS-HASAN-02","installed_by":"Hasan","role":"EMPLOYEE","erp":{"enabled":false}}
165
+ EOF
166
+ OUT=$(echo '{"tool_input":{"content":"Fawzi said ok, ship it now."}}' | HOME="$TMP" $NODE "$HOOKS_DIR/fawzi-approval-guard.js" 2>&1)
167
+ RC=$?
168
+ if [ "$RC" -eq 0 ] \
169
+ && [ -z "$OUT" ] \
170
+ && [ -f "$TMP/.claude/.approval-policy-events.json" ] \
171
+ && grep -q '"proxy_owner_approval_claim"' "$TMP/.claude/.approval-policy-events.json" \
172
+ && grep -q '"total": 1' "$TMP/.claude/.approval-policy-events.json"; then
173
+ echo " ✓ employee proxy approval claim → silently recorded"
174
+ PASS=$((PASS + 1))
175
+ else
176
+ echo " ✗ employee proxy approval claim record failed (exit=$RC out=$OUT)"
177
+ FAIL=$((FAIL + 1))
178
+ fi
179
+ rm -rf "$TMP"
180
+
181
+ TMP=$(mktemp -d)
182
+ mkdir -p "$TMP/.claude"
183
+ cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
184
+ {"code":"QS-FAWZI-11","installed_by":"Fawzi Goussous","role":"OWNER","erp":{"enabled":false}}
185
+ EOF
186
+ echo '{"tool_input":{"content":"Fawzi said ok, ship it now."}}' | HOME="$TMP" $NODE "$HOOKS_DIR/fawzi-approval-guard.js" >/dev/null 2>&1
187
+ RC=$?
188
+ if [ "$RC" -eq 0 ] && [ ! -f "$TMP/.claude/.approval-policy-events.json" ]; then
189
+ echo " ✓ OWNER phrasing → not recorded as employee violation"
190
+ PASS=$((PASS + 1))
191
+ else
192
+ echo " ✗ OWNER phrasing should not record (exit=$RC)"
193
+ FAIL=$((FAIL + 1))
194
+ fi
195
+ rm -rf "$TMP"
196
+
157
197
  # --- pre-push.js ---
158
198
  echo ""
159
199
  echo "pre-push:"
@@ -184,6 +224,27 @@ rm -rf "$TMP"
184
224
  echo ""
185
225
  echo "pre-deploy-gate:"
186
226
 
227
+ TMP=$(mktemp -d)
228
+ mkdir -p "$TMP/.claude" "$TMP/proj/.planning"
229
+ cat > "$TMP/.claude/.qualia-config.json" <<'EOF'
230
+ {"code":"QS-HASAN-02","installed_by":"Hasan","role":"EMPLOYEE"}
231
+ EOF
232
+ cat > "$TMP/proj/.planning/tracking.json" <<'EOF'
233
+ {"status":"built","verification":"pending","next_command":"/qualia-report"}
234
+ EOF
235
+ OUT=$(cd "$TMP/proj" && echo '{"tool_input":{"command":"QUALIA_SHIP_FORCE=1 vercel --prod"}}' | HOME="$TMP" $NODE "$HOOKS_DIR/pre-deploy-gate.js" 2>&1)
236
+ RC=$?
237
+ if [ "$RC" -eq 2 ] \
238
+ && echo "$OUT" | grep -q "OWNER-only" \
239
+ && echo "$OUT" | grep -q "/qualia-report"; then
240
+ echo " ✓ employee force ship → blocked with short next command"
241
+ PASS=$((PASS + 1))
242
+ else
243
+ echo " ✗ employee force ship block failed (exit=$RC out=$OUT)"
244
+ FAIL=$((FAIL + 1))
245
+ fi
246
+ rm -rf "$TMP"
247
+
187
248
  # Empty project (no package.json, no tsconfig) → nothing to gate → exit 0
188
249
  TMP=$(mktemp -d)
189
250
  (cd "$TMP" && $NODE "$HOOKS_DIR/pre-deploy-gate.js" >/dev/null 2>&1)
@@ -338,6 +399,25 @@ Status: setup
338
399
  EOF
339
400
  (cd "$TMP" && $NODE "$HOOKS_DIR/session-start.js" >/dev/null 2>&1)
340
401
  assert_exit "exits 0 with STATE.md" 0 $?
402
+
403
+ cat > "$TMP/.planning/work-packet.json" <<'EOF'
404
+ {
405
+ "id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
406
+ "project_id": "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
407
+ "deadline_date": "2026-06-01",
408
+ "next_command": "/qualia-verify",
409
+ "project": { "name": "Acme Portal" }
410
+ }
411
+ EOF
412
+ OUT=$(cd "$TMP" && $NODE "$HOOKS_DIR/session-start.js" 2>&1)
413
+ RC=$?
414
+ if [ "$RC" -eq 0 ] && echo "$OUT" | grep -q "Acme Portal" && echo "$OUT" | grep -q "/qualia-verify"; then
415
+ echo " ✓ renders local ERP work packet context"
416
+ PASS=$((PASS + 1))
417
+ else
418
+ echo " ✗ ERP work packet context missing (exit=$RC)"
419
+ FAIL=$((FAIL + 1))
420
+ fi
341
421
  rm -rf "$TMP"
342
422
 
343
423
  # pre-compact.js removed in v6.2.0 — state.js journal provides crash safety.
@@ -348,7 +428,7 @@ echo "auto-update:"
348
428
 
349
429
  TMP=$(mktemp -d)
350
430
  mkdir -p "$TMP/.claude"
351
- echo '{"code":"QS-FAWZI-01","version":"99.99.99"}' > "$TMP/.claude/.qualia-config.json"
431
+ echo '{"code":"QS-FAWZI-11","version":"99.99.99"}' > "$TMP/.claude/.qualia-config.json"
352
432
  HOME="$TMP" $NODE "$HOOKS_DIR/auto-update.js" >/dev/null 2>&1
353
433
  assert_exit "exits 0 (fast path)" 0 $?
354
434
  # Should now have cache file