riskrails 3.2.1 → 4.0.1
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +40 -83
- package/agents/ai-reviewer.md.tmpl +1 -1
- package/ai/using-riskrails.md +0 -3
- package/bin/riskrails.js +13 -59
- package/hooks/ai-path-guard-defaults.json +1 -1
- package/hooks/context-guard.py +2 -4
- package/hooks/guard/paths.py +3 -6
- package/hooks/guard/scope.py +1 -3
- package/hooks/runtime-gate.py +18 -58
- package/instructions/routing.md +2 -2
- package/package.json +1 -1
- package/scripts/ai-path +1 -1
- package/scripts/resolve-profile.py +0 -3
- package/skills/ai-audit/templates/ai-sdlc-adoption-plan.md +1 -1
- package/skills/ai-audit/templates/play-scoring-rubric.md +1 -1
- package/skills/ai-init/templates/.ai/AGENTS.md +6 -6
- package/skills/ai-init/templates/.ai/VERSION +1 -1
- package/skills/ai-init/templates/.ai/policies/security.md +1 -2
- package/skills/ai-init/templates/.ai/policies/testing.md +5 -12
- package/skills/ai-init/templates/.ai/policies/verification.md +18 -0
- package/skills/ai-init/templates/.ai/policies/weight.json +0 -1
- package/skills/ai-init/templates/.ai/policies/weight.md +1 -2
- package/skills/ai-init/templates/.ai/policies/weight.project.json +4 -0
- package/skills/ai-init/templates/.ai/project/architecture.md +1 -1
- package/skills/ai-init/templates/.ai/project/initial-assessment.md +2 -2
- package/skills/ai-init/templates/.ai/project/overview.md +1 -1
- package/skills/ai-init/templates/.ai/rules/README.md +2 -2
- package/skills/ai-init/templates/.ai/state/README.md +1 -1
- package/skills/ai-task/memory_store.py +8 -9
- package/skills/ai-task/rr_state/cli.py +1 -1
- package/skills/ai-task/rr_state/dialog.py +2 -4
- package/skills/ai-task/rr_state/fs.py +5 -13
- package/skills/ai-task/rr_state/profile.py +2 -4
- package/skills/ai-task/rr_state/questions_cmd.py +1 -1
- package/skills/ai-task/rr_state/report.py +3 -4
- package/skills/ai-task/rr_state/runtime.py +1 -1
- package/skills/ai-task/rr_state/start.py +7 -7
- package/skills/ai-task/sensors.py +10 -11
- package/skills/ai-task/state.py +4 -24
- package/skills/ai-task/weight.py +17 -17
- package/skills/ai-task/weight_overlay.py +38 -0
- package/skills/project-init/templates/constitution.md +2 -2
- package/skills/project-update/history/blobs/00f5e27ce2d66e3a1d8b222b013ae8fa1fed32612d91a551e0c661cee3ef9c2d +34 -0
- package/skills/project-update/history/blobs/0a6b1b6dd06a35582b2e9989a1f41c40abc29254b8e482714fcc6f0a7b16c406 +32 -0
- package/skills/project-update/history/blobs/0aeb04b04262683cac6513545683486a73dc473b447bba43b5aaab18403957a6 +34 -0
- package/skills/project-update/history/blobs/0ce913a28996f546f72d570b0e5a376362e993ce4d805bc4aae57d38caa44212 +41 -0
- package/skills/project-update/history/blobs/0ea9e36446b624b73b2a821231b2ee66a357b43d584a5b23da48b3c800855e65 +41 -0
- package/skills/project-update/history/blobs/0fb1d68678a1349195b2e79433bb20174d25874e3bfd0b70410bb4e428b4e4b8 +35 -0
- package/skills/project-update/history/blobs/119b2b9d0f9c647a243540724edac6b29afa020c69aa205797bcfa9eb06bc021 +35 -0
- package/skills/project-update/history/blobs/1d0fe3ee5fb8260ba610942d4bbdfff7410fbe80ed826ac07f32985031dc2b3f +34 -0
- package/skills/project-update/history/blobs/1de9a37ed6402893dcab6e61ddbf15ffd35f15a6d84b18e675a0c5bf4e981f85 +42 -0
- package/skills/project-update/history/blobs/1f44e1a236233dcbab58064f39b69f798b35d1d9a29f8c615b5b12854ce633cb +15 -0
- package/skills/project-update/history/blobs/1f824645299579cbdd8141642ddbb4bca9fd5fe9d3112f036d8221f0811e0abf +40 -0
- package/skills/project-update/history/blobs/235fb88393cfe20dd58b35fe9785cc45baf5ffe21a13d926652d76ec68cea8b7 +35 -0
- package/skills/project-update/history/blobs/3918b4ee011d9477b9d2779e2893ab599749c406d4b09439a9748b64fbff58f3 +18 -0
- package/skills/project-update/history/blobs/449273200dfec2a56885c881ff34d40e8ecc00da53c24c2d09b7fbeb1004d255 +40 -0
- package/skills/project-update/history/blobs/4c45aee9b9fc5f6b4e1d9739e434c4094975a5a8dec6b9703fb25f3080680c77 +124 -0
- package/skills/project-update/history/blobs/4dd3fa12bc45acc8c836ab65d790248ca7504a021bca6677499d17bb3d798ed9 +64 -0
- package/skills/project-update/history/blobs/51e3f15095d7123ea8566b512479ee10a6cb2f336b7352a259a083a887bd7116 +33 -0
- package/skills/project-update/history/blobs/5497a204967bea7dab29079a6e1dfa3d8713b2d2cb294c2779378039f03a55fc +36 -0
- package/skills/project-update/history/blobs/60c4d7e7fde7049d92d84295fc13ca9a91eb2de423be08f093b3ee5d5e817ff8 +64 -0
- package/skills/project-update/history/blobs/6221b7c14cc04634e485e562d464c6860d45666a7f63e293c06bb2944ff556cc +27 -0
- package/skills/project-update/history/blobs/637971cfb844ef4285e2886a4b1c834fb2ed5c46e773adb88c2c147fea626ad3 +33 -0
- package/skills/project-update/history/blobs/65af2282eea2a51fcc27a4acf2c26c727b0961c30e1be13176369200c460c219 +34 -0
- package/skills/project-update/history/blobs/66ecd73e303e7bbc1aa8ee72435d0d10812ff7b2eff0adac59bbf0a303e2cc01 +41 -0
- package/skills/project-update/history/blobs/6a43bf32461b22b87fafe2865529dc04fa66cd00182a2a7598aa071667ca255a +35 -0
- package/skills/project-update/history/blobs/6d6dee8634abf9ac057bb206828b83a893a2afcf4f86bbe69e839a3b47d0adde +48 -0
- package/skills/project-update/history/blobs/7224ede803ea81e65a456e21b6028a0e848e8a880456c6503eebe7534ca4f6aa +74 -0
- package/skills/project-update/history/blobs/765a39a202617096c232017822ae738d37e4405430c71700dc7bc14bf1ba794e +33 -0
- package/skills/project-update/history/blobs/77577440a933d1cabd8c6f4a6401cf361a784aa09a25500a6f7b44ead8ab5e55 +41 -0
- package/skills/project-update/history/blobs/7bae90789625d6fb9071ecb412d14a8d1eb0bc5659d8d284c4eaf213e1b5de56 +67 -0
- package/skills/project-update/history/blobs/7bcdf9a0e6b85277b9b60669150224b9414d2e32821ff06f4d148eb1d18785bb +42 -0
- package/skills/project-update/history/blobs/7f834103e9d97aea44e76717bcdcbbe349c560e5b81a42ce85a1cec341041281 +4 -0
- package/skills/project-update/history/blobs/7fb3acb0211818efebc2234863db0b8c846022a7280a6d2d69f267dbf63db48c +34 -0
- package/skills/project-update/history/blobs/87f0855859ff68cc6c988cc0b631ee7f56af7fbba062172bf80e01f4982cc054 +35 -0
- package/skills/project-update/history/blobs/8abab74759766d02b5cb7b0c3e59a3d440b25a454216cd8fea325c23fd822d36 +33 -0
- package/skills/project-update/history/blobs/a1fb50e6c86fae1679ef3351296fd6713411a08cf8dd1790a4fd05fae8688164 +1 -0
- package/skills/project-update/history/blobs/a3df7268feb0780be0d2cf9acced6ed81780a7790f36fe024b6ea0b1bd6eb7a6 +35 -0
- package/skills/project-update/history/blobs/b28721136482dafb9fd2801af340364cb97e9f6eaa987908606c786045b8d334 +28 -0
- package/skills/project-update/history/blobs/b3726422d767f9219fea633bea77f0c99ad9af843c591e6e928e1ccd2a47f374 +27 -0
- package/skills/project-update/history/blobs/b3839425f9d0ab2efa42a6f5e9488ec2d26ca5fb8dcd694b8ab098e10743ca46 +32 -0
- package/skills/project-update/history/blobs/ba14a457e83f9dde65e4190fdfab83b912f7398c1442a2a1cb3d89bfac741cf3 +8 -0
- package/skills/project-update/history/blobs/bceb7189444bb6291b262ca08e34db01010dda2f6e64d696231ec3c343c95c66 +34 -0
- package/skills/project-update/history/blobs/bf82a2bb4fce1bd349ff66118930a01d61a7af8e2bd8d200c721d43afc58c713 +34 -0
- package/skills/project-update/history/blobs/c4dbeb180292a6199ad73a3be861ece07c1f8bf6bf0cc7ca204412bc8e1bb1d8 +31 -0
- package/skills/project-update/history/blobs/c644838866df2001a42501a988dd7b77aacf862bf09d22b465f3cd8a22c6b6eb +33 -0
- package/skills/project-update/history/blobs/c980d74f76a4bdfb38c94b573ac10a54eb50b850b052e15fa6f2442889b36ccb +32 -0
- package/skills/project-update/history/blobs/ceed2f3bd937f862d0e6ca59ce1b1e3603e19a0d7f85d90d6dfeb7bf690153be +29 -0
- package/skills/project-update/history/blobs/d51ea2e893482a20c5882056cf8043327ca1dc1c957927f6746929a47ee8368e +45 -0
- package/skills/project-update/history/blobs/d78f5e0bb1380259fce2cce009785a9a11f6de8b87a160080b9872c059f95060 +34 -0
- package/skills/project-update/history/blobs/d97f46a2cca020406252b1f7baa4184617fa71faca3885e2379c44ae4e1d9327 +67 -0
- package/skills/project-update/history/blobs/da3ecd4c4c414c93d04488685931df39a56bf959bfeb9c45cb1aea2c13bd991b +38 -0
- package/skills/project-update/history/blobs/e129bf71a5a922e24b2c1bc8daa8a5d2b5589b0069770e17ce17e7db5ed4e7a4 +27 -0
- package/skills/project-update/history/blobs/e504529519a371892838725f8b89b5d32e3300e345bcbf2643a3a1a48434b3dd +24 -0
- package/skills/project-update/history/blobs/e9e62d03ca70b3dffccef8dceeb214173352cfef005145e519f0e037993f1c03 +36 -0
- package/skills/project-update/history/blobs/effefbaaf4beb8f1ba55081d6b7e74bf25ebb91045dd10613418f17b95fa7182 +33 -0
- package/skills/project-update/history/blobs/f6af4581bafbf62b257d57e06c3ae2c5998aeca608ee7df037fcc3c3e4b563a9 +34 -0
- package/skills/project-update/history/blobs/fc35045777d29630303430752a651b3e553580a581036a02cc103eb96a46f4b0 +34 -0
- package/skills/project-update/history/blobs/fdc21345c77f92a42d244aa104f393f439a0ff9981a9fd462bd837e8a47931bb +48 -0
- package/skills/project-update/history/index.json +32 -13
- package/skills/project-update/render_instructions.py +12 -45
- package/skills/project-update/update.py +757 -1172
- package/skills/rr-setup/SKILL.md +42 -81
- package/skills/rr-setup/scaffold_ai.py +7 -7
- package/skills/rr-setup/setup.py +96 -164
- package/skills/rr-status/status.py +7 -10
- package/skills/usage-report/usage-report.py +4 -5
- package/skills/ai-audit/SKILL.md +0 -9
- package/skills/ai-init/SKILL.md +0 -9
- package/skills/ai-status/SKILL.md +0 -9
- package/skills/ai-task/SKILL.md +0 -9
- package/skills/project-init/SKILL.md +0 -9
- package/skills/project-update/SKILL.md +0 -9
- package/skills/project-update/adopt-map.json +0 -91
- package/skills/project-update/adopt.py +0 -2225
- package/skills/project-update/migrations/0001_schema_version.py +0 -13
- package/skills/project-update/migrations/0002_task_journal.py +0 -123
- package/skills/project-update/migrations/0003_context_diet.py +0 -65
- package/skills/project-update/migrations/0004_deterministic_gates.py +0 -57
- package/skills/project-update/migrations/0005_runtimes_and_plans.py +0 -35
- package/skills/project-update/migrations/0006_shared_files.py +0 -154
- package/skills/project-update/migrations/0007_weight_model.py +0 -295
- package/skills/project-update/migrations/0008_renames.py +0 -43
- package/skills/project-update/migrations/0009_state_file.py +0 -25
- package/skills/project-update/migrations/0010_dialog_switch.py +0 -30
- package/skills/project-update/migrations/0011_retire_risk_tiers.py +0 -37
- package/skills/project-update/migrations/README.md +0 -76
- package/skills/project-update/migrations/__init__.py +0 -186
- package/skills/sdlc-intent/SKILL.md +0 -9
- package/skills/sdlc-plan/SKILL.md +0 -9
- package/skills/sdlc-spec/SKILL.md +0 -9
- package/skills/usage-report/SKILL.md +0 -10
- /package/{ai/workflows/refactoring.md → skills/project-update/history/blobs/36cb593293496fbcf38df828a9b9b2bc0d5a53333f584a5319ebc3d799016e24} +0 -0
- /package/{ai/workflows/feature.md → skills/project-update/history/blobs/56e16072c2f3edc6c8897c690d09a11d12fc414c3e3f361f359f7dc609a21282} +0 -0
- /package/{ai/workflows/hotfix.md → skills/project-update/history/blobs/8cbefbf1aa412bae3e5019acd40b8fe0598fceba6c781906b3bc6dbd014f6b23} +0 -0
- /package/{ai/workflows/bugfix.md → skills/project-update/history/blobs/af56dc16e44ae1d8c3dac4c3ca82e2163b719553c02ea455e77430bab9a14089} +0 -0
- /package/{ai/workflows/investigation.md → skills/project-update/history/blobs/b9e09cb24958cd6831589997558974bd6356305306e8f9685e226bcdc30d60ac} +0 -0
- /package/{ai/agents/manager.md → skills/project-update/history/blobs/d0cf6388f35a92a0cf607d33909278382f6d7b6a4c32e281b9f9e0ea652c7b91} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Why a separate module: state.py owns every write to state.json and has no
|
|
5
5
|
subprocess use at all; this module shells out to git and to the commands written
|
|
6
|
-
in .ai/policies/
|
|
6
|
+
in .ai/policies/verification.md, imports nothing from state.py, and never opens
|
|
7
7
|
state.json for writing. state.py imports it, not the reverse. Since redesign
|
|
8
8
|
2.6 it measures nothing else: the size budget, the re-score and the static
|
|
9
9
|
sensors (bite, duplicates, traceability, plan sections, lint, typecheck, detect)
|
|
@@ -213,11 +213,11 @@ SCOPE_FIELD = {"suite": "verify_command", "step": "step_test_command",
|
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
def testing_path(root):
|
|
216
|
-
return os.path.join(root, ".ai", "policies", "
|
|
216
|
+
return os.path.join(root, ".ai", "policies", "verification.md")
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
def read_commands(root):
|
|
220
|
-
"""The project's own commands, as a human wrote them into
|
|
220
|
+
"""The project's own commands, as a human wrote them into verification.md.
|
|
221
221
|
|
|
222
222
|
A line's value is everything after the colon, minus a trailing comment; the
|
|
223
223
|
template ships the fields with an explanatory comment and no value, and that
|
|
@@ -253,7 +253,7 @@ def _escaped(text):
|
|
|
253
253
|
|
|
254
254
|
def bite_codes(root):
|
|
255
255
|
"""The exit codes that count as "the test fails" under --expect fail: the
|
|
256
|
-
|
|
256
|
+
verification.md `bite_codes` list of integers 1-255, 1 when absent or not a clean list
|
|
257
257
|
(an empty part, a non-integer, 0, a negative or a value over 255 all fall back)."""
|
|
258
258
|
raw = read_commands(root).get("bite_codes", "")
|
|
259
259
|
try:
|
|
@@ -349,8 +349,6 @@ def resolve_trees(root, args):
|
|
|
349
349
|
from_tree = args.from_tree
|
|
350
350
|
if not from_tree:
|
|
351
351
|
state = os.path.join(root, ".ai", "state", "state.json")
|
|
352
|
-
if not os.path.isfile(state):
|
|
353
|
-
state = os.path.join(root, ".ai", "state", "current.json") # R34: legacy name, one version
|
|
354
352
|
try:
|
|
355
353
|
with open(state, encoding="utf-8") as fh:
|
|
356
354
|
from_tree = ((json.load(fh) or {}).get("diff") or {}).get("base_tree")
|
|
@@ -387,11 +385,12 @@ def cmd_diff(args, root):
|
|
|
387
385
|
|
|
388
386
|
|
|
389
387
|
def tests_config(root):
|
|
390
|
-
"""The runner's caps from weight
|
|
388
|
+
"""The runner's caps from the weight table's `tests` (the plugin's, the project's
|
|
389
|
+
weight.project.json over it), {} when the table cannot be read."""
|
|
391
390
|
try:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
except (OSError, ValueError, AttributeError):
|
|
391
|
+
import weight # pylint: disable=import-outside-toplevel # sits beside this file; only cmd_run needs it
|
|
392
|
+
config = weight.load_policy(root)[0].get("tests") or {}
|
|
393
|
+
except (ImportError, OSError, ValueError, AttributeError):
|
|
395
394
|
config = {}
|
|
396
395
|
return config if isinstance(config, dict) else {}
|
|
397
396
|
|
|
@@ -400,7 +399,7 @@ def cmd_run(args, root):
|
|
|
400
399
|
config = tests_config(root)
|
|
401
400
|
command = command_for(root, args.scope)
|
|
402
401
|
if not command:
|
|
403
|
-
print("%-13s UNAVAIL %s is not written down in .ai/policies/
|
|
402
|
+
print("%-13s UNAVAIL %s is not written down in .ai/policies/verification.md"
|
|
404
403
|
% (args.scope, SCOPE_FIELD.get(args.scope, args.scope)))
|
|
405
404
|
return UNKNOWNCODE
|
|
406
405
|
files = [f.strip() for f in (args.files or "").split(",") if f.strip()]
|
package/skills/ai-task/state.py
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Task state for /
|
|
2
|
+
"""Task state for /rr-build — the small, machine-readable record of one task.
|
|
3
3
|
|
|
4
4
|
Why a file and not the conversation: a conversation is expensive to re-read and
|
|
5
5
|
impossible for a hook to consult. This file is what ai-scope-guard enforces
|
|
6
|
-
against, what /
|
|
6
|
+
against, what /rr-status reports, and what lets a task survive a /clear or a
|
|
7
7
|
crash. It holds facts, never transcripts.
|
|
8
8
|
|
|
9
9
|
Everything is stdlib. Writes are atomic (temp file + os.replace), so a hook that
|
|
10
10
|
reads the file while a stage is being recorded never sees half a document.
|
|
11
11
|
|
|
12
12
|
Every state change is also appended to .ai/reports/<task-id>/events.jsonl, the
|
|
13
|
-
append-only journal /
|
|
13
|
+
append-only journal /rr-status and /rr-status --cost read at zero model cost. The
|
|
14
14
|
journal is best effort by contract: a line that cannot be written never fails
|
|
15
15
|
the command that emitted it, and nothing here depends on it being lossless.
|
|
16
16
|
history[] keeps its exact shape and its original event names beside it.
|
|
@@ -57,8 +57,7 @@ redesign 2.6) answers status, handoff and questions, and close --abandon drops
|
|
|
57
57
|
it; every other command refuses it.
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
|
-
# pylint: disable=
|
|
61
|
-
import json
|
|
60
|
+
# pylint: disable=wrong-import-position
|
|
62
61
|
import os
|
|
63
62
|
import sys
|
|
64
63
|
|
|
@@ -68,26 +67,7 @@ try:
|
|
|
68
67
|
except ImportError:
|
|
69
68
|
sys.exit("rr_state/ is missing beside state.py: re-run `npx riskrails`")
|
|
70
69
|
fs.ENTRY = os.path.abspath(__file__) # R6a: the one path the package prints and compares
|
|
71
|
-
|
|
72
|
-
# The names the suites reach as state_mod.<name> (R6) and json_loads_capped, which
|
|
73
|
-
# tests/test_dialog_contract.py:176,189 reach as module.json_loads_capped over (dialog, state_mod);
|
|
74
|
-
# json and os are imported above for the same reason: the suites patch state_mod.json.dump and state_mod.os.
|
|
75
70
|
from rr_state.cli import main
|
|
76
|
-
from rr_state.fs import current_tree, read_session, session_path, state_path
|
|
77
|
-
from rr_state.runtime import AGENT_MARKERS
|
|
78
|
-
from rr_state.journal import append_journal, journal_line, read_journal
|
|
79
|
-
from rr_state.task import TASK_ID_RE, abandon_old, load, next_task_id, sealed_task_ids, valid_task_id
|
|
80
|
-
from rr_state.policy import NEVER_DOCUMENTS, is_document, mode_for, rescore_weight
|
|
81
|
-
from rr_state.locks import LOCK_STALE
|
|
82
|
-
from rr_state.questions import parse_questions
|
|
83
|
-
from rr_state.questions_cmd import close_gate_from_file, sync_answers
|
|
84
|
-
from rr_state.ledger import LEDGER_LINE_MAX, LEDGER_TYPES, live_picks, read_ledger
|
|
85
|
-
from rr_state.dialog import DIALOG_TOOL, JSON_DEPTH_MAX, QUESTION_MAX, SESSION_ENV, json_loads_capped
|
|
86
|
-
from rr_state.dialog import dialog_on, dialog_payload, dialog_policy, dialog_tool_verified, task_facts
|
|
87
|
-
from rr_state.labels import LABEL_MAX, validate_label
|
|
88
|
-
from rr_state.gate import confirm_names
|
|
89
|
-
from rr_state.profile import jwt_plan_type, read_json_object, read_profile, read_quota
|
|
90
|
-
from rr_state.close import archive_v7
|
|
91
71
|
|
|
92
72
|
if __name__ == "__main__":
|
|
93
73
|
main()
|
package/skills/ai-task/weight.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Weight — six axes, 0 to 2 each, from .ai/policies/weight.json.
|
|
1
|
+
"""Weight — six axes, 0 to 2 each, from the plugin's weight table with .ai/policies/weight.project.json laid over it.
|
|
2
2
|
|
|
3
3
|
Pure computation: it reads the declared files, the tree listing and `git grep`,
|
|
4
4
|
and writes nothing. A measured value is a floor: the session may raise an axis
|
|
@@ -39,15 +39,10 @@ class Weight:
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def load_policy(root):
|
|
42
|
-
"""(policy,
|
|
43
|
-
|
|
44
|
-
own = os.path.join(root, ".ai", "policies", "weight.json")
|
|
45
|
-
|
|
46
|
-
with open(path, encoding="utf-8") as fh:
|
|
47
|
-
policy = json.load(fh)
|
|
48
|
-
if not isinstance(policy, dict) or not all(isinstance(policy.get(k), dict) for k in ("axes", "modes")):
|
|
49
|
-
raise ValueError("%s has no axes or modes table" % path)
|
|
50
|
-
return policy, path
|
|
42
|
+
"""(policy, [shipped, project]): the shipped table with the project's weight.project.json laid over it."""
|
|
43
|
+
import weight_overlay # pylint: disable=import-outside-toplevel # beside this file; update.py loads this file by path
|
|
44
|
+
own = os.path.join(root, ".ai", "policies", "weight.project.json")
|
|
45
|
+
return weight_overlay.load(SHIPPED, own), [SHIPPED, own]
|
|
51
46
|
|
|
52
47
|
|
|
53
48
|
@functools.lru_cache(maxsize=None)
|
|
@@ -268,14 +263,19 @@ def render(result, long=False):
|
|
|
268
263
|
return "\n".join(lines)
|
|
269
264
|
|
|
270
265
|
|
|
271
|
-
def mirror(
|
|
272
|
-
"""weight.md for the
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
266
|
+
def mirror(source):
|
|
267
|
+
"""weight.md for `source`: a policy dict (the effective table, sha256 of its canonical JSON) or
|
|
268
|
+
the path of one JSON file (sha256 of its bytes)."""
|
|
269
|
+
if isinstance(source, dict):
|
|
270
|
+
policy, origin = source, "the plugin's weight table plus weight.project.json"
|
|
271
|
+
raw = json.dumps(source, sort_keys=True, ensure_ascii=False).encode("utf-8")
|
|
272
|
+
else:
|
|
273
|
+
with open(source, "rb") as fh:
|
|
274
|
+
raw = fh.read()
|
|
275
|
+
policy, origin = json.loads(raw.decode("utf-8")), "weight.json"
|
|
276
276
|
out = ["# Weight table", "",
|
|
277
|
-
"<!-- generated by `state.py weight --mirror` from
|
|
278
|
-
" sha256: %s -->" % hashlib.sha256(raw).hexdigest(), "",
|
|
277
|
+
"<!-- generated by `state.py weight --mirror` from %s; edit the JSON and regenerate."
|
|
278
|
+
" sha256: %s -->" % (origin, hashlib.sha256(raw).hexdigest()), "",
|
|
279
279
|
"Six axes, 0–2 each; W is their sum. Why each rule is what it is: the plugin's `docs/weight.md`.", "",
|
|
280
280
|
"| Axis | Measured by | Table |", "|---|---|---|"]
|
|
281
281
|
for axis in AXES:
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""The weight table a project sees: the plugin's shipped table with the project's
|
|
2
|
+
weight.project.json laid over it (R9). weight.py's `load_policy` calls `load`.
|
|
3
|
+
|
|
4
|
+
Objects merge recursively, any other value (a list too) replaces. A file that is not
|
|
5
|
+
a JSON object, or a result without the axes and modes tables, raises ValueError
|
|
6
|
+
naming the file; nothing falls back to a default.
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _table(path):
|
|
13
|
+
"""One JSON object from `path`; ValueError naming the file when it is not one."""
|
|
14
|
+
try:
|
|
15
|
+
with open(path, encoding="utf-8") as fh:
|
|
16
|
+
table = json.load(fh)
|
|
17
|
+
if isinstance(table, dict):
|
|
18
|
+
return table
|
|
19
|
+
raise ValueError("not a JSON object")
|
|
20
|
+
except ValueError as exc:
|
|
21
|
+
raise ValueError("%s: %s" % (path, exc)) from exc
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _overlay(base, top):
|
|
25
|
+
"""`top` laid over `base`: dicts merge, any other value (a list too) replaces."""
|
|
26
|
+
for key, value in top.items():
|
|
27
|
+
base[key] = _overlay(base[key], value) if isinstance(value, dict) and isinstance(base.get(key), dict) else value
|
|
28
|
+
return base
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def load(shipped, own):
|
|
32
|
+
"""The table at `shipped`, with `own` laid over it when that file exists."""
|
|
33
|
+
policy = _table(shipped)
|
|
34
|
+
if os.path.isfile(own):
|
|
35
|
+
_overlay(policy, _table(own))
|
|
36
|
+
if not all(isinstance(policy.get(k), dict) for k in ("axes", "modes")):
|
|
37
|
+
raise ValueError("%s has no axes or modes table" % own)
|
|
38
|
+
return policy
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Constitution — {{PROJECT}}
|
|
2
2
|
|
|
3
3
|
<!-- The 10–15 principles this project does not negotiate, one line each, numbered C1…;
|
|
4
|
-
/
|
|
4
|
+
/rr-spec and the planner cite them. Under 15: what is not here lives in .ai/policies/. -->
|
|
5
5
|
|
|
6
6
|
C1. Production behaviour is the source of truth; what looks wrong may be load-bearing.
|
|
7
7
|
C2. A bugfix starts with the failing test; legacy behaviour gets a characterization test before it changes.
|
|
8
8
|
C3. A refactoring changes no behaviour and is never mixed with a feature.
|
|
9
9
|
C4. Every step names its files; scope grows only by amending the plan.
|
|
10
10
|
C5. No agent merges or deploys; an agent commits, pushes or approves only by running, verbatim and once, a command a human picked in the dialog, as the harness recorded; else a human runs it outside.
|
|
11
|
-
C6. <!-- project principle — filled by /
|
|
11
|
+
C6. <!-- project principle — filled by /rr-setup from the survey, confirmed by you -->
|
|
12
12
|
C7. <!-- project principle -->
|
|
13
13
|
C8. <!-- project principle -->
|
|
14
14
|
C9. <!-- project principle -->
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Workflow: bugfix
|
|
2
|
+
|
|
3
|
+
Something behaves wrongly. The goal is the smallest change that fixes it without
|
|
4
|
+
changing anything else.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated; in the default `solo`
|
|
8
|
+
> profile the session does the stage inline up to the tier where the profile
|
|
9
|
+
> delegates it.
|
|
10
|
+
|
|
11
|
+
| Stage | Who | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| DISCOVERY | `ai-discovery` | reproduce first: find the exact path that produces the symptom |
|
|
14
|
+
| CONTEXT | `ai-context` | include the *correct* behaviour and where it is defined |
|
|
15
|
+
| IMPACT ANALYSIS | `ai-discovery` | who else depends on the current, wrong behaviour |
|
|
16
|
+
| RISK CLASSIFICATION | `ai-risk` | a bug in a payment path is still T4 |
|
|
17
|
+
| PLAN | `ai-planner` | failing test first, then the fix |
|
|
18
|
+
| IMPLEMENTATION | the session | the failing test is its own step |
|
|
19
|
+
| TEST | `ai-tester` | the new test fails before the fix and passes after |
|
|
20
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | T2 and above |
|
|
21
|
+
| SECURITY REVIEW | `ai-security` | if the bug was a security bug, always |
|
|
22
|
+
| RELEASE REPORT | `ai-release` | |
|
|
23
|
+
| HUMAN APPROVAL | the human | |
|
|
24
|
+
|
|
25
|
+
## Specific to this workflow
|
|
26
|
+
|
|
27
|
+
- **Write the failing test first.** A bugfix without a test that failed before it
|
|
28
|
+
is a bugfix nobody can prove.
|
|
29
|
+
- Find out *why* the bug exists before fixing it. A bug that is deliberate
|
|
30
|
+
behaviour somebody depends on is not a bug; it is a requirements conflict, and
|
|
31
|
+
it goes back to the human.
|
|
32
|
+
- Resist the urge to fix the surrounding code. Note it, fix the bug.
|
|
33
|
+
- If the same bug exists in three places, fix the one that was reported and list
|
|
34
|
+
the other two in `project/known-risks.md`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Workflow: feature
|
|
2
|
+
|
|
3
|
+
New behaviour that someone asked for. The default workflow.
|
|
4
|
+
|
|
5
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
6
|
+
> The table names the agent for when a stage is delegated; in the default `solo`
|
|
7
|
+
> profile the session does the stage inline up to the tier where the profile
|
|
8
|
+
> delegates it.
|
|
9
|
+
|
|
10
|
+
| Stage | Who | Notes |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| DISCOVERY | `ai-indexer` then `ai-discovery` | where the feature lands, what it will touch |
|
|
13
|
+
| CONTEXT | `ai-context` | the structured summary everything downstream reads |
|
|
14
|
+
| IMPACT ANALYSIS | `ai-discovery` (second pass) | callers, data, contracts, other environments |
|
|
15
|
+
| RISK CLASSIFICATION | `ai-risk` | one tier, from `policies/risk-tiers.json` |
|
|
16
|
+
| PLAN | `ai-planner` | steps with `allowed_files`; STRONG for T3/T4, `ai-expert` for T5 |
|
|
17
|
+
| PLAN REVIEW | `ai-reviewer` | T3 and above |
|
|
18
|
+
| IMPLEMENTATION | the session, one step at a time | scope-guarded |
|
|
19
|
+
| TEST | `ai-tester` | after every step, not only at the end |
|
|
20
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | T2 and above |
|
|
21
|
+
| SECURITY REVIEW | `ai-security` | T4, T5, and anything touching auth or personal data |
|
|
22
|
+
| RELEASE REPORT | `ai-release` | full report from T2 up |
|
|
23
|
+
| HUMAN APPROVAL | the human | the pipeline stops here |
|
|
24
|
+
|
|
25
|
+
## Specific to this workflow
|
|
26
|
+
|
|
27
|
+
- The plan states what stays the same, not only what changes. A feature that
|
|
28
|
+
quietly alters an existing behaviour is the most common source of regressions.
|
|
29
|
+
- New code paths need their negative cases tested: not authorized, not found,
|
|
30
|
+
invalid input, external system down.
|
|
31
|
+
- If the feature needs a new dependency, that is a decision worth its own line in
|
|
32
|
+
the plan.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Manager
|
|
2
|
+
|
|
3
|
+
The manager is the main session, not a subagent. It orchestrates; it does not
|
|
4
|
+
collect facts itself, and it keeps its own context small so it can stay in the
|
|
5
|
+
task until the end.
|
|
6
|
+
|
|
7
|
+
## Responsibilities
|
|
8
|
+
|
|
9
|
+
- Understand the request and restate it in one sentence the human can correct.
|
|
10
|
+
- Classify the task: which workflow, which risk tier.
|
|
11
|
+
- Establish scope, and defend it.
|
|
12
|
+
- Choose the stages the tier requires, and the agent for each.
|
|
13
|
+
- Delegate every reading and analysis stage. Never read logs, test output or
|
|
14
|
+
large files into its own context.
|
|
15
|
+
- Split the work into steps small enough that each one names the files it touches.
|
|
16
|
+
- Track state through `state.py` after every stage. The state file, not the
|
|
17
|
+
conversation, is what survives.
|
|
18
|
+
- Decide when to escalate a model tier, one task at a time, against the triggers
|
|
19
|
+
in `policies/risk-tiers.json`.
|
|
20
|
+
- Write the final summary the human reads.
|
|
21
|
+
|
|
22
|
+
## What the manager must not do
|
|
23
|
+
|
|
24
|
+
- Skip a stage because the task looks easy. Make it lightweight instead, and
|
|
25
|
+
record that it happened.
|
|
26
|
+
- Expand scope. A discovered problem goes into `project/known-risks.md`.
|
|
27
|
+
- Delegate the conclusion. The synthesis a human reads is written by the session.
|
|
28
|
+
- Commit, push, merge or deploy. The pipeline ends at human approval.
|
|
29
|
+
|
|
30
|
+
## Implementation
|
|
31
|
+
|
|
32
|
+
The manager implements approved steps itself, under this policy and under
|
|
33
|
+
`ai-scope-guard`. `ai-implementer` exists for mechanical, pattern-copying steps
|
|
34
|
+
and for when the human asks for it — not as the default.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Workflow: refactoring
|
|
2
|
+
|
|
3
|
+
Changing the shape of code without changing what it does. The most dangerous
|
|
4
|
+
workflow in a legacy codebase, because success is invisible.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
8
|
+
> profile T0–T2 run in direct mode — the session does every stage itself, in a
|
|
9
|
+
> few lines, with cheap readers and one `sonnet` review at T2 — and T3+ run the
|
|
10
|
+
> full pipeline with the delegations below.
|
|
11
|
+
|
|
12
|
+
| Stage | Who | Notes |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| DISCOVERY | `ai-discovery` | every caller, every test, every dynamic reference |
|
|
15
|
+
| CONTEXT | `ai-context` | with `legacy_constraints` filled properly |
|
|
16
|
+
| IMPACT ANALYSIS | `ai-discovery` | serialized data, cache keys, service ids, event names |
|
|
17
|
+
| RISK CLASSIFICATION | `ai-risk` | shared code is T3 minimum |
|
|
18
|
+
| PLAN | `ai-planner` | characterization tests as their own steps, before anything moves |
|
|
19
|
+
| PLAN REVIEW | `ai-reviewer` | always, whatever the tier |
|
|
20
|
+
| IMPLEMENTATION | the session | one mechanical transformation per step |
|
|
21
|
+
| TEST | the session (`ai-tester` in `team`) | the same tests, unchanged, must still pass — the characterization tests for the moved code run inside their step, the full suite once at the end, then the e2e suite once; failures fixed as one batch |
|
|
22
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | looking specifically for behaviour drift |
|
|
23
|
+
| RELEASE REPORT | `ai-release` | |
|
|
24
|
+
| HUMAN APPROVAL | the human | |
|
|
25
|
+
|
|
26
|
+
## The order, which is not negotiable
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
characterization test → refactor → verify identical behaviour → (a different task) feature change
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- **Never** combine a refactoring with a feature change. If the plan contains
|
|
35
|
+
both, it is two tasks.
|
|
36
|
+
- A test that has to be modified during a refactoring is a signal that behaviour
|
|
37
|
+
changed. Stop and say so.
|
|
38
|
+
- Renaming something that appears in a string — a service id, a template name, a
|
|
39
|
+
queue name, a route name, a column — is not a rename, it is a migration.
|
|
40
|
+
- If the only justification is "this is cleaner", the task needs a human to
|
|
41
|
+
confirm it is worth the risk before it starts.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Workflow: refactoring
|
|
2
|
+
|
|
3
|
+
Changing the shape of code without changing what it does. The most dangerous
|
|
4
|
+
workflow in a legacy codebase, because success is invisible.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
8
|
+
> profile T0–T2 run in direct mode — the session does every stage itself, in a
|
|
9
|
+
> few lines, with cheap readers and one `sonnet` review at T2 — and T3+ run the
|
|
10
|
+
> full pipeline with the delegations below.
|
|
11
|
+
|
|
12
|
+
| Stage | Who | Notes |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| DISCOVERY | `ai-discovery` | every caller, every test, every dynamic reference |
|
|
15
|
+
| CONTEXT | `ai-context` | with `legacy_constraints` filled properly |
|
|
16
|
+
| IMPACT ANALYSIS | `ai-discovery` | serialized data, cache keys, service ids, event names |
|
|
17
|
+
| RISK CLASSIFICATION | `ai-risk` | shared code is T3 minimum |
|
|
18
|
+
| PLAN | `ai-planner` | characterization tests as their own steps, before anything moves |
|
|
19
|
+
| PLAN REVIEW | `ai-reviewer` | always, whatever the tier |
|
|
20
|
+
| IMPLEMENTATION | the session | one mechanical transformation per step |
|
|
21
|
+
| TEST | the session (`ai-tester` in `team`) | the same tests, unchanged, must still pass; one full run at the end, failures fixed as one batch |
|
|
22
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | looking specifically for behaviour drift |
|
|
23
|
+
| RELEASE REPORT | `ai-release` | |
|
|
24
|
+
| HUMAN APPROVAL | the human | |
|
|
25
|
+
|
|
26
|
+
## The order, which is not negotiable
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
characterization test → refactor → verify identical behaviour → (a different task) feature change
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- **Never** combine a refactoring with a feature change. If the plan contains
|
|
35
|
+
both, it is two tasks.
|
|
36
|
+
- A test that has to be modified during a refactoring is a signal that behaviour
|
|
37
|
+
changed. Stop and say so.
|
|
38
|
+
- Renaming something that appears in a string — a service id, a template name, a
|
|
39
|
+
queue name, a route name, a column — is not a rename, it is a migration.
|
|
40
|
+
- If the only justification is "this is cleaner", the task needs a human to
|
|
41
|
+
confirm it is worth the risk before it starts.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Workflow: hotfix
|
|
2
|
+
|
|
3
|
+
Production is broken now. Stages get shorter; none of them disappears.
|
|
4
|
+
|
|
5
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
6
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
7
|
+
> profile T0–T3 run in direct mode — the session does every stage itself, in a
|
|
8
|
+
> few lines, with cheap readers and one review (BALANCED at T2; STRONG at T3,
|
|
9
|
+
> whose plan the human approves in plan mode) — and T4+ run the full pipeline
|
|
10
|
+
> with the delegations below.
|
|
11
|
+
|
|
12
|
+
| Stage | Who | Notes |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| DISCOVERY | `ai-discovery` | narrow: the failing path only |
|
|
15
|
+
| CONTEXT | the session, inline | a paragraph, recorded in the state file |
|
|
16
|
+
| RISK CLASSIFICATION | `ai-risk` | the tier of the code being touched, not of the urgency |
|
|
17
|
+
| PLAN | `ai-planner` or the session | the smallest change that stops the bleeding |
|
|
18
|
+
| IMPLEMENTATION | the session | one step |
|
|
19
|
+
| TEST | the session (`ai-tester` in `team`) | at minimum, a test that reproduces the incident, run scoped; the full command once after the fix, then e2e only if the incident is in a flow it covers; failures fixed as one batch |
|
|
20
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | short, focused on "what else does this touch" |
|
|
21
|
+
| SECURITY REVIEW | `ai-security` | if the incident is a security incident |
|
|
22
|
+
| RELEASE REPORT | `ai-release` | short form, but rollback is mandatory |
|
|
23
|
+
| HUMAN APPROVAL | the human | always, and usually faster than the rest |
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
- Urgency lowers the *depth* of a stage, never its existence. The risk tier is a
|
|
28
|
+
property of the code, not of how loudly someone is asking.
|
|
29
|
+
- A hotfix is the smallest possible change. Everything else — the real fix, the
|
|
30
|
+
cleanup, the missing test — becomes a follow-up task, written down before the
|
|
31
|
+
hotfix is approved so it does not evaporate when the incident closes.
|
|
32
|
+
- Record what actually happened in `project/known-risks.md`: the trigger, the
|
|
33
|
+
detection, and what would have caught it earlier.
|
|
34
|
+
- Never disable a test or a check to get a hotfix out. If CI is the obstacle, a
|
|
35
|
+
human decides that, explicitly.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Workflow: bugfix
|
|
2
|
+
|
|
3
|
+
Something behaves wrongly. The goal is the smallest change that fixes it without
|
|
4
|
+
changing anything else.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
8
|
+
> profile T0–T2 run in direct mode — the session does every stage itself, in a
|
|
9
|
+
> few lines, with cheap readers and one BALANCED review at T2 — and T3+ run the
|
|
10
|
+
> full pipeline with the delegations below.
|
|
11
|
+
|
|
12
|
+
| Stage | Who | Notes |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| DISCOVERY | `ai-discovery` | reproduce first: find the exact path that produces the symptom |
|
|
15
|
+
| CONTEXT | `ai-context` | include the *correct* behaviour and where it is defined |
|
|
16
|
+
| IMPACT ANALYSIS | `ai-discovery` | who else depends on the current, wrong behaviour |
|
|
17
|
+
| RISK CLASSIFICATION | `ai-risk` | a bug in a payment path is still T4 |
|
|
18
|
+
| PLAN | `ai-planner` | failing test first, then the fix |
|
|
19
|
+
| IMPLEMENTATION | the session | the failing test is its own step |
|
|
20
|
+
| TEST | the session (`ai-tester` in `team`) | the new test is shown failing before the fix; each step runs only its own scoped tests; the full verification command runs once after the last step, to the end, then the e2e suite once; every failure fixed as one batch |
|
|
21
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | T2 and above |
|
|
22
|
+
| SECURITY REVIEW | `ai-security` | if the bug was a security bug, always |
|
|
23
|
+
| RELEASE REPORT | `ai-release` | |
|
|
24
|
+
| HUMAN APPROVAL | the human | |
|
|
25
|
+
|
|
26
|
+
## Specific to this workflow
|
|
27
|
+
|
|
28
|
+
- **Write the failing test first.** A bugfix without a test that failed before it
|
|
29
|
+
is a bugfix nobody can prove.
|
|
30
|
+
- Find out *why* the bug exists before fixing it. A bug that is deliberate
|
|
31
|
+
behaviour somebody depends on is not a bug; it is a requirements conflict, and
|
|
32
|
+
it goes back to the human.
|
|
33
|
+
- Resist the urge to fix the surrounding code. Note it, fix the bug.
|
|
34
|
+
- If the same bug exists in three places, fix the one that was reported and list
|
|
35
|
+
the other two in `project/known-risks.md`.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Workflow: hotfix
|
|
2
|
+
|
|
3
|
+
Production is broken now. Stages get shorter; none of them disappears.
|
|
4
|
+
|
|
5
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
6
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
7
|
+
> profile T0–T2 run in direct mode — the session does every stage itself, in a
|
|
8
|
+
> few lines, with cheap readers and one BALANCED review at T2 — and T3+ run the
|
|
9
|
+
> full pipeline with the delegations below.
|
|
10
|
+
|
|
11
|
+
| Stage | Who | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| DISCOVERY | `ai-discovery` | narrow: the failing path only |
|
|
14
|
+
| CONTEXT | the session, inline | a paragraph, recorded in the state file |
|
|
15
|
+
| RISK CLASSIFICATION | `ai-risk` | the tier of the code being touched, not of the urgency |
|
|
16
|
+
| PLAN | `ai-planner` or the session | the smallest change that stops the bleeding |
|
|
17
|
+
| IMPLEMENTATION | the session | one step |
|
|
18
|
+
| TEST | the session (`ai-tester` in `team`) | at minimum, a test that reproduces the incident, run scoped; the full command once after the fix, then e2e only if the incident is in a flow it covers; failures fixed as one batch |
|
|
19
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | short, focused on "what else does this touch" |
|
|
20
|
+
| SECURITY REVIEW | `ai-security` | if the incident is a security incident |
|
|
21
|
+
| RELEASE REPORT | `ai-release` | short form, but rollback is mandatory |
|
|
22
|
+
| HUMAN APPROVAL | the human | always, and usually faster than the rest |
|
|
23
|
+
|
|
24
|
+
## Rules
|
|
25
|
+
|
|
26
|
+
- Urgency lowers the *depth* of a stage, never its existence. The risk tier is a
|
|
27
|
+
property of the code, not of how loudly someone is asking.
|
|
28
|
+
- A hotfix is the smallest possible change. Everything else — the real fix, the
|
|
29
|
+
cleanup, the missing test — becomes a follow-up task, written down before the
|
|
30
|
+
hotfix is approved so it does not evaporate when the incident closes.
|
|
31
|
+
- Record what actually happened in `project/known-risks.md`: the trigger, the
|
|
32
|
+
detection, and what would have caught it earlier.
|
|
33
|
+
- Never disable a test or a check to get a hotfix out. If CI is the obstacle, a
|
|
34
|
+
human decides that, explicitly.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Workflow: refactoring
|
|
2
|
+
|
|
3
|
+
Changing the shape of code without changing what it does. The most dangerous
|
|
4
|
+
workflow in a legacy codebase, because success is invisible.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated. In the default `solo`
|
|
8
|
+
> profile T0–T4 run in direct mode — the session does every stage itself, in a
|
|
9
|
+
> few lines, with cheap readers and one review (BALANCED at T2/T3, and only
|
|
10
|
+
> when a sensor is red; STRONG at T4, whose plan the human approves in plan
|
|
11
|
+
> mode) — and T5+ run the full pipeline with the delegations below.
|
|
12
|
+
|
|
13
|
+
| Stage | Who | Notes |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| DISCOVERY | `ai-discovery` | every caller, every test, every dynamic reference |
|
|
16
|
+
| CONTEXT | `ai-context` | with `legacy_constraints` filled properly |
|
|
17
|
+
| IMPACT ANALYSIS | `ai-discovery` | serialized data, cache keys, service ids, event names |
|
|
18
|
+
| RISK CLASSIFICATION | `ai-risk` | shared code is T4 minimum |
|
|
19
|
+
| PLAN | `ai-planner` | characterization tests as their own steps, before anything moves |
|
|
20
|
+
| PLAN REVIEW | `ai-reviewer` | always, whatever the tier |
|
|
21
|
+
| IMPLEMENTATION | the session | one mechanical transformation per step |
|
|
22
|
+
| TEST | the session (`ai-tester` in `team`) | the same tests, unchanged, must still pass — the characterization tests for the moved code run inside their step, the full suite once at the end, then the e2e suite once; failures fixed as one batch |
|
|
23
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | looking specifically for behaviour drift |
|
|
24
|
+
| RELEASE REPORT | `ai-release` | |
|
|
25
|
+
| HUMAN APPROVAL | the human | |
|
|
26
|
+
|
|
27
|
+
## The order, which is not negotiable
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
characterization test → refactor → verify identical behaviour → (a different task) feature change
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Rules
|
|
34
|
+
|
|
35
|
+
- **Never** combine a refactoring with a feature change. If the plan contains
|
|
36
|
+
both, it is two tasks.
|
|
37
|
+
- A test that has to be modified during a refactoring is a signal that behaviour
|
|
38
|
+
changed. Stop and say so.
|
|
39
|
+
- Renaming something that appears in a string — a service id, a template name, a
|
|
40
|
+
queue name, a route name, a column — is not a rename, it is a migration.
|
|
41
|
+
- If the only justification is "this is cleaner", the task needs a human to
|
|
42
|
+
confirm it is worth the risk before it starts.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Constitution — {{PROJECT}}
|
|
2
|
+
|
|
3
|
+
<!-- The 10–15 principles this project does not negotiate, one line each, numbered C1…;
|
|
4
|
+
/rr-spec and the planner cite them. Under 15: what is not here lives in .ai/policies/. -->
|
|
5
|
+
|
|
6
|
+
C1. Production behaviour is the source of truth; what looks wrong may be load-bearing.
|
|
7
|
+
C2. A bugfix starts with the failing test; legacy behaviour gets a characterization test before it changes.
|
|
8
|
+
C3. A refactoring changes no behaviour and is never mixed with a feature.
|
|
9
|
+
C4. Every step names its files; scope grows only by amending the plan.
|
|
10
|
+
C5. No agent merges or deploys; an agent commits, pushes or approves only by running, verbatim and once, a command a human picked in the dialog, as the harness recorded; else a human runs it outside.
|
|
11
|
+
C6. <!-- project principle — filled by /rr-setup from the survey, confirmed by you -->
|
|
12
|
+
C7. <!-- project principle -->
|
|
13
|
+
C8. <!-- project principle -->
|
|
14
|
+
C9. <!-- project principle -->
|
|
15
|
+
C10. <!-- project principle -->
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Workflow: refactoring
|
|
2
|
+
|
|
3
|
+
Changing the shape of code without changing what it does. The most dangerous
|
|
4
|
+
workflow in a legacy codebase, because success is invisible.
|
|
5
|
+
|
|
6
|
+
> Who runs a stage is set by `pipeline_profile` in `policies/risk-tiers.json`.
|
|
7
|
+
> The table names the agent for when a stage is delegated; in the default `solo`
|
|
8
|
+
> profile the session does the stage inline up to the tier where the profile
|
|
9
|
+
> delegates it.
|
|
10
|
+
|
|
11
|
+
| Stage | Who | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| DISCOVERY | `ai-discovery` | every caller, every test, every dynamic reference |
|
|
14
|
+
| CONTEXT | `ai-context` | with `legacy_constraints` filled properly |
|
|
15
|
+
| IMPACT ANALYSIS | `ai-discovery` | serialized data, cache keys, service ids, event names |
|
|
16
|
+
| RISK CLASSIFICATION | `ai-risk` | shared code is T3 minimum |
|
|
17
|
+
| PLAN | `ai-planner` | characterization tests as their own steps, before anything moves |
|
|
18
|
+
| PLAN REVIEW | `ai-reviewer` | always, whatever the tier |
|
|
19
|
+
| IMPLEMENTATION | the session | one mechanical transformation per step |
|
|
20
|
+
| TEST | `ai-tester` | the same tests, unchanged, must still pass |
|
|
21
|
+
| ADVERSARIAL REVIEW | `ai-reviewer` | looking specifically for behaviour drift |
|
|
22
|
+
| RELEASE REPORT | `ai-release` | |
|
|
23
|
+
| HUMAN APPROVAL | the human | |
|
|
24
|
+
|
|
25
|
+
## The order, which is not negotiable
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
characterization test → refactor → verify identical behaviour → (a different task) feature change
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
|
|
33
|
+
- **Never** combine a refactoring with a feature change. If the plan contains
|
|
34
|
+
both, it is two tasks.
|
|
35
|
+
- A test that has to be modified during a refactoring is a signal that behaviour
|
|
36
|
+
changed. Stop and say so.
|
|
37
|
+
- Renaming something that appears in a string — a service id, a template name, a
|
|
38
|
+
queue name, a route name, a column — is not a rename, it is a migration.
|
|
39
|
+
- If the only justification is "this is cleaner", the task needs a human to
|
|
40
|
+
confirm it is worth the risk before it starts.
|