@codyswann/lisa 3.11.6 → 3.11.7

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 (59) hide show
  1. package/dist/core/upstream-evidence-manifest.js +2 -2
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  4. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  5. package/plugins/lisa/.codex-plugin/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  6. package/plugins/lisa/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  7. package/plugins/lisa-agy/plugin.json +1 -1
  8. package/plugins/lisa-agy/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  9. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  12. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-copilot/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  16. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cursor/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  18. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-expo-agy/plugin.json +1 -1
  21. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  26. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  31. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  36. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  41. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-rails-agy/plugin.json +1 -1
  46. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  51. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  56. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md +18 -3
  59. package/scripts/check-required-check-promotions.mjs +93 -0
@@ -571,7 +571,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
571
571
  "plugins/src/base/skills/lisa-parity-code-review/SKILL.md": "5805254747c4ed9081fd514236f06e078be86d41694bf74b480bf7592cd58c1f",
572
572
  "plugins/src/base/skills/lisa-parity-code-simplifier/SKILL.md": "c721ae772e73abff633c43d93267066afac188e911a77322fbb102db673849d7",
573
573
  "plugins/src/base/skills/lisa-parity-coderabbit/SKILL.md": "ae882837d43741293d1b639c4516331fa6124fa1f5da234a74ecb31c5d7e52cd",
574
- "plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md": "f240857de2f14938009ddd212c56601269fd9e1aec33a766cd09da5bea5656e0",
574
+ "plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md": "4b00da1ced810e8604572a0ae36bbd3188835fce22413fc73a214741973f9255",
575
575
  "plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md": "edb513a9d29b3faeccce71d92596e12bc1f35e44fe3af1349bd7bd473fee98af",
576
576
  "plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md": "ec09515906a55e98ac0f619f048f14c4a16db74c1cd5744dda0cdfa42ce7fed6",
577
577
  "plugins/src/base/skills/lisa-parity-skill-creator/SKILL.md": "616e0493f75fe92c18137548d7c86a91a9b04d9844ca76fa3f14156e3e7814e5",
@@ -1037,7 +1037,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
1037
1037
  "scripts/check-duplicate-versions.mjs": "84d97e94eb834522848ddce951bb54ae9da1e4be252e2c51fed0c01c4f4d6b72",
1038
1038
  "scripts/check-learnings-budget.ts": "007430c2d6938efcc79ccbfd5717ebe2c7cf66b4de9a21a3e67b8db7f3600349",
1039
1039
  "scripts/check-plugins-sync.sh": "3a99cbff0e8ec5e7c944690eae003a6d51b51c85436d77bd37faea4d553728af",
1040
- "scripts/check-required-check-promotions.mjs": "2693787413a276f7493c0fac1407a2e61630b2978d20acebb0ee5463c4678660",
1040
+ "scripts/check-required-check-promotions.mjs": "f644f0feb246f36a79efaa6b820409605c637813e158aea425982b863bb6ed7c",
1041
1041
  "scripts/check-rules-pairing.sh": "4d4a0d9e8d36794a22020f419c879d7336b1c5bfe883acdcc826d26764560c7a",
1042
1042
  "scripts/check-security-floors.mjs": "0060a0f65885b54fc93bd3885ca249cbb1ac822c52813817aae640bc1303827b",
1043
1043
  "scripts/check-state-classification.mjs": "26baaa85c0758fa41f1f66257f7d3a31ea4dd5cf17a9c0acaa3e89caaaf6265a",
package/package.json CHANGED
@@ -122,7 +122,7 @@
122
122
  }
123
123
  },
124
124
  "name": "@codyswann/lisa",
125
- "version": "3.11.6",
125
+ "version": "3.11.7",
126
126
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
127
127
  "main": "dist/index.js",
128
128
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the…"
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the custom guard rules enforced by Lisa's safety-net PreToolUse Bash hook (parity-safety-net.sh). The consolidated cross-agent equivalent of the upstream safety-net plugin's set-custom-rules + verify-custom-rules skills — manages a project-local list of extended-regex patterns that block destructive shell commands, on Codex, agy, Copilot, Cursor, and Claude."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the custom guard rules enforced by Lisa's safety-net PreToolUse Bash hook (parity-safety-net.sh). The consolidated cross-agent equivalent of the upstream safety-net plugin's set-custom-rules + verify-custom-rules skills — manages a project-local list of extended-regex patterns that block destructive shell commands, on Codex, agy, Copilot, Cursor, and Claude."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the custom guard rules enforced by Lisa's safety-net PreToolUse Bash hook (parity-safety-net.sh). The consolidated cross-agent equivalent of the upstream safety-net plugin's set-custom-rules + verify-custom-rules skills — manages a project-local list of extended-regex patterns that block destructive shell commands, on Codex, agy, Copilot, Cursor, and Claude."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the custom guard rules enforced by Lisa's safety-net PreToolUse Bash hook (parity-safety-net.sh). The consolidated cross-agent equivalent of the upstream safety-net plugin's set-custom-rules + verify-custom-rules skills — manages a project-local list of extended-regex patterns that block destructive shell commands, on Codex, agy, Copilot, Cursor, and Claude."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "3.11.6",
3
+ "version": "3.11.7",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -2,7 +2,7 @@
2
2
  name: lisa-parity-safety-net-rules
3
3
  description: "View, set, and verify the custom guard rules enforced by Lisa's safety-net PreToolUse Bash hook (parity-safety-net.sh). The consolidated cross-agent equivalent of the upstream safety-net plugin's set-custom-rules + verify-custom-rules skills — manages a project-local list of extended-regex patterns that block destructive shell commands, on Codex, agy, Copilot, Cursor, and Claude."
4
4
  allowed-tools: ["Read", "Edit", "Write", "Bash"]
5
- synced-from: safety-net@cc-marketplace@2.0.3
5
+ synced-from: safety-net@cc-marketplace@2.0.4
6
6
  ---
7
7
 
8
8
  # Parity Safety-Net Rules
@@ -24,7 +24,7 @@ project-specific rules on top of those built-ins.
24
24
  > against Lisa conventions — it does **not** port or invoke upstream plugin
25
25
  > code.
26
26
  >
27
- > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.3`.
27
+ > **Drift tracking.** Pinned to `safety-net@cc-marketplace@2.0.4`.
28
28
  > `scripts/plugin-parity-drift.mjs` compares this pin against the upstream
29
29
  > version in the plugin cache and flags staleness. **Do not port or copy upstream
30
30
  > plugin code.**
@@ -34,7 +34,22 @@ project-specific rules on top of those built-ins.
34
34
  > rule-management skill or Lisa's project-local ERE rule contract, and Lisa does
35
35
  > not currently ship hooks for those runtimes, so no behavior is absorbed here.
36
36
  >
37
- > **Known gap at the 2.0.3 pin.** Upstream 2.0.0 rebuilt its engine and added two
37
+ > **2.0.4 review.** Method, so the next person can re-run it rather than trust
38
+ > it: hash the sorted (relative path, content) manifest of every rule-bearing
39
+ > directory in the plugin cache under both versions, then diff the trees
40
+ > excluding `dist/`, `.git/`, and `node_modules/`. Result — `src/` (230 files),
41
+ > `skills/` (1), and `hooks/` (1) are byte-identical across 2.0.3 and 2.0.4
42
+ > (`src` digest `7e346e205fbd1aa7` both sides). The only non-generated
43
+ > differences are the `version` string in `package.json`, `kimi.plugin.json`,
44
+ > and `.claude-plugin/plugin.json`, plus a test-harness fix in
45
+ > `tests/cli/cli-statusline.test.ts` that tolerates EPIPE when an oversized
46
+ > payload is flushed at the bounded reader's cap. Everything else is rebuilt
47
+ > `dist/` output. No rule, guard family, or skill surface moved, so nothing is
48
+ > absorbed here — and, critically, **2.0.4 does not close the gap recorded
49
+ > below**, which therefore carries forward unchanged rather than being dropped
50
+ > at the new pin.
51
+ >
52
+ > **Known gap at the 2.0.4 pin.** Upstream 2.0.0 rebuilt its engine and added two
38
53
  > guard families this hook does **not** mirror: `secret.*` (blocks reading or
39
54
  > copying SSH keys, `.env` files, cloud credentials, and coding-CLI credential
40
55
  > stores) and `rm.git-metadata` (blocks deleting the `.git` control plane). Both
@@ -69,6 +69,48 @@
69
69
  * `measured_on_subject` separately makes that mechanically visible instead
70
70
  * of a footnote in a report.
71
71
  *
72
+ * 6. **A worst case must come from a run that COMPLETED, and must be below the
73
+ * budget it justifies** (#2528). Two clauses, one rule:
74
+ *
75
+ * *Do not size a budget from the duration of a run that failed on time.*
76
+ * This is the mirror of clause 3. #2509 says do not size from runs that
77
+ * passed, because the sample excludes the failure mode; the mirror says do
78
+ * not size from the DURATION of a run the budget terminated, because that
79
+ * duration is the starvation, not the work. The failing-run version is
80
+ * strictly worse: it does not merely omit information, it INVERTS the
81
+ * ratio — the more contended the box was, the safer the resulting budget
82
+ * looks. So `observed_on` must say `"pass"`, meaning the measured run
83
+ * completed inside its budget. (That is a statement about TIME, not about
84
+ * the check's verdict: a run that reproduces a real violation and exits 1
85
+ * in 30s completed, and is `"pass"` here.)
86
+ *
87
+ * *And an entry claiming a worst case at or above its own budget refuses
88
+ * itself*, needing no knowledge of the test, the machine, or the workload.
89
+ * #2523 cited 60,245ms while setting the budget to 60,000ms. The ratio in
90
+ * clause 4 already rejects that arithmetically at 0.996x, but it reports a
91
+ * THIN MARGIN when the defect is an IMPOSSIBLE CLAIM, and a message that
92
+ * misnames the defect sends the reader off to re-measure when they should
93
+ * be re-reading. The tell was on the face of the number: a test cannot run
94
+ * 60s against a 10s budget, so 60,245ms was wall clock spent waiting.
95
+ * Re-measured in isolation at load 31 the same test takes 2,499ms — 24x,
96
+ * not 0.996x, a 24-fold error in the unsafe direction.
97
+ *
98
+ * The class is not specific to test timeouts. #2520 chased an actionlint
99
+ * invocation reported as taking "25 minutes". It was not slow: a
100
+ * 3,490-line workflow returns in 0s while a 217-line one hangs, and the
101
+ * minimal repro is 28 lines. It is a spin inside actionlint's shellcheck
102
+ * integration — ~850% CPU across 37 threads, zero children — so it never
103
+ * terminates. The 25 minutes was the observer's patience, not the
104
+ * command's cost, and NO budget would have been generous enough. That is
105
+ * what `observed_on` refuses: a number produced by a run that did not
106
+ * finish is not a measurement of how long the work takes.
107
+ *
108
+ * A missing `observed_on` is refused rather than grandfathered. Every
109
+ * `proven` entry in the ledger when this clause shipped had already
110
+ * recorded, in prose, that its worst case came from runs that completed, so
111
+ * backfilling the field only restates what was already proved. Exempting
112
+ * them would have exempted the only entries the clause could bind on.
113
+ *
72
114
  * ## The ratchet, and why incumbents are not simply exempted
73
115
  *
74
116
  * Contexts already required when this guard shipped may declare
@@ -315,9 +357,47 @@ function budgetProblems(budget) {
315
357
  },
316
358
  ];
317
359
  }
360
+ // A budgets[] entry publishes its OWN observed_worst_ms, so it can be a
361
+ // starved figure exactly as the block-level one can. Checking provenance
362
+ // first: a ratio computed from a duration that measures contention is
363
+ // arithmetic on the wrong number, so the reader needs the provenance before
364
+ // the margin.
365
+ const provenance = provenanceProblems(budget.observed_on);
366
+ if (provenance.length > 0) return provenance;
318
367
  return ratioProblems(budget.budget_ms, budget.observed_worst_ms);
319
368
  }
320
369
 
370
+ /**
371
+ * Validate where an observed worst case was measured (#2528).
372
+ *
373
+ * `observed_on` records whether the run that produced `observed_worst_ms`
374
+ * COMPLETED within its budget (`"pass"`) or was terminated by it (`"fail"`).
375
+ * That is a claim about time, not about the check's verdict — a run that
376
+ * reproduces a real violation and exits 1 well inside its budget completed.
377
+ *
378
+ * @param {unknown} observedOn - the declared provenance.
379
+ * @returns {{ rule: string, detail: string }[]} problems, empty when sound.
380
+ */
381
+ function provenanceProblems(observedOn) {
382
+ if (observedOn === "pass") return [];
383
+ if (observedOn === "fail") {
384
+ return [
385
+ {
386
+ rule: "headroom-measured-on-failing-run",
387
+ detail:
388
+ 'observed_worst_ms was taken from a run the budget terminated ("observed_on": "fail"); that duration is the starvation, not the work, and the more contended the box was the safer the budget looks — re-measure on a run that completed, in isolation',
389
+ },
390
+ ];
391
+ }
392
+ return [
393
+ {
394
+ rule: "headroom-evidence-missing",
395
+ detail:
396
+ 'headroom.observed_on must be "pass": the run that produced observed_worst_ms must have COMPLETED within its budget, because a duration reported alongside a timeout measures contention, not cost',
397
+ },
398
+ ];
399
+ }
400
+
321
401
  /**
322
402
  * Compare an observed worst case against its budget.
323
403
  *
@@ -340,6 +420,17 @@ function ratioProblems(budgetMs, observedMs) {
340
420
  },
341
421
  ];
342
422
  }
423
+ // Checked before the ratio, and reported as its own defect: an entry whose
424
+ // worst case is not below the budget it justifies can never be valid, and
425
+ // "thin margin" would misname it. See clause 6 in the module preamble.
426
+ if (observedMs >= budgetMs) {
427
+ return [
428
+ {
429
+ rule: "headroom-worst-case-exceeds-budget",
430
+ detail: `observed worst ${observedMs}ms is not below the ${budgetMs}ms budget it justifies, so the entry disproves itself; a worst case at or above its own budget is usually elapsed time from a run the budget terminated, which measures contention rather than cost (#2528)`,
431
+ },
432
+ ];
433
+ }
343
434
  const ratio = budgetMs / observedMs;
344
435
  if (ratio < MIN_HEADROOM_RATIO) {
345
436
  return [
@@ -394,6 +485,8 @@ export function headroomProblems(headroom) {
394
485
  }
395
486
  }
396
487
  if (problems.length > 0) return problems;
488
+ problems.push(...provenanceProblems(headroom.observed_on));
489
+ if (problems.length > 0) return problems;
397
490
  problems.push(
398
491
  ...ratioProblems(headroom.budget_ms, headroom.observed_worst_ms)
399
492
  );