riskrails 3.0.1 → 3.1.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 (62) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +28 -15
  5. package/ai/policies/model-routing.md +7 -7
  6. package/ai/policies/production.md +3 -3
  7. package/ai/policies/release.md +2 -2
  8. package/ai/policies/review-economy.md +27 -30
  9. package/bin/riskrails.js +5 -5
  10. package/hooks/context-guard.py +1 -1
  11. package/hooks/guard/common.py +2 -0
  12. package/hooks/guard/paths.py +41 -30
  13. package/hooks/project-scaffold.py +1 -5
  14. package/hooks/runtime-gate.py +6 -6
  15. package/hooks/update_notice.py +20 -14
  16. package/instructions/routing.md +1 -1
  17. package/instructions/stub.md +3 -3
  18. package/package.json +1 -1
  19. package/skills/AGENTS.md +1 -1
  20. package/skills/CLAUDE.md +1 -1
  21. package/skills/ai-init/templates/.ai/AGENTS.md +1 -1
  22. package/skills/ai-init/templates/.ai/VERSION +1 -1
  23. package/skills/ai-init/templates/.ai/policies/security.md +7 -1
  24. package/skills/ai-init/templates/.ai/policies/testing.md +19 -6
  25. package/skills/ai-init/templates/AGENTS.block.md +2 -2
  26. package/skills/ai-init/templates/CLAUDE.block.md +2 -2
  27. package/skills/ai-init/templates/GEMINI.block.md +2 -2
  28. package/skills/ai-init/templates/gitignore.snippet +1 -0
  29. package/skills/ai-init/templates/junie-guidelines.block.md +2 -2
  30. package/skills/ai-task/sensors.py +24 -4
  31. package/skills/ai-task/state.py +37 -14
  32. package/skills/project-init/templates/constitution.md +1 -1
  33. package/skills/project-init/templates/sdlc-README.md +20 -14
  34. package/skills/project-update/history/blobs/00289f98434fed230eebe768dfb3425f83d737866a3aebc97aa95167c4fa0c6e +131 -0
  35. package/skills/project-update/history/blobs/079a91f976ad69b5cf49ccb9a28849576e4735ddd9485fc26599e528a69fd2f4 +30 -0
  36. package/skills/project-update/history/blobs/07ff7fa6f93d471ff533f553b4e523e4105ccde1f3dab70132c5237728f68422 +13 -0
  37. package/skills/project-update/history/blobs/0ef4a360c76da290173dea0f8073949cb0f8113710a38df95acae5d96bdd1286 +123 -0
  38. package/skills/project-update/history/blobs/18c7a2753ce9cb6f6d3d1e9d5d1125d75950b879d56b7325225b200869631b29 +15 -0
  39. package/skills/project-update/history/blobs/25d4f2a86deb5e2574bb3210b67bb24fcc4afb19f93a7b65a057daa874a9d18e +1 -0
  40. package/skills/project-update/history/blobs/48d9950f16e31d55475f566a80dc95f64b35f1c804d2f51729e313a4f29bac8d +13 -0
  41. package/skills/project-update/history/blobs/5a93f78b4ed4d416c171139b2ce610a117f9c1dd46fbb56ca86729cb4c53d10c +6 -0
  42. package/skills/project-update/history/blobs/6a3be0e624e5ad91e44d08857b7183ee53b7903e1e8d56ff196dbc9dde271e4a +75 -0
  43. package/skills/project-update/history/blobs/7170553410bba904ffb7edb4b231e3b3579b85542d84de717299980938f82c9d +13 -0
  44. package/skills/project-update/history/blobs/774b1e3a04ef0d49d33c44a2cfecd92eb6f6b738a12b6a681103ba7fc13e7b86 +67 -0
  45. package/skills/project-update/history/blobs/7f063e79195a5c85c37b7260dd20c184d3b9bea85e37202e0bbca73ad84bba49 +13 -0
  46. package/skills/project-update/history/blobs/c8573ca1f810ce6c4ac49456a4c1725b93e0d3b74c54ce95d46d8747777895f0 +13 -0
  47. package/skills/project-update/history/blobs/d6e5b34d475e7187d2a8cb2aac7e7f1a427142baf6461bda387d70ceb4d8a8c1 +30 -0
  48. package/skills/project-update/history/blobs/e120ff4e32b2e950fc94ada4e787d57dc9c790da37223e5a202d74f7e3aadf80 +13 -0
  49. package/skills/project-update/history/index.json +36 -15
  50. package/skills/project-update/migrations/0011_retire_risk_tiers.py +37 -0
  51. package/skills/project-update/migrations/__init__.py +6 -1
  52. package/skills/project-update/render_instructions.py +1 -1
  53. package/skills/project-update/update.py +374 -87
  54. package/skills/rr-build-all/SKILL.md +2 -2
  55. package/skills/rr-plan/SKILL.md +3 -1
  56. package/skills/rr-review/SKILL.md +13 -8
  57. package/skills/rr-setup/SKILL.md +15 -2
  58. package/skills/rr-setup/setup.py +7 -1
  59. package/skills/rr-spec/SKILL.md +4 -2
  60. package/skills/usage-report/usage-report.py +4 -2
  61. package/skills/ai-init/templates/.ai/policies/risk-tiers.json +0 -628
  62. package/skills/ai-init/templates/.ai/policies/risk-tiers.md +0 -180
@@ -146,8 +146,8 @@ EOF
146
146
  - **pass** → §6.
147
147
  - **pass_with_findings** → the in-scope HIGHs, grouped by file, one fixer per group in
148
148
  parallel; `$STATE verify --scope all --after-fix "H1,H2: …"`; `$STATE review --closes "H1,H2"`
149
- → §6. Each MEDIUM and LOW is one `$STATE memory risk add`, not a fix; only a BLOCKER, a HIGH
150
- or a regression buys an `--after-fix` run.
149
+ → §6. MEDIUM and LOW: `memory risk add` as `/rr-review` §4 says, for every verdict; only a
150
+ BLOCKER, a HIGH or a regression buys an `--after-fix` run.
151
151
  - **blockers_open** → every in-scope BLOCKER and HIGH, grouped by file, one fixer per group in
152
152
  parallel; `$STATE verify --scope all --after-fix "B1,H1: …"` (red: §4's batch); then
153
153
  **§5 again, a full pass** — a fix batch across many files is a new change, not a scoped one.
@@ -24,7 +24,9 @@ first: a task already in flight is finished or abandoned before another starts.
24
24
 
25
25
  When `$ARGUMENTS` is a spec (default: the newest `docs/sdlc/specs/*.md`):
26
26
 
27
- 1. `docs/sdlc/plans/TEMPLATE.md` exists, else `/rr-setup`. If the spec's
27
+ 1. `docs/sdlc/constitution.md` exists, else `/rr-setup`. The template is
28
+ `docs/sdlc/plans/TEMPLATE.md` when the project overrides it, else
29
+ `$AI_HOME/skills/project-init/templates/plan.md`. If the spec's
28
30
  **Flagged concerns** holds unresolved items, list them and have the human
29
31
  resolve or explicitly accept each one before planning.
30
32
  2. If `superpowers:writing-plans` is available, use it for the step
@@ -60,7 +60,10 @@ guarded, about 80 in full, then FINDINGS and VERDICT.
60
60
 
61
61
  Before you delegate, probe the change yourself for a minute: the few inputs its
62
62
  own threat model makes interesting, through the real code, and hand the
63
- reviewer what you saw — it starts where you stopped.
63
+ reviewer what you saw — it starts where you stopped. When the change touches a
64
+ guard regex's running time, run the timed probe yourself (`/usr/bin/grep -E`,
65
+ or Python `timeit` on inputs of at most 4096 chars) and hand over the
66
+ measurement: the bounded reviewer may not run timing loops.
64
67
 
65
68
  ## 3. Record the verdict
66
69
 
@@ -81,16 +84,18 @@ task's record (`task.md`), so there is no separate report to write.
81
84
 
82
85
  ## 4. After the verdict
83
86
 
84
- - **pass:** `/rr-ship`; the record and the close are one call,
85
- `$STATE review --verdict pass … <<'EOF' && $STATE close`. `review` exits 0 for every
86
- verdict, so the chain is for `pass` only.
87
+ Continue from the verdict §3 recorded; do not record it again. Whatever the
88
+ verdict, each MEDIUM and LOW is one `$STATE memory risk add`
89
+ (`.ai/project/known-risks.md` amended into the task if missing), not a fix.
90
+
91
+ - **pass:** `/rr-ship`, i.e. `$STATE close` directly: the verdict is already
92
+ recorded. (To record and close in one call, §3's `review --verdict pass … <<'EOF' && $STATE close`;
93
+ `review` exits 0 for every verdict, so that chain is for `pass` only.)
87
94
  - **pass_with_findings:** fix every in-scope HIGH in one batch, then
88
95
  `$STATE verify --scope all --after-fix "H1,H2: <one line>"` and
89
96
  `$STATE review --closes "H1,H2"`. The findings close on that green run, on a
90
- tree the fix changed — no second review. Each MEDIUM and LOW is one
91
- `$STATE memory risk add` (`.ai/project/known-risks.md` amended into the task
92
- if missing), not a fix; only a BLOCKER, a HIGH or a regression buys an
93
- `--after-fix` run.
97
+ tree the fix changed — no second review. MEDIUM and LOW: `memory risk add`
98
+ as above; only a BLOCKER, a HIGH or a regression buys an `--after-fix` run.
94
99
  - **blockers_open:** fix every BLOCKER and HIGH together, `verify --scope all
95
100
  --after-fix "…"`, then **one scoped re-review** (`/rr-review B1,H1`): brief a fresh `ai-reviewer`
96
101
  with the named findings and the fix's diff only — do they close, and what did
@@ -133,12 +133,25 @@ it cannot.
133
133
  each in one plain sentence and ask, unless `$ARGUMENTS` holds `--apply`.
134
134
  4. `$UPDATE --apply`. Exit 3 stopped on a changed, non-regular or unwritable
135
135
  file and names it; nothing after it was written — run the dry run again.
136
- **A `delete?` is the human's.** Never pass `--confirm-delete`, not even with
136
+ **A `delete?` is the human's.** Never pass `--confirm-delete` or `--confirm-cleanup`, not even with
137
137
  `--apply`. Give them, with `$AI_HOME` and `$PWD` substituted, for their own
138
138
  terminal (the `!` prefix is refused):
139
139
  `python3 "<home>/skills/project-update/update.py" "<project>" --apply --confirm-delete "<your name>"`.
140
140
  The schema stays put until it is settled — that command, or deleting the
141
- file by hand; there is no third way. For 0006 (shared files) the order is:
141
+ file by hand; there is no third way. Two kinds are housekeeping, not
142
+ migrations: `[sdlc]` — an unedited `docs/sdlc/*/TEMPLATE.md`, which the plugin
143
+ now supplies (an edited one stays as the project's override); `[cleanup]` —
144
+ the `*.log` files of closed tasks, and the report and log files of an
145
+ abandoned task (its `state.json` stays) or of one unclosed for more than seven
146
+ days (never the task in flight; and none when `.ai/state/state.json` is unreadable).
147
+ `--confirm-delete` does not settle `[cleanup]` rows, and the rows differ by kind:
148
+ files under `.ai/state/logs/` are git-ignored and git cannot restore them; files
149
+ under `.ai/reports/` are usually tracked, and the row says "tracked: git can restore
150
+ a committed copy" or, when git holds no committed copy, "uncommitted" — then
151
+ commit `.ai/` first (the hint says so), and an `original/` copy is kept as for any
152
+ other deletion. They have their own command, the human's too, never passed by the agent:
153
+ `python3 "<home>/skills/project-update/update.py" "<project>" --apply --confirm-cleanup "<your name>"`.
154
+ Show both groups as printed. For 0006 (shared files) the order is:
142
155
  `install.sh` for every runtime used, commit `.ai/`, read the `delete?` list,
143
156
  then the command with no task in flight. Rollback is git:
144
157
  `git restore --source=<commit before> --staged --worktree -- .ai`, before
@@ -182,7 +182,11 @@ def comment_purpose(lines):
182
182
 
183
183
 
184
184
  def purpose_of(root, rel):
185
- text = read_text(os.path.join(root, rel))
185
+ full = os.path.join(root, rel)
186
+ real, base = os.path.realpath(full), os.path.realpath(root)
187
+ if os.path.commonpath([real, base]) != base:
188
+ return None # a link out of the project: listed UNKNOWN, never read into toolbox.md
189
+ text = read_text(full)
186
190
  if text is None:
187
191
  return None
188
192
  lines = text.splitlines()
@@ -225,6 +229,8 @@ def inventory(root, table):
225
229
  for rel in paths:
226
230
  if rel in seen or not pattern.match(rel):
227
231
  continue
232
+ if "/hooks/" in rel and os.path.basename(rel).startswith("."):
233
+ continue
228
234
  seen.add(rel)
229
235
  if row["kind"] == "make":
230
236
  for n, target, purpose in make_targets(root, rel):
@@ -19,7 +19,9 @@ STATE="python3 $AI_HOME/skills/ai-task/state.py"
19
19
 
20
20
  ## 1. Prerequisites
21
21
 
22
- `docs/sdlc/specs/TEMPLATE.md` exists, else run `/rr-setup` first. Derive
22
+ `docs/sdlc/constitution.md` exists, else run `/rr-setup` first. The template is
23
+ `docs/sdlc/specs/TEMPLATE.md` when the project overrides it, else
24
+ `$AI_HOME/skills/project-init/templates/spec.md`. Derive
23
25
  `<slug>` from the topic (kebab-case, at most five words). If
24
26
  `docs/sdlc/specs/<slug>.md` exists, offer to refine it instead of starting over.
25
27
  When `$ARGUMENTS` is a path to an intent file, read it fully — it is small by
@@ -75,7 +77,7 @@ decision — moves this to the top tier.
75
77
 
76
78
  ## 5. Write
77
79
 
78
- Copy `docs/sdlc/specs/TEMPLATE.md` to `docs/sdlc/specs/<slug>.md`, replace
80
+ Copy the template (§1) to `docs/sdlc/specs/<slug>.md`, creating the folder, replace
79
81
  `{{TITLE}}` and `{{SLUG}}`. Replace the template's `Intent:` line with:
80
82
 
81
83
  ```markdown
@@ -690,7 +690,8 @@ def task_report(args) -> int:
690
690
  return 1
691
691
  start = min(stamps)
692
692
  closed = [parse_ts(e.get("ts")) for e in events if e.get("event") == "task_closed"]
693
- end = max(c for c in closed if c) if any(closed) else dt.datetime.now(dt.timezone.utc)
693
+ unclosed = not any(closed)
694
+ end = max(stamps) if unclosed else max(c for c in closed if c) # unclosed: the last event, not now
694
695
  tier, mode = "untiered", None
695
696
  involved = []
696
697
  for e in events:
@@ -729,7 +730,8 @@ def task_report(args) -> int:
729
730
 
730
731
  label = f"mode {mode} (tier {tier})" if mode else f"tier {tier}"
731
732
  print(f"task {args.task} {label} window {start.isoformat(timespec='seconds')}"
732
- f"..{end.isoformat(timespec='seconds')}")
733
+ f"..{end.isoformat(timespec='seconds')}"
734
+ + (" (unclosed: window ends at the last event)" if unclosed else ""))
733
735
  print(" (by time window: any other session in this project inside it is counted too)")
734
736
  for rt in involved or sorted(used):
735
737
  inp, cache, out = used.get(rt, [0, 0, 0])