@michelj/context-guard 0.4.2 → 0.4.3

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 (72) hide show
  1. package/README.md +74 -6
  2. package/README.zh-CN.md +74 -6
  3. package/{skills/context-guard/SKILL.md → SKILL.md} +216 -77
  4. package/bin/context-guard-skill.js +88 -3
  5. package/hooks.json +25 -1
  6. package/package.json +7 -3
  7. package/{skills/context-guard/references → references}/context-template.md +52 -1
  8. package/references/feature-chain-methodology.md +228 -0
  9. package/{skills/context-guard/scripts → scripts}/context_guard.py +3119 -121
  10. package/{skills/context-guard/scripts → scripts}/context_guard_hook.py +344 -12
  11. package/{skills/context-guard/tests → tests}/BC-20260701-090.sh +8 -7
  12. package/{skills/context-guard/tests → tests}/BC-20260702-096.sh +6 -3
  13. package/tests/BC-20260706-098.sh +66 -0
  14. package/tests/BC-20260707-099.sh +47 -0
  15. package/tests/BC-20260707-100.sh +46 -0
  16. package/tests/BC-20260707-101.sh +47 -0
  17. package/tests/BC-20260707-102.sh +68 -0
  18. package/tests/BC-20260707-103.sh +59 -0
  19. package/tests/BC-20260707-104.sh +103 -0
  20. package/tests/BC-20260707-105.sh +109 -0
  21. package/tests/BC-20260707-106.sh +80 -0
  22. package/tests/BC-20260707-107.sh +74 -0
  23. package/tests/BC-20260707-108.sh +48 -0
  24. package/tests/BC-20260707-109.sh +56 -0
  25. package/tests/BC-20260707-110.sh +71 -0
  26. package/tests/BC-20260707-111.sh +70 -0
  27. package/tests/BC-20260707-112.sh +45 -0
  28. package/tests/BC-20260707-113.sh +73 -0
  29. package/tests/BC-20260707-115.sh +77 -0
  30. package/tests/BC-20260707-116.sh +77 -0
  31. package/tests/BC-20260707-118.sh +115 -0
  32. package/tests/BC-20260707-119.sh +47 -0
  33. package/tests/BC-20260707-120.sh +60 -0
  34. package/tests/BC-20260707-121.sh +66 -0
  35. package/tests/BC-20260707-122.sh +48 -0
  36. package/tests/BC-20260707-123.sh +43 -0
  37. package/tests/BC-20260707-124.sh +56 -0
  38. package/tests/BC-20260707-125.sh +64 -0
  39. package/tests/BC-20260707-126.sh +80 -0
  40. package/tests/BC-20260707-127.sh +88 -0
  41. package/tests/BC-20260707-129.sh +59 -0
  42. package/tests/BC-20260707-130.sh +69 -0
  43. package/tests/BC-20260707-131.sh +140 -0
  44. package/tests/BC-20260707-132.sh +150 -0
  45. package/tests/BC-20260707-133.sh +70 -0
  46. package/tests/BC-20260708-136.sh +210 -0
  47. package/tests/BC-20260708-137.sh +106 -0
  48. package/tests/BC-20260708-138.sh +168 -0
  49. package/tests/BC-20260708-139.sh +79 -0
  50. package/tests/BC-20260709-002.sh +63 -0
  51. package/tests/BC-20260709-003.sh +239 -0
  52. package/tests/BC-20260709-006.sh +76 -0
  53. package/tests/BC-20260709-008.sh +168 -0
  54. package/tests/BC-20260710-001.sh +61 -0
  55. package/tests/BC-20260710-002.sh +111 -0
  56. package/tests/npm-install-smoke.sh +53 -0
  57. package/skills/context-guard/README.md +0 -234
  58. package/skills/context-guard/README.zh-CN.md +0 -234
  59. /package/{skills/context-guard/agents → agents}/openai.yaml +0 -0
  60. /package/{skills/context-guard/references → references}/register-template.md +0 -0
  61. /package/{skills/context-guard/references → references}/task-case-template.md +0 -0
  62. /package/{skills/context-guard/tests → tests}/BC-20260618-063.sh +0 -0
  63. /package/{skills/context-guard/tests → tests}/BC-20260618-065.sh +0 -0
  64. /package/{skills/context-guard/tests → tests}/BC-20260626-080.sh +0 -0
  65. /package/{skills/context-guard/tests → tests}/BC-20260626-081.sh +0 -0
  66. /package/{skills/context-guard/tests → tests}/BC-20260626-082.sh +0 -0
  67. /package/{skills/context-guard/tests → tests}/BC-20260626-083.sh +0 -0
  68. /package/{skills/context-guard/tests → tests}/BC-20260627-084.sh +0 -0
  69. /package/{skills/context-guard/tests → tests}/BC-20260630-086.sh +0 -0
  70. /package/{skills/context-guard/tests → tests}/BC-20260630-087.sh +0 -0
  71. /package/{skills/context-guard/tests → tests}/BC-20260630-088.sh +0 -0
  72. /package/{skills/context-guard/tests → tests}/BC-20260630-089.sh +0 -0
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-test-hub-feature-policy-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+ python3 "$SCRIPT" show-test-hub --root "$ROOT" >"$OUT"
11
+ HTML_PATH="$(tail -1 "$OUT")"
12
+ if grep -q "检查点策略" "$HTML_PATH"; then
13
+ cat "$HTML_PATH"
14
+ exit 1
15
+ fi
16
+
17
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
18
+ --root "$ROOT" \
19
+ --title "GPU 监控按钮" \
20
+ --entry "点击 GPU 监控按钮" \
21
+ --exit-check "打开包含有效 grafana_url 的监控页")"
22
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
23
+
24
+ python3 "$SCRIPT" feature-chain-attach-bc \
25
+ --root "$ROOT" \
26
+ --chain-id "$CHAIN_ID" \
27
+ --node-title "后端返回监控 URL" \
28
+ --bad-case "BC-20260707-109" \
29
+ --check "grafana_url 不为空" >/dev/null
30
+
31
+ python3 "$SCRIPT" feature-chain-attach-bc \
32
+ --root "$ROOT" \
33
+ --chain-id "$CHAIN_ID" \
34
+ --node-title "前端打开监控页" \
35
+ --bad-case "BC-20260707-109" \
36
+ --check "点击后进入监控页" >/dev/null
37
+
38
+ python3 "$SCRIPT" feature-chain-set-checkpoint \
39
+ --root "$ROOT" \
40
+ --chain-id "$CHAIN_ID" \
41
+ --node-title "前端打开监控页" \
42
+ --required optional \
43
+ --reason "浏览器环境才运行" >/dev/null
44
+
45
+ python3 "$SCRIPT" feature-chain-approve \
46
+ --root "$ROOT" \
47
+ --chain-id "$CHAIN_ID" \
48
+ --command-text "printf 'CG_CHECKPOINT:后端返回监控 URL:PASS\n'" >/dev/null
49
+
50
+ python3 "$SCRIPT" show-test-hub --root "$ROOT" >"$OUT"
51
+ HTML_PATH="$(tail -1 "$OUT")"
52
+
53
+ grep -q "检查点策略:1 必跑 / 1 可选" "$HTML_PATH"
54
+ grep -q "后端返回监控 URL" "$HTML_PATH"
55
+ grep -q "前端打开监控页" "$HTML_PATH"
56
+ grep -q "浏览器环境才运行" "$HTML_PATH"
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SKILL_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ SCRIPT="$SKILL_ROOT/scripts/context_guard.py"
6
+ HOOK="$SKILL_ROOT/scripts/context_guard_hook.py"
7
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-summary-XXXXXX")"
8
+ trap 'rm -rf "$ROOT"' EXIT
9
+ OUT="$ROOT/out.txt"
10
+
11
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
12
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
13
+ --root "$ROOT" \
14
+ --title "GPU 监控按钮" \
15
+ --entry "点击 GPU 监控按钮" \
16
+ --exit-check "打开包含有效 grafana_url 的监控页")"
17
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
18
+
19
+ python3 "$SCRIPT" feature-chain-attach-bc \
20
+ --root "$ROOT" \
21
+ --chain-id "$CHAIN_ID" \
22
+ --node-title "后端返回监控 URL" \
23
+ --bad-case "BC-20260707-110" \
24
+ --check "grafana_url 不为空" >/dev/null
25
+
26
+ python3 "$SCRIPT" feature-chain-attach-bc \
27
+ --root "$ROOT" \
28
+ --chain-id "$CHAIN_ID" \
29
+ --node-title "前端打开监控页" \
30
+ --bad-case "BC-20260707-110" \
31
+ --check "点击后进入监控页" >/dev/null
32
+
33
+ python3 - "$ROOT/.codex/context/test-hub/feature-chains.json" "$CHAIN_ID" <<'PY'
34
+ from pathlib import Path
35
+ import json
36
+ import sys
37
+ path = Path(sys.argv[1])
38
+ chain_id = sys.argv[2]
39
+ data = json.loads(path.read_text(encoding="utf-8"))
40
+ chain = next(item for item in data["chains"] if item["id"] == chain_id)
41
+ chain["status"] = "approved"
42
+ chain["type"] = "command"
43
+ chain["command"] = "printf 'CG_CHECKPOINT:后端返回监控 URL:PASS\\n'"
44
+ path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
45
+ PY
46
+
47
+ if python3 "$SCRIPT" dev-complete --root "$ROOT" >"$OUT" 2>&1; then
48
+ cat "$OUT"
49
+ exit 1
50
+ fi
51
+
52
+ grep -q "missing checkpoint marker: 前端打开监控页" "$OUT"
53
+ grep -q "\\[log: " "$OUT"
54
+
55
+ PYTHONPATH="$SKILL_ROOT/scripts" python3 - "$ROOT" "$HOOK" <<'PY'
56
+ from pathlib import Path
57
+ import importlib.util
58
+ import sys
59
+
60
+ root = Path(sys.argv[1])
61
+ hook_path = Path(sys.argv[2])
62
+ spec = importlib.util.spec_from_file_location("context_guard_hook", hook_path)
63
+ module = importlib.util.module_from_spec(spec)
64
+ assert spec.loader is not None
65
+ spec.loader.exec_module(module)
66
+
67
+ details = module.completion_test_failure_details(root)
68
+ assert "failed: GPU 监控按钮" in details
69
+ assert "missing checkpoint marker: 前端打开监控页" in details
70
+ assert "test-hub/runs/" in details
71
+ PY
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-coverage-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
11
+ # Bad Case Register
12
+
13
+ ### BC-20260707-111: GPU 监控按钮没有打开
14
+
15
+ - Status: resolved
16
+ - Tags: #gpu #ui
17
+ - Display summary: 点击 GPU 监控后没有进入监控页。
18
+
19
+ ### BC-20260707-112: 后端没有返回 grafana URL
20
+
21
+ - Status: resolved
22
+ - Tags: #gpu #backend
23
+ - Display summary: job payload 里缺少 grafana_url。
24
+
25
+ ### BC-20260707-113: Worker keepalive 丢失
26
+
27
+ - Status: resolved
28
+ - Tags: #worker #lifecycle
29
+ - Display summary: 空闲 worker 没有进入 keepalive_running。
30
+ MD
31
+
32
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
33
+ --root "$ROOT" \
34
+ --title "GPU 监控按钮" \
35
+ --entry "点击 GPU 监控按钮" \
36
+ --exit-check "打开包含有效 grafana_url 的监控页")"
37
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
38
+
39
+ python3 "$SCRIPT" feature-chain-attach-bc \
40
+ --root "$ROOT" \
41
+ --chain-id "$CHAIN_ID" \
42
+ --node-title "后端返回监控 URL" \
43
+ --bad-case "BC-20260707-112" \
44
+ --check "grafana_url 不为空" >/dev/null
45
+
46
+ python3 "$SCRIPT" feature-chain-attach-bc \
47
+ --root "$ROOT" \
48
+ --chain-id "$CHAIN_ID" \
49
+ --node-title "前端打开监控页" \
50
+ --bad-case "BC-20260707-111" \
51
+ --check "点击后进入监控页" >/dev/null
52
+
53
+ BEFORE="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
54
+ python3 "$SCRIPT" feature-chain-coverage --root "$ROOT" >"$OUT"
55
+ AFTER="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
56
+
57
+ grep -q "feature chains: 1" "$OUT"
58
+ grep -q "bad cases in register: 3" "$OUT"
59
+ grep -q "covered by feature chains: 2" "$OUT"
60
+ grep -q "unassigned candidates: 1" "$OUT"
61
+ grep -q "BC-20260707-113" "$OUT"
62
+ if grep -q "BC-20260707-111" "$OUT" && grep -q "candidate: BC-20260707-111" "$OUT"; then
63
+ cat "$OUT"
64
+ exit 1
65
+ fi
66
+ test "$BEFORE" = "$AFTER"
67
+
68
+ python3 "$SCRIPT" feature-chain-coverage --root "$ROOT" --verbose >"$OUT"
69
+ grep -q "checkpoint: 后端返回监控 URL | covers: BC-20260707-112" "$OUT"
70
+ grep -q "checkpoint: 前端打开监控页 | covers: BC-20260707-111" "$OUT"
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-bc-query-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
11
+ # Bad Case Register
12
+
13
+ ### BC-20260707-112: GPU 监控点击没有打开页面
14
+
15
+ - Status: resolved
16
+ - Tags: #gpu #grafana #ui
17
+ - Display summary: 点击 GPU 监控按钮后,前端没有打开包含 grafana_url 的监控页。
18
+ - Phenomenon: 用户点击 GPU 监控后页面卡住,或者跳转 URL 为空。
19
+ - Trigger / reproduction: job payload 缺少 grafana_url,前端仍把它当成可打开的监控入口。
20
+ - Root cause: 前端把 job 数据当成 GPU URL 的唯一来源,没有检查后端返回值是否有效。
21
+ MD
22
+
23
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
24
+ --root "$ROOT" \
25
+ --title "GPU 监控按钮" \
26
+ --entry "点击 GPU 监控按钮" \
27
+ --exit-check "打开包含有效 grafana_url 的监控页")"
28
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
29
+
30
+ python3 "$SCRIPT" feature-chain-attach-bc \
31
+ --root "$ROOT" \
32
+ --chain-id "$CHAIN_ID" \
33
+ --node-title "前端打开 Grafana 监控页" \
34
+ --bad-case "BC-20260707-000" \
35
+ --check "点击后进入 grafana_url 页面" >/dev/null
36
+
37
+ BEFORE="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
38
+ python3 "$SCRIPT" feature-chain-suggest --root "$ROOT" --query "BC-20260707-112" >"$OUT"
39
+ AFTER="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
40
+
41
+ grep -q "query expanded from bad-case register: BC-20260707-112 GPU 监控点击没有打开页面" "$OUT"
42
+ grep -q "$CHAIN_ID" "$OUT"
43
+ grep -q "GPU 监控按钮" "$OUT"
44
+ grep -q "checkpoint candidate: 前端打开 Grafana 监控页" "$OUT"
45
+ test "$BEFORE" = "$AFTER"
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-coverage-suggest-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
11
+ # Bad Case Register
12
+
13
+ ### BC-20260707-113: GPU 监控点击没有打开 Grafana 页面
14
+
15
+ - Status: resolved
16
+ - Tags: #gpu #grafana #ui
17
+ - Display summary: 点击 GPU 监控按钮后,前端没有打开包含 grafana_url 的监控页。
18
+ - Phenomenon: 用户点击 GPU 监控后页面卡住,或者跳转 URL 为空。
19
+ - Trigger / reproduction: job payload 缺少 grafana_url,前端仍把它当成可打开的监控入口。
20
+
21
+ ### BC-20260707-114: 后端返回监控 URL 为空
22
+
23
+ - Status: resolved
24
+ - Tags: #gpu #backend
25
+ - Display summary: 后端没有给 GPU 监控按钮返回 grafana_url。
26
+
27
+ ### BC-20260707-115: Worker keepalive 状态丢失
28
+
29
+ - Status: resolved
30
+ - Tags: #worker #lifecycle
31
+ - Display summary: 空闲 worker 没有进入 keepalive_running。
32
+ MD
33
+
34
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
35
+ --root "$ROOT" \
36
+ --title "GPU 监控按钮" \
37
+ --entry "点击 GPU 监控按钮" \
38
+ --exit-check "打开包含有效 grafana_url 的 Grafana 监控页")"
39
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
40
+
41
+ python3 "$SCRIPT" feature-chain-attach-bc \
42
+ --root "$ROOT" \
43
+ --chain-id "$CHAIN_ID" \
44
+ --node-title "后端返回监控 URL" \
45
+ --bad-case "BC-20260707-114" \
46
+ --check "grafana_url 不为空" >/dev/null
47
+
48
+ python3 "$SCRIPT" feature-chain-attach-bc \
49
+ --root "$ROOT" \
50
+ --chain-id "$CHAIN_ID" \
51
+ --node-title "前端打开 Grafana 监控页" \
52
+ --bad-case "BC-20260707-000" \
53
+ --check "点击后进入 grafana_url 页面" >/dev/null
54
+
55
+ BEFORE="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
56
+ python3 "$SCRIPT" feature-chain-coverage --root "$ROOT" >"$OUT"
57
+ AFTER="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
58
+
59
+ grep -q "covered by feature chains: 1" "$OUT"
60
+ grep -q "unassigned candidates: 2" "$OUT"
61
+ grep -q "candidate: BC-20260707-113 | GPU 监控点击没有打开 Grafana 页面" "$OUT"
62
+ grep -q "possible chain: $CHAIN_ID" "$OUT"
63
+ grep -q "possible checkpoint: 前端打开 Grafana 监控页" "$OUT"
64
+ grep -q "match evidence:" "$OUT"
65
+ grep -q "grafana" "$OUT"
66
+ grep -q "candidate: BC-20260707-115 | Worker keepalive 状态丢失" "$OUT"
67
+ if awk '/candidate: BC-20260707-115/{flag=1; next} flag && /possible chain/{exit 1} flag && /registry:/{exit 0}' "$OUT"; then
68
+ :
69
+ else
70
+ cat "$OUT"
71
+ exit 1
72
+ fi
73
+ test "$BEFORE" = "$AFTER"
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-plan-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ STRONG_OUT="$ROOT/strong.txt"
8
+ WEAK_OUT="$ROOT/weak.txt"
9
+
10
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
11
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
12
+ # Bad Case Register
13
+
14
+ ### BC-20260707-115: GPU 监控点击没有打开 Grafana 页面
15
+
16
+ - Status: resolved
17
+ - Tags: #gpu #grafana #ui
18
+ - Display summary: 点击 GPU 监控按钮后,前端没有打开包含 grafana_url 的监控页。
19
+ - Phenomenon: 用户点击 GPU 监控后页面卡住,或者跳转 URL 为空。
20
+ - Trigger / reproduction: job payload 缺少 grafana_url,前端仍把它当成可打开的监控入口。
21
+
22
+ ### BC-20260707-116: Worker keepalive 状态丢失
23
+
24
+ - Status: resolved
25
+ - Tags: #worker #lifecycle
26
+ - Display summary: 空闲 worker 没有进入 keepalive_running。
27
+ MD
28
+
29
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
30
+ --root "$ROOT" \
31
+ --title "GPU 监控按钮" \
32
+ --entry "点击 GPU 监控按钮" \
33
+ --exit-check "打开包含有效 grafana_url 的 Grafana 监控页")"
34
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
35
+
36
+ python3 "$SCRIPT" feature-chain-attach-bc \
37
+ --root "$ROOT" \
38
+ --chain-id "$CHAIN_ID" \
39
+ --node-title "前端打开 Grafana 监控页" \
40
+ --bad-case "BC-20260707-115" \
41
+ --check "点击后进入 grafana_url 页面" >/dev/null
42
+
43
+ BEFORE="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
44
+ python3 "$SCRIPT" feature-chain-plan --root "$ROOT" --query "BC-20260707-115" >"$STRONG_OUT"
45
+ python3 "$SCRIPT" feature-chain-plan --root "$ROOT" --query "BC-20260707-116" >"$WEAK_OUT"
46
+ AFTER="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
47
+
48
+ grep -q "action: review-existing-chain" "$STRONG_OUT"
49
+ grep -q "chain: $CHAIN_ID" "$STRONG_OUT"
50
+ grep -q "checkpoint: 前端打开 Grafana 监控页" "$STRONG_OUT"
51
+ grep -q "match evidence:" "$STRONG_OUT"
52
+ grep -q "after-confirmation command: .*feature-chain-attach-bc" "$STRONG_OUT"
53
+ grep -q -- "--bad-case BC-20260707-115" "$STRONG_OUT"
54
+ grep -q "tighten checkpoint based on confirmed symptom" "$STRONG_OUT"
55
+ grep -q "next: if the user confirms the match" "$STRONG_OUT"
56
+
57
+ grep -q "action: propose-new-chain" "$WEAK_OUT"
58
+ grep -q "confirmation prompt: 测试创建识别" "$WEAK_OUT"
59
+ grep -q "Worker keepalive 状态丢失" "$WEAK_OUT"
60
+ grep -q "after-confirmation command: .*feature-chain-propose" "$WEAK_OUT"
61
+ grep -q "confirmed feature title" "$WEAK_OUT"
62
+ grep -q -- "--node-title 'Worker keepalive 状态丢失'" "$WEAK_OUT"
63
+ grep -q -- "--bad-cases BC-20260707-116" "$WEAK_OUT"
64
+ if grep -q "after-confirmation command: .*feature-chain-add" "$WEAK_OUT"; then
65
+ cat "$WEAK_OUT"
66
+ exit 1
67
+ fi
68
+ if grep -q "从「BC-20260707-116」相关入口" "$WEAK_OUT"; then
69
+ cat "$WEAK_OUT"
70
+ exit 1
71
+ fi
72
+ if grep -q "action: review-existing-chain" "$WEAK_OUT"; then
73
+ cat "$WEAK_OUT"
74
+ exit 1
75
+ fi
76
+
77
+ test "$BEFORE" = "$AFTER"
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-candidates-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+ cat >"$ROOT/.codex/context/bad-cases.md" <<'MD'
11
+ # Bad Case Register
12
+
13
+ ### BC-20260707-116: Roadmap 卡片标题看不懂
14
+
15
+ - Status: resolved
16
+ - Tags: #roadmap-ux #readability
17
+ - Display summary: 路线图卡片标题像实现日志,不像用户任务。
18
+
19
+ ### BC-20260707-117: Roadmap 详情页太啰嗦
20
+
21
+ - Status: resolved
22
+ - Tags: #roadmap-ux #readability
23
+ - Display summary: 点击节点后看到太多字段,无法快速理解任务。
24
+
25
+ ### BC-20260707-118: Context 没有在新会话恢复
26
+
27
+ - Status: resolved
28
+ - Tags: #context-loss
29
+ - Display summary: 新会话不知道之前已经讨论过的路线。
30
+
31
+ ### BC-20260707-119: Context 写到远程服务器路径
32
+
33
+ - Status: resolved
34
+ - Tags: #context-loss #remote
35
+ - Display summary: SSH 开发时 context 被写到远程路径。
36
+
37
+ ### BC-20260707-120: 已覆盖的 roadmap 旧问题
38
+
39
+ - Status: resolved
40
+ - Tags: #roadmap-ux
41
+ - Display summary: 已经挂到功能链的旧路线图问题。
42
+ MD
43
+
44
+ ADD_OUTPUT="$(python3 "$SCRIPT" feature-chain-add \
45
+ --root "$ROOT" \
46
+ --title "路线图展示体验" \
47
+ --entry "打开 roadmap.html" \
48
+ --exit-check "用户能快速看懂路线图节点")"
49
+ CHAIN_ID="$(printf '%s\n' "$ADD_OUTPUT" | sed -n 's/.*feature chain: //p')"
50
+ python3 "$SCRIPT" feature-chain-attach-bc \
51
+ --root "$ROOT" \
52
+ --chain-id "$CHAIN_ID" \
53
+ --node-title "路线图卡片可读" \
54
+ --bad-case "BC-20260707-120" \
55
+ --check "卡片标题能直接说明任务" >/dev/null
56
+
57
+ BEFORE="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
58
+ python3 "$SCRIPT" feature-chain-candidates --root "$ROOT" --min-cases 2 >"$OUT"
59
+ AFTER="$(cat "$ROOT/.codex/context/test-hub/feature-chains.json")"
60
+
61
+ grep -q "feature-chain candidates" "$OUT"
62
+ grep -q "candidate chain: 路线图展示体验 / 可读性 | 2 unassigned bad cases | new coverage: 2 | tags: #roadmap-ux, #readability" "$OUT"
63
+ grep -q "candidate chain: Context 持久化 | 2 unassigned bad cases | new coverage: 2 | tags: #context-loss" "$OUT"
64
+ grep -q "confirmation prompt: 测试创建识别" "$OUT"
65
+ grep -q "BC-20260707-116" "$OUT"
66
+ grep -q "BC-20260707-117" "$OUT"
67
+ grep -q "BC-20260707-118" "$OUT"
68
+ grep -q "BC-20260707-119" "$OUT"
69
+ if grep -q "BC-20260707-120" "$OUT"; then
70
+ cat "$OUT"
71
+ exit 1
72
+ fi
73
+ if grep -q "candidate chain: 路线图展示体验 | 2 unassigned bad cases | tags: #roadmap-ux" "$OUT"; then
74
+ cat "$OUT"
75
+ exit 1
76
+ fi
77
+ test "$BEFORE" = "$AFTER"
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py}"
5
+ ROOT_FAIL="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-closed-loop-fail-XXXXXX")"
6
+ ROOT_PASS="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-closed-loop-pass-XXXXXX")"
7
+ trap 'rm -rf "$ROOT_FAIL" "$ROOT_PASS"' EXIT
8
+ OUT="$ROOT_FAIL/out.txt"
9
+
10
+ create_chain() {
11
+ local root="$1"
12
+ local command_text="$2"
13
+ local mode="${3:-approve}"
14
+ python3 "$SCRIPT" init --root "$root" >/dev/null
15
+ local add_output
16
+ add_output="$(python3 "$SCRIPT" feature-chain-add \
17
+ --root "$root" \
18
+ --title "Markdown 公式预览" \
19
+ --entry "输入包含单行、多行和矩阵公式的 Markdown" \
20
+ --exit-check "预览区完成 MathJax 渲染且没有空白或错误占位")"
21
+ local chain_id
22
+ chain_id="$(printf '%s\n' "$add_output" | sed -n 's/.*feature chain: //p')"
23
+ test -n "$chain_id"
24
+
25
+ python3 "$SCRIPT" feature-chain-attach-bc \
26
+ --root "$root" \
27
+ --chain-id "$chain_id" \
28
+ --node-title "公式输入进入预览流程" \
29
+ --bad-case "BC-20260707-118-input" \
30
+ --check "单行、多行和矩阵公式都进入同一预览流程" >/dev/null
31
+
32
+ python3 "$SCRIPT" feature-chain-attach-bc \
33
+ --root "$root" \
34
+ --chain-id "$chain_id" \
35
+ --node-title "MathJax 渲染完成" \
36
+ --bad-case "BC-20260707-118-render" \
37
+ --check "预览区展示渲染后的公式且没有空白或错误占位" >/dev/null
38
+
39
+ if [[ "$mode" == "direct-approved" ]]; then
40
+ python3 - "$root/.codex/context/test-hub/feature-chains.json" "$chain_id" "$command_text" <<'PY'
41
+ from pathlib import Path
42
+ import json
43
+ import sys
44
+ path = Path(sys.argv[1])
45
+ chain_id = sys.argv[2]
46
+ command = sys.argv[3]
47
+ data = json.loads(path.read_text(encoding="utf-8"))
48
+ chain = next(item for item in data["chains"] if item["id"] == chain_id)
49
+ chain["status"] = "approved"
50
+ chain["type"] = "command"
51
+ chain["command"] = command
52
+ path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
53
+ PY
54
+ else
55
+ python3 "$SCRIPT" feature-chain-approve \
56
+ --root "$root" \
57
+ --chain-id "$chain_id" \
58
+ --command-text "$command_text" >/dev/null
59
+ fi
60
+
61
+ python3 "$SCRIPT" validate-feature-chains --root "$root" | grep -q "feature-chain validation passed"
62
+ }
63
+
64
+ FAIL_COMMAND='printf "CG_CHECKPOINT:公式输入进入预览流程:PASS\nCG_CHECKPOINT:MathJax 渲染完成:FAIL:预览区为空\n"; printf "render empty\n" > "$CONTEXT_GUARD_TEST_RUN_DIR/render-diagnostic.txt"'
65
+ create_chain "$ROOT_FAIL" "$FAIL_COMMAND" direct-approved
66
+
67
+ if python3 "$SCRIPT" dev-complete --root "$ROOT_FAIL" >"$OUT" 2>&1; then
68
+ cat "$OUT"
69
+ exit 1
70
+ fi
71
+ grep -q "0 passed, 1 failed, 0 blocked" "$OUT"
72
+ grep -q "checkpoint failed: MathJax 渲染完成 - 预览区为空" "$OUT"
73
+ grep -q "evidence preserved" "$OUT"
74
+
75
+ python3 - "$ROOT_FAIL/.codex/context/test-hub/last-run.json" <<'PY'
76
+ from pathlib import Path
77
+ import json
78
+ import sys
79
+
80
+ run = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
81
+ result = run["results"][0]
82
+ assert result["status"] == "failed"
83
+ assert result["reason"] == "checkpoint failed: MathJax 渲染完成 - 预览区为空"
84
+ assert [item["label"] for item in result["checkpoints"]] == ["公式输入进入预览流程", "MathJax 渲染完成"]
85
+ log_path = Path(result["log"])
86
+ run_dir = log_path.parent
87
+ assert run_dir.exists(), run_dir
88
+ assert (run_dir / "render-diagnostic.txt").exists()
89
+ PY
90
+
91
+ PASS_COMMAND='tmp=.codex/context/test-hub/feature-chain-closed-loop.tmp; printf "CG_CHECKPOINT:公式输入进入预览流程:PASS\nCG_CHECKPOINT:MathJax 渲染完成:PASS\n" > "$tmp"; cat "$tmp"; rm -f "$tmp"'
92
+ create_chain "$ROOT_PASS" "$PASS_COMMAND"
93
+
94
+ python3 "$SCRIPT" dev-complete --root "$ROOT_PASS" >"$OUT"
95
+ grep -q "1 passed, 0 failed, 0 blocked" "$OUT"
96
+ grep -q "success artifacts cleaned" "$OUT"
97
+ test ! -e "$ROOT_PASS/.codex/context/test-hub/feature-chain-closed-loop.tmp"
98
+ if find "$ROOT_PASS/.codex/context/test-hub/runs" -mindepth 1 -maxdepth 1 2>/dev/null | grep -q .; then
99
+ find "$ROOT_PASS/.codex/context/test-hub/runs" -mindepth 1 -maxdepth 1
100
+ exit 1
101
+ fi
102
+
103
+ python3 - "$ROOT_PASS/.codex/context/test-hub/feature-chains.json" "$ROOT_PASS/.codex/context/test-hub/last-run.json" <<'PY'
104
+ from pathlib import Path
105
+ import json
106
+ import sys
107
+
108
+ registry = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
109
+ chain = registry["chains"][0]
110
+ covered = sorted(bc for node in chain["nodes"] for bc in node["bad_cases"])
111
+ assert covered == ["BC-20260707-118-input", "BC-20260707-118-render"]
112
+ result = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))["results"][0]
113
+ assert result["status"] == "passed"
114
+ assert result["missing_checkpoints"] == []
115
+ PY
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/scripts/context_guard.py}"
5
+ ROOT="$(mktemp -d "${TMPDIR:-/tmp}/context-guard-feature-chain-propose-XXXXXX")"
6
+ trap 'rm -rf "$ROOT"' EXIT
7
+ OUT="$ROOT/out.txt"
8
+
9
+ python3 "$SCRIPT" init --root "$ROOT" >/dev/null
10
+
11
+ python3 "$SCRIPT" feature-chain-propose \
12
+ --root "$ROOT" \
13
+ --title "路线图节点阅读" \
14
+ --entry "用户点击路线图节点" \
15
+ --exit-check "节点详情页用自然语言展示用户问题、相关 bad case、方法和进度" \
16
+ --node-title "节点详情可读" \
17
+ --bad-cases "BC-20260707-119-title, BC-20260707-119-detail" \
18
+ --check "详情页能一眼看懂节点对应任务" >"$OUT"
19
+
20
+ grep -q "feature chain proposed:" "$OUT"
21
+ grep -q "status: proposed; this chain is not executable and will not run in dev-complete" "$OUT"
22
+ grep -q "checkpoint: 节点详情可读 | covers BC-20260707-119-title, BC-20260707-119-detail" "$OUT"
23
+ grep -q "next: after the user confirms the automation" "$OUT"
24
+
25
+ python3 "$SCRIPT" validate-feature-chains --root "$ROOT" >"$OUT"
26
+ grep -q "feature-chain validation passed: 1 chain(s), 0 warning(s)" "$OUT"
27
+
28
+ python3 "$SCRIPT" dev-complete --root "$ROOT" >"$OUT"
29
+ grep -q "test hub: no approved every-dev-completion tests" "$OUT"
30
+
31
+ python3 - "$ROOT/.codex/context/test-hub/feature-chains.json" <<'PY'
32
+ from pathlib import Path
33
+ import json
34
+ import sys
35
+
36
+ registry = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
37
+ chain = registry["chains"][0]
38
+ assert chain["status"] == "proposed"
39
+ assert chain["type"] == "manual"
40
+ assert chain["command"] == ""
41
+ assert chain["run_policy"] == "every-dev-completion"
42
+ assert chain["proposal_note"].startswith("Human-confirmed draft only")
43
+ node = chain["nodes"][0]
44
+ assert node["title"] == "节点详情可读"
45
+ assert node["bad_cases"] == ["BC-20260707-119-title", "BC-20260707-119-detail"]
46
+ assert node["checks"] == ["详情页能一眼看懂节点对应任务"]
47
+ PY