safeword 0.71.0 → 0.72.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.
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks.json +5 -5
- package/codex-plugin/skills/audit/SKILL.md +55 -13
- package/codex-plugin/skills/bdd/SKILL.md +13 -10
- package/codex-plugin/skills/bdd/references/DISCOVERY.md +22 -7
- package/codex-plugin/skills/bdd/references/PLAN_IMPLEMENTATION.md +12 -2
- package/codex-plugin/skills/bdd/references/TDD.md +6 -6
- package/codex-plugin/skills/closeout/SKILL.md +124 -0
- package/codex-plugin/skills/quality-review/SKILL.md +65 -11
- package/codex-plugin/skills/retro-filer/SKILL.md +9 -4
- package/codex-plugin/skills/review-spec/SKILL.md +28 -3
- package/codex-plugin/skills/self-review/SKILL.md +9 -3
- package/codex-plugin/skills/verify/SKILL.md +8 -0
- package/dist/{architecture-XECMMTJO.js → architecture-GOUJM5NE.js} +3 -3
- package/dist/{architecture-document-WW2KDC7G.js → architecture-document-KFR4JDUT.js} +3 -3
- package/dist/{boundary-2VG6JWGW.js → boundary-J2RW4N3E.js} +10 -8
- package/dist/{boundary-2VG6JWGW.js.map → boundary-J2RW4N3E.js.map} +1 -1
- package/dist/chunk-2MQTOSGG.js +312 -0
- package/dist/chunk-2MQTOSGG.js.map +1 -0
- package/dist/{chunk-ABCSHC5I.js → chunk-5KUTV6L5.js} +16 -2
- package/dist/chunk-5KUTV6L5.js.map +1 -0
- package/dist/{chunk-2EHR2PVO.js → chunk-7NZ26QJP.js} +4 -4
- package/dist/{chunk-VXFLYFZ6.js → chunk-AF6L253C.js} +2 -2
- package/dist/{chunk-Z6LFUJ6B.js → chunk-F4CA33GP.js} +229 -157
- package/dist/chunk-F4CA33GP.js.map +1 -0
- package/dist/{chunk-YEMSUOB2.js → chunk-I5QEPYVK.js} +107 -73
- package/dist/chunk-I5QEPYVK.js.map +1 -0
- package/dist/{chunk-DTDUW7QI.js → chunk-KWBGQ2YZ.js} +6 -6
- package/dist/chunk-KWBGQ2YZ.js.map +1 -0
- package/dist/{chunk-7MZST3KV.js → chunk-OSBX5BZS.js} +40 -16
- package/dist/chunk-OSBX5BZS.js.map +1 -0
- package/dist/{chunk-HU7KMEIQ.js → chunk-OWGNCT45.js} +2 -2
- package/dist/{chunk-QQI3PT2V.js → chunk-PAC2VLLK.js} +21 -35
- package/dist/chunk-PAC2VLLK.js.map +1 -0
- package/dist/chunk-PSKZASFR.js +36 -0
- package/dist/chunk-PSKZASFR.js.map +1 -0
- package/dist/{chunk-QVI4TWIU.js → chunk-QPWX5JXI.js} +2 -2
- package/dist/{chunk-PZHHGMVB.js → chunk-RFP2MSVO.js} +1 -1
- package/dist/chunk-RFP2MSVO.js.map +1 -0
- package/dist/{chunk-WHNYCYU6.js → chunk-RLH5PLSD.js} +2 -2
- package/dist/{chunk-PKWJP43G.js → chunk-UM7PJKBV.js} +2 -2
- package/dist/chunk-Y6LUZKTN.js +144 -0
- package/dist/chunk-Y6LUZKTN.js.map +1 -0
- package/dist/{chunk-IRKICK2K.js → chunk-ZFM3XTN3.js} +3 -3
- package/dist/{chunk-WZDLZULJ.js → chunk-ZQCKTQKJ.js} +2 -2
- package/dist/cleanup-STJVSD7S.js +294 -0
- package/dist/cleanup-STJVSD7S.js.map +1 -0
- package/dist/cli.js +99 -29
- package/dist/cli.js.map +1 -1
- package/dist/{codex-hook-EOWMR47H.js → codex-hook-HBEPMPEK.js} +5 -5
- package/dist/{codify-ZAEKSB2M.js → codify-L2V7J2GJ.js} +4 -4
- package/dist/{configured-paths-CSRPNDRS.js → configured-paths-TXRFWRTV.js} +2 -2
- package/dist/contract-BJD62H2W.js +13 -0
- package/dist/contract-BJD62H2W.js.map +1 -0
- package/dist/{converge-setup-UMMCYSH2.js → converge-setup-6WS2RMSG.js} +37 -26
- package/dist/converge-setup-6WS2RMSG.js.map +1 -0
- package/dist/coordinator-P7SET5EM.js +1024 -0
- package/dist/coordinator-P7SET5EM.js.map +1 -0
- package/dist/{corpus-AFBBTLYZ.js → corpus-XW3XX3F5.js} +4 -4
- package/dist/{feature-directories-FUAV6QSQ.js → feature-directories-36DL4FAU.js} +3 -3
- package/dist/{learning-sync-OPK7A6IA.js → learning-sync-6ESNEZTX.js} +2 -2
- package/dist/{legacy-global-guidance-S6YM7CLF.js → legacy-global-guidance-JPJBHFMW.js} +4 -4
- package/dist/{lint-gherkin-MK3ZICLF.js → lint-gherkin-UHMNF5SD.js} +4 -4
- package/dist/{migrate-codex-plugin-QAPK7USM.js → migrate-codex-plugin-CPLYYCGP.js} +8 -8
- package/dist/{plan-DNSAGZEC.js → plan-RRN2ESJ7.js} +9 -9
- package/dist/profile-DM4UNHMN.js +17 -0
- package/dist/{remove-NFOKH6VW.js → remove-GNAT5APA.js} +9 -9
- package/dist/{retro-T5NS6SAH.js → retro-XO7CALV4.js} +17 -7
- package/dist/retro-XO7CALV4.js.map +1 -0
- package/dist/{retro-draft-spool-XAD5F76M.js → retro-draft-spool-OU4YMZQO.js} +6 -2
- package/dist/{run-IUKI4FQ3.js → run-HQCZ67WE.js} +2 -2
- package/dist/status-5DDTQIJU.js +16 -0
- package/dist/status-5DDTQIJU.js.map +1 -0
- package/dist/{status-7E3ZIJJL.js → status-ILKQIXSD.js} +14 -13
- package/dist/{status-7E3ZIJJL.js.map → status-ILKQIXSD.js.map} +1 -1
- package/dist/{sync-tracker-G37ZNGZU.js → sync-tracker-EMEVBKQS.js} +4 -4
- package/dist/{test-plan-VGGQW5VP.js → test-plan-QAQT6OXT.js} +2 -2
- package/dist/{ticket-new-GDGYKYDR.js → ticket-new-Y2QIVBHL.js} +3 -3
- package/dist/{ticket-sync-YCOPASYY.js → ticket-sync-5XRY6Q2Z.js} +3 -3
- package/dist/ticket-sync-5XRY6Q2Z.js.map +1 -0
- package/package.json +3 -1
- package/templates/SAFEWORD.md +11 -1
- package/templates/agents/safeword-retro-filer.md +11 -6
- package/templates/commands/audit.md +1 -1
- package/templates/commands/bdd.md +1 -1
- package/templates/commands/closeout.md +5 -0
- package/templates/commands/debug.md +1 -1
- package/templates/commands/quality-review.md +1 -1
- package/templates/commands/refactor.md +1 -1
- package/templates/commands/retro.md +1 -1
- package/templates/commands/review-spec.md +1 -1
- package/templates/commands/self-review.md +4 -0
- package/templates/commands/spike.md +1 -1
- package/templates/commands/testing.md +1 -1
- package/templates/commands/verify.md +1 -1
- package/templates/cursor/rules/bdd-core.mdc +1 -1
- package/templates/cursor/rules/bdd-discovery.mdc +1 -1
- package/templates/cursor/rules/bdd-done.mdc +1 -1
- package/templates/cursor/rules/bdd-plan-implementation.mdc +1 -1
- package/templates/cursor/rules/bdd-scenarios.mdc +1 -1
- package/templates/cursor/rules/bdd-splitting.mdc +1 -1
- package/templates/cursor/rules/bdd-tdd.mdc +1 -1
- package/templates/cursor/rules/bdd-verify.mdc +1 -1
- package/templates/cursor/rules/safeword-brainstorming.mdc +1 -1
- package/templates/cursor/rules/safeword-debugging.mdc +1 -1
- package/templates/cursor/rules/safeword-elicitation.mdc +1 -1
- package/templates/cursor/rules/safeword-figure-it-out.mdc +1 -1
- package/templates/cursor/rules/safeword-quality-reviewing.mdc +1 -1
- package/templates/cursor/rules/safeword-refactoring.mdc +1 -1
- package/templates/cursor/rules/safeword-retro-filer.mdc +1 -1
- package/templates/cursor/rules/safeword-tdd-review.mdc +1 -1
- package/templates/cursor/rules/safeword-testing.mdc +1 -1
- package/templates/cursor/rules/safeword-ticket-system.mdc +1 -1
- package/templates/doc-templates/impl-plan-template.md +14 -4
- package/templates/guides/self-report-filing.md +15 -5
- package/templates/hooks/audit-principle-trace.ts +49 -0
- package/templates/hooks/codex/pre-tool-quality.ts +9 -0
- package/templates/hooks/cursor/before-shell-execution.ts +19 -10
- package/templates/hooks/lib/closeout-binding.ts +145 -0
- package/templates/hooks/lib/drain-retro-spool.ts +28 -0
- package/templates/hooks/lib/impl-plan.ts +22 -2
- package/templates/hooks/lib/lint.ts +2 -0
- package/templates/hooks/lib/namespace-root.ts +13 -0
- package/templates/hooks/lib/principle-trace.ts +173 -0
- package/templates/hooks/lib/project-knowledge.ts +39 -0
- package/templates/hooks/lib/retro-draft-spool.ts +57 -17
- package/templates/hooks/lib/retro-nudge.ts +3 -2
- package/templates/hooks/lib/review-ledger.ts +70 -11
- package/templates/hooks/post-tool-sync-learnings.ts +7 -3
- package/templates/hooks/pre-tool-architecture-stage.ts +7 -3
- package/templates/hooks/pre-tool-quality.ts +29 -7
- package/templates/hooks/resolve-namespace-root.ts +9 -3
- package/templates/hooks/resolve-project-knowledge.ts +10 -0
- package/templates/hooks/session-architecture-heal.ts +7 -3
- package/templates/hooks/session-auto-upgrade.ts +4 -0
- package/templates/hooks/stop-quality.ts +5 -4
- package/templates/hooks/stop-retro.ts +2 -0
- package/templates/hooks/write-review-stamp.ts +43 -5
- package/templates/principles-template.md +49 -0
- package/templates/scripts/closeout-cleanup.ts +843 -0
- package/templates/skills/audit/SKILL.md +55 -13
- package/templates/skills/bdd/DISCOVERY.md +22 -7
- package/templates/skills/bdd/PLAN_IMPLEMENTATION.md +12 -2
- package/templates/skills/bdd/SKILL.md +13 -10
- package/templates/skills/bdd/TDD.md +6 -6
- package/templates/skills/closeout/SKILL.md +125 -0
- package/templates/skills/quality-review/SKILL.md +65 -11
- package/templates/skills/retro-filer/SKILL.md +9 -4
- package/templates/skills/review-spec/SKILL.md +28 -3
- package/templates/skills/self-review/SKILL.md +9 -3
- package/templates/skills/verify/SKILL.md +8 -0
- package/dist/chunk-7MZST3KV.js.map +0 -1
- package/dist/chunk-ABCSHC5I.js.map +0 -1
- package/dist/chunk-DTDUW7QI.js.map +0 -1
- package/dist/chunk-PZHHGMVB.js.map +0 -1
- package/dist/chunk-QQI3PT2V.js.map +0 -1
- package/dist/chunk-YEMSUOB2.js.map +0 -1
- package/dist/chunk-Z6LFUJ6B.js.map +0 -1
- package/dist/converge-setup-UMMCYSH2.js.map +0 -1
- package/dist/retro-T5NS6SAH.js.map +0 -1
- /package/dist/{architecture-XECMMTJO.js.map → architecture-GOUJM5NE.js.map} +0 -0
- /package/dist/{architecture-document-WW2KDC7G.js.map → architecture-document-KFR4JDUT.js.map} +0 -0
- /package/dist/{chunk-2EHR2PVO.js.map → chunk-7NZ26QJP.js.map} +0 -0
- /package/dist/{chunk-VXFLYFZ6.js.map → chunk-AF6L253C.js.map} +0 -0
- /package/dist/{chunk-HU7KMEIQ.js.map → chunk-OWGNCT45.js.map} +0 -0
- /package/dist/{chunk-QVI4TWIU.js.map → chunk-QPWX5JXI.js.map} +0 -0
- /package/dist/{chunk-WHNYCYU6.js.map → chunk-RLH5PLSD.js.map} +0 -0
- /package/dist/{chunk-PKWJP43G.js.map → chunk-UM7PJKBV.js.map} +0 -0
- /package/dist/{chunk-IRKICK2K.js.map → chunk-ZFM3XTN3.js.map} +0 -0
- /package/dist/{chunk-WZDLZULJ.js.map → chunk-ZQCKTQKJ.js.map} +0 -0
- /package/dist/{codex-hook-EOWMR47H.js.map → codex-hook-HBEPMPEK.js.map} +0 -0
- /package/dist/{codify-ZAEKSB2M.js.map → codify-L2V7J2GJ.js.map} +0 -0
- /package/dist/{configured-paths-CSRPNDRS.js.map → configured-paths-TXRFWRTV.js.map} +0 -0
- /package/dist/{corpus-AFBBTLYZ.js.map → corpus-XW3XX3F5.js.map} +0 -0
- /package/dist/{feature-directories-FUAV6QSQ.js.map → feature-directories-36DL4FAU.js.map} +0 -0
- /package/dist/{learning-sync-OPK7A6IA.js.map → learning-sync-6ESNEZTX.js.map} +0 -0
- /package/dist/{legacy-global-guidance-S6YM7CLF.js.map → legacy-global-guidance-JPJBHFMW.js.map} +0 -0
- /package/dist/{lint-gherkin-MK3ZICLF.js.map → lint-gherkin-UHMNF5SD.js.map} +0 -0
- /package/dist/{migrate-codex-plugin-QAPK7USM.js.map → migrate-codex-plugin-CPLYYCGP.js.map} +0 -0
- /package/dist/{plan-DNSAGZEC.js.map → plan-RRN2ESJ7.js.map} +0 -0
- /package/dist/{retro-draft-spool-XAD5F76M.js.map → profile-DM4UNHMN.js.map} +0 -0
- /package/dist/{remove-NFOKH6VW.js.map → remove-GNAT5APA.js.map} +0 -0
- /package/dist/{ticket-sync-YCOPASYY.js.map → retro-draft-spool-OU4YMZQO.js.map} +0 -0
- /package/dist/{run-IUKI4FQ3.js.map → run-HQCZ67WE.js.map} +0 -0
- /package/dist/{sync-tracker-G37ZNGZU.js.map → sync-tracker-EMEVBKQS.js.map} +0 -0
- /package/dist/{test-plan-VGGQW5VP.js.map → test-plan-QAQT6OXT.js.map} +0 -0
- /package/dist/{ticket-new-GDGYKYDR.js.map → ticket-new-Y2QIVBHL.js.map} +0 -0
package/codex-plugin/hooks.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "bunx --bun safeword@0.
|
|
9
|
+
"command": "bunx --bun safeword@0.72.0 hook codex session-start --plugin-hook",
|
|
10
10
|
"timeout": 120,
|
|
11
11
|
"statusMessage": "Loading Safe Word standing instructions"
|
|
12
12
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hooks": [
|
|
20
20
|
{
|
|
21
21
|
"type": "command",
|
|
22
|
-
"command": "bunx --bun safeword@0.
|
|
22
|
+
"command": "bunx --bun safeword@0.72.0 hook codex pre-tool-use --plugin-hook",
|
|
23
23
|
"timeout": 30,
|
|
24
24
|
"statusMessage": "Checking Safe Word edit gates"
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"hooks": [
|
|
33
33
|
{
|
|
34
34
|
"type": "command",
|
|
35
|
-
"command": "bunx --bun safeword@0.
|
|
35
|
+
"command": "bunx --bun safeword@0.72.0 hook codex post-tool-use --plugin-hook",
|
|
36
36
|
"timeout": 30,
|
|
37
37
|
"statusMessage": "Surfacing Safe Word post-tool context"
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"hooks": [
|
|
46
46
|
{
|
|
47
47
|
"type": "command",
|
|
48
|
-
"command": "bunx --bun safeword@0.
|
|
48
|
+
"command": "bunx --bun safeword@0.72.0 hook codex user-prompt-submit --plugin-hook",
|
|
49
49
|
"timeout": 30,
|
|
50
50
|
"statusMessage": "Checking queued Safe Word prompt context"
|
|
51
51
|
}
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"hooks": [
|
|
59
59
|
{
|
|
60
60
|
"type": "command",
|
|
61
|
-
"command": "bunx --bun safeword@0.
|
|
61
|
+
"command": "bunx --bun safeword@0.72.0 hook codex stop --plugin-hook",
|
|
62
62
|
"timeout": 600,
|
|
63
63
|
"statusMessage": "Checking Safe Word stop continuation"
|
|
64
64
|
}
|
|
@@ -670,7 +670,35 @@ Test Quality:
|
|
|
670
670
|
|
|
671
671
|
Review the changed area from the printed scope. For each significantly changed area, check if related docs, readmes, or guides need updating. Flag stale, missing, or contradictory impacted documentation as errors. Documentation drift is never a warning; date-only staleness with no changed-code contradiction is repository-audit context, not a diff finding.
|
|
672
672
|
|
|
673
|
-
### 6.
|
|
673
|
+
### 6. Principle Trace Integrity
|
|
674
|
+
|
|
675
|
+
For the active ticket, when `impl-plan.md` declares project-principle alignment,
|
|
676
|
+
resolve the source using `paths.principles` (default
|
|
677
|
+
`<namespace-root>/principles.md`) and check the principle trace as **observable
|
|
678
|
+
facts only**:
|
|
679
|
+
|
|
680
|
+
- The named principle exists in the configured source.
|
|
681
|
+
- The trace contains a non-empty concrete consequence and proof.
|
|
682
|
+
- The proof reference resolves to recorded test, verification, or manual
|
|
683
|
+
evidence; an intentional conflict is named in Known deviations.
|
|
684
|
+
|
|
685
|
+
Report a missing source entry, incomplete mapping, dead evidence reference, or
|
|
686
|
+
unrecorded conflict as `[E010] Broken principle trace`. Do not judge whether a
|
|
687
|
+
principle was applicable, whether the consequence was a wise interpretation,
|
|
688
|
+
or whether an experience was genuinely delightful—those are adversarial
|
|
689
|
+
`quality-review` judgments. A plan with no declared applicable principle is not
|
|
690
|
+
an audit finding.
|
|
691
|
+
|
|
692
|
+
Run the factual checker below verbatim. Its sentinel keeps the executable audit
|
|
693
|
+
contract testable without turning semantic review into shell heuristics.
|
|
694
|
+
|
|
695
|
+
```bash
|
|
696
|
+
# principle-trace-check — E010 objective trace integrity only.
|
|
697
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2> /dev/null || pwd)}"
|
|
698
|
+
bun "$PROJECT_DIR/.safeword/hooks/audit-principle-trace.ts" "$PROJECT_DIR"
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### 7. Namespace Domain Docs
|
|
674
702
|
|
|
675
703
|
When a changed feature/spec or changed domain doc references them, reconcile the
|
|
676
704
|
three namespace domain docs — `personas.md`, `surfaces.md`, `glossary.md` —
|
|
@@ -687,20 +715,29 @@ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2> /dev/null
|
|
|
687
715
|
source "$PROJECT_DIR/.safeword/hooks/lib/audit-scope.sh"
|
|
688
716
|
audit_scope_initialize "$PROJECT_DIR"
|
|
689
717
|
|
|
690
|
-
# A branch audit skips unrelated domain-doc corpus drift. Deleted and
|
|
691
|
-
# type-changed feature/spec/domain files remain in reference review scope, so
|
|
692
|
-
# they still trigger this check for broken-reference review. A repository audit
|
|
693
|
-
# deliberately checks every domain doc and every discovered feature/spec.
|
|
694
|
-
if [ "$AUDIT_SCOPE_MODE" = "diff" ] && ! audit_scope_has_review_path_matching '(^|/)(personas|surfaces|glossary)\.md$|\.feature$|(^|/)spec\.md$'; then
|
|
695
|
-
exit 0
|
|
696
|
-
fi
|
|
697
|
-
|
|
698
718
|
# Resolve the namespace root (honors config paths.projectRoot in real runs).
|
|
699
719
|
# Fall back on directory existence — robust when the resolver hook is absent.
|
|
700
720
|
NS_ROOT="$(bun "$PROJECT_DIR/.safeword/hooks/resolve-namespace-root.ts" "$PROJECT_DIR" 2> /dev/null)"
|
|
701
721
|
[ -d "$NS_ROOT" ] || {
|
|
702
722
|
if [ -d "$PROJECT_DIR/.project" ]; then NS_ROOT="$PROJECT_DIR/.project"; else NS_ROOT="$PROJECT_DIR/.safeword-project"; fi
|
|
703
723
|
}
|
|
724
|
+
PERSONAS_FILE="$(bun "$PROJECT_DIR/.safeword/hooks/resolve-namespace-root.ts" "$PROJECT_DIR" personas personas.md 2> /dev/null)"
|
|
725
|
+
SURFACES_FILE="$(bun "$PROJECT_DIR/.safeword/hooks/resolve-namespace-root.ts" "$PROJECT_DIR" surfaces surfaces.md 2> /dev/null)"
|
|
726
|
+
GLOSSARY_FILE="$(bun "$PROJECT_DIR/.safeword/hooks/resolve-namespace-root.ts" "$PROJECT_DIR" glossary glossary.md 2> /dev/null)"
|
|
727
|
+
[ -n "$PERSONAS_FILE" ] || PERSONAS_FILE="$NS_ROOT/personas.md"
|
|
728
|
+
[ -n "$SURFACES_FILE" ] || SURFACES_FILE="$NS_ROOT/surfaces.md"
|
|
729
|
+
[ -n "$GLOSSARY_FILE" ] || GLOSSARY_FILE="$NS_ROOT/glossary.md"
|
|
730
|
+
|
|
731
|
+
# A branch audit skips unrelated domain-doc corpus drift. Include configured
|
|
732
|
+
# domain paths, whose basenames need not be personas.md/surfaces.md/glossary.md.
|
|
733
|
+
if [ "$AUDIT_SCOPE_MODE" = "diff" ] && ! audit_scope_has_review_path_matching '(^|/)(personas|surfaces|glossary)\.md$|\.feature$|(^|/)spec\.md$'; then
|
|
734
|
+
domain_path_changed=false
|
|
735
|
+
for configured_domain_file in "$PERSONAS_FILE" "$SURFACES_FILE" "$GLOSSARY_FILE"; do
|
|
736
|
+
configured_domain_path="${configured_domain_file#"$PROJECT_DIR"/}"
|
|
737
|
+
audit_scope_path_changed "$configured_domain_path" && domain_path_changed=true
|
|
738
|
+
done
|
|
739
|
+
[ "$domain_path_changed" = true ] || exit 0
|
|
740
|
+
fi
|
|
704
741
|
|
|
705
742
|
# Single-source the HTML-comment strip used by every check below. Strips
|
|
706
743
|
# same-line comments FIRST (`s/<!--.*-->//g`) then deletes multi-line comment
|
|
@@ -724,7 +761,11 @@ domain_docs_entry_count() {
|
|
|
724
761
|
# In a diff audit, report only a changed domain doc. An unchanged empty scaffold
|
|
725
762
|
# is existing debt, not a finding caused by an unrelated feature or spec change.
|
|
726
763
|
for doc in personas surfaces glossary; do
|
|
727
|
-
|
|
764
|
+
case "$doc" in
|
|
765
|
+
personas) dd_file="$PERSONAS_FILE" ;;
|
|
766
|
+
surfaces) dd_file="$SURFACES_FILE" ;;
|
|
767
|
+
glossary) dd_file="$GLOSSARY_FILE" ;;
|
|
768
|
+
esac
|
|
728
769
|
[ -f "$dd_file" ] || continue
|
|
729
770
|
domain_doc_path="${dd_file#"$PROJECT_DIR"/}"
|
|
730
771
|
[ "$AUDIT_SCOPE_MODE" = "repository" ] || audit_scope_path_changed "$domain_doc_path" || continue
|
|
@@ -749,7 +790,7 @@ feature_directories() {
|
|
|
749
790
|
return 127
|
|
750
791
|
fi
|
|
751
792
|
}
|
|
752
|
-
surfaces_file="$
|
|
793
|
+
surfaces_file="$SURFACES_FILE"
|
|
753
794
|
dd_file="$surfaces_file"
|
|
754
795
|
surfaces_path="${surfaces_file#"$PROJECT_DIR"/}"
|
|
755
796
|
if [ "$AUDIT_SCOPE_MODE" = "repository" ] || audit_scope_path_changed "$surfaces_path"; then
|
|
@@ -785,7 +826,7 @@ fi
|
|
|
785
826
|
# --- Persona drift (E009): spec **Persona:** code referenced but undefined ---
|
|
786
827
|
# Spec lines only, comment-stripped (feature lineage tags carry ticket-ids, not
|
|
787
828
|
# personas). Suppressed when personas.md is empty/absent.
|
|
788
|
-
personas_file="$
|
|
829
|
+
personas_file="$PERSONAS_FILE"
|
|
789
830
|
tickets_dir="$NS_ROOT/tickets"
|
|
790
831
|
dd_file="$personas_file"
|
|
791
832
|
personas_path="${personas_file#"$PROJECT_DIR"/}"
|
|
@@ -923,7 +964,7 @@ fi
|
|
|
923
964
|
|
|
924
965
|
**Empty-doc offer (W008):** report the empty doc and point the user to its template — do **not** draft entries or write the file during the audit pass (read-only). Filling it is a follow-up the user approves.
|
|
925
966
|
|
|
926
|
-
**Coverage limitation:**
|
|
967
|
+
**Coverage limitation:** configured `paths.personas`, `paths.surfaces`, and `paths.glossary` are resolved before reconciliation. `safeword doctor` separately reports missing configured files and orphaned defaults. If the safeword feature-directory resolver is unavailable, W009 says E008 fell back to root `features/` only. Persona drift reads spec `**Persona:**` lines only — feature lineage tags are not a reliable persona source.
|
|
927
968
|
|
|
928
969
|
---
|
|
929
970
|
|
|
@@ -941,6 +982,7 @@ Report findings by severity with codes:
|
|
|
941
982
|
- [E007] Drifted layer→dir: `ARCHITECTURE.md` maps `domain` → `src/core/` but no such module path is in `architecture.generated.md`
|
|
942
983
|
- [E008] Surface drift: `@surface.safeword-cli` is referenced in `features/` but has no matching entry in `surfaces.md`
|
|
943
984
|
- [E009] Persona drift: persona code `DEV` is named in a spec `**Persona:**` line but has no matching entry in `personas.md`
|
|
985
|
+
- [E010] Broken principle trace: `Delight the user` points to `verify.md#persona-walkthrough`, but that evidence record does not exist
|
|
944
986
|
|
|
945
987
|
### Warnings (should review)
|
|
946
988
|
|
|
@@ -48,18 +48,21 @@ phase: implement # intake | define-behavior | scenario-gate | plan-implementatio
|
|
|
48
48
|
|
|
49
49
|
The **scenario-gate exit requires** an independent review of the scenarios — not
|
|
50
50
|
your own pass. (Your own inline pass is Tier 1: `$safeword:self-review`, per asset, as you
|
|
51
|
-
author.)
|
|
52
|
-
|
|
53
|
-
an explicit subagent — handed only the phase's artifacts and the ticket's scope,
|
|
54
|
-
applying the `$safeword:review-spec` procedure; **its** verdict decides. When
|
|
55
|
-
`crossModelReview` is on, that reviewer must be a **different model than the
|
|
56
|
-
author** — a same-model reviewer shares the author's blind spots. Prefer one of
|
|
57
|
-
comparable-or-better capability; never weaker. If you can't run a different
|
|
58
|
-
model, log a deliberate skip (`--skip "<reason>"`) rather than stamping a
|
|
59
|
-
same-model review. On a pass, record the stamp:
|
|
51
|
+
author.) Invoke the shared host-owned coordinator with only the phase artifacts
|
|
52
|
+
and ticket scope; its typed verdict decides:
|
|
60
53
|
|
|
61
54
|
```bash
|
|
62
|
-
|
|
55
|
+
safeword review run scenario-gate feature-file ticket-spec [legacy-test-definitions]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The coordinator prefers the opposite headless agent, labels a permitted
|
|
59
|
+
same-agent fallback as degraded, and blocks with one recovery action when no
|
|
60
|
+
safe route remains. Do not bypass it with a private subagent. On a result that
|
|
61
|
+
satisfies the configured policy, record the returned provenance in the stamp
|
|
62
|
+
(substitute the four values from `data` in the coordinator result):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bun .safeword/hooks/write-review-stamp.ts --author-agent "author-agent" --reviewer-agent "actual-reviewer" --independence "independence" --phase phase-name
|
|
63
66
|
```
|
|
64
67
|
|
|
65
68
|
If the reviewer finds blocking issues, fix them and re-review — don't stamp.
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
## Sub-phase gates
|
|
6
6
|
|
|
7
|
-
Intake advances through sub-phases (load personas/glossary/surfaces → JTBD → Rules → engineering scope). Each one ends with a **gate** — don't advance on your own momentum; present what you captured and get the user's signoff first. Three moves:
|
|
7
|
+
Intake advances through sub-phases (load principles/personas/glossary/surfaces → JTBD → Rules → engineering scope). Each one ends with a **gate** — don't advance on your own momentum; present what you captured and get the user's signoff first. Three moves:
|
|
8
8
|
|
|
9
9
|
1. **Present** the captured artifact verbatim — the JTBD list, the Rules list grouped by JTBD, or the Scope / Out of Scope / Done When block.
|
|
10
10
|
2. **Ask** the sub-phase's closing question (below).
|
|
11
11
|
3. **Wait** for confirmation. Any forward-moving reply advances — an explicit "looks good" / "proceed", or an amendment you fold in and re-present. A new concern loops back; you don't advance until it's resolved.
|
|
12
12
|
|
|
13
|
-
| Sub-phase
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
| Jobs To Be Done
|
|
17
|
-
| Rules
|
|
18
|
-
| Engineering scope
|
|
13
|
+
| Sub-phase | Closing question |
|
|
14
|
+
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| Principles / personas / glossary / surfaces | _"`<file>` is empty — add entries now, or proceed without?"_ (only when missing/empty) |
|
|
16
|
+
| Jobs To Be Done | _"Here's who asked, the cost of not doing it, and how reversible it is — plus the jobs it serves. Given that, is this a feature, or a task? And do the jobs cover who this serves and why?"_ |
|
|
17
|
+
| Rules | _"Does each job's criteria capture what 'done' means for the persona? Any to split, add, or drop?"_ |
|
|
18
|
+
| Engineering scope | _"Here's the scope / out-of-scope / done-when — ready to proceed?"_ |
|
|
19
19
|
|
|
20
20
|
**On resume** (picked up mid-sub-phase across sessions): re-present the captured artifact for re-confirmation rather than assuming the prior signoff still stands — context may have shifted.
|
|
21
21
|
|
|
@@ -23,6 +23,21 @@ Intake advances through sub-phases (load personas/glossary/surfaces → JTBD →
|
|
|
23
23
|
|
|
24
24
|
These gates are conversational discipline the agent runs — not a hook block. (Hook-enforced sub-phase tracking is future work, coordinated with phase-step-enforcement epic 172.)
|
|
25
25
|
|
|
26
|
+
## Load project principles
|
|
27
|
+
|
|
28
|
+
At intake start, read the configured principles file (`paths.principles`,
|
|
29
|
+
default `<namespace-root>/principles.md`). This is the project's source of truth
|
|
30
|
+
for durable decision policy. Do not copy the catalogue into the ticket and do
|
|
31
|
+
not force every principle to apply.
|
|
32
|
+
|
|
33
|
+
- **Missing or empty:** ask whether to add principles now or proceed without.
|
|
34
|
+
- **Applicable:** carry the principle forward only when it changes a Rule,
|
|
35
|
+
design choice, proof, or deliberate deviation.
|
|
36
|
+
- **Experiential:** translate it into observable Rules and, when appropriate, a
|
|
37
|
+
Rave Moment; tests prove the mechanics, not the emotion itself.
|
|
38
|
+
- **Technical:** keep product Rules technology-neutral and carry the principle
|
|
39
|
+
into plan-implementation, where alternatives and evidence belong.
|
|
40
|
+
|
|
26
41
|
## Load project personas
|
|
27
42
|
|
|
28
43
|
At intake start, read the configured personas file (`paths.personas`, default `<namespace-root>/personas.md`). This file is the project's source of truth for who features serve; later phases (JTBD authoring, criteria validation, scenario numbering) reference its entries.
|
|
@@ -21,6 +21,16 @@ worktree. Never reuse the spike's experimental code or commits.
|
|
|
21
21
|
2. **Then survey what exists** — after sketching the ideal, read the generated architecture state doc (`architecture.generated.md` — the machine-owned _what-is_) and the decision record (resolved from `paths.architecture`) for **reuse** candidates: components that already do the job, or do it better. Order matters: surveying first anchors the design to the status quo.
|
|
22
22
|
3. **Reconcile without sunk-cost conformance.** Existing architecture is changeable with a recorded decision, not a constraint to conform to. Reuse what's better; change what's worse — deliberately, with the change recorded (ADR lifecycle below).
|
|
23
23
|
|
|
24
|
+
## Apply project principles
|
|
25
|
+
|
|
26
|
+
Re-read the configured principles file (`paths.principles`, default
|
|
27
|
+
`<namespace-root>/principles.md`) so planning does not depend on intake context
|
|
28
|
+
surviving. Identify only the **applicable project principles**—do not enumerate
|
|
29
|
+
the catalogue as a checklist. For each applicable principle, record in Design
|
|
30
|
+
alignment: **principle → concrete consequence → proof**. Put an intentional
|
|
31
|
+
conflict in Known deviations with its reason. No applicable principle is a
|
|
32
|
+
valid `skip:`; vague “complies with principles” prose is not.
|
|
33
|
+
|
|
24
34
|
## Environment fluency
|
|
25
35
|
|
|
26
36
|
- **Map installed language skills and component skills to the scenarios** — for the languages the feature touches, check the installed skill packs (`.claude/skills/<lang>-*`) and note per-scenario which apply. Scope to the feature's touched code and surfaces: in a polyglot monorepo, surface only what's relevant, never the full inventory.
|
|
@@ -36,7 +46,7 @@ Scaffold from `.safeword/templates/impl-plan-template.md` (sibling to `ticket.md
|
|
|
36
46
|
|
|
37
47
|
- **Approach** — open with the riskiest assumption and the cheapest scenario that proves it; then the proof plan: for each scenario the primary proof (`unit`, `integration`, `E2E`, or `eval` per `testing/SKILL.md`'s highest practical scope rule), supporting proofs, at least one wiring test per new entry point, and the build order with the load-bearing slice first. Cover each **affected surface** the spec lists — name the proof that covers it or a per-surface `skip: <reason>`.
|
|
38
48
|
- **Decisions** — one row per significant technical choice: choice, alternatives, rejected-because, with the `$safeword:figure-it-out` evidence cited.
|
|
39
|
-
- **
|
|
49
|
+
- **Design alignment** — record applicable project principles with their concrete consequence and proof, then consult the architecture record (resolve `paths.architecture` in `.safeword/config.json`; default `.project/architecture.md`; a directory holds one ADR per `.md`, README excluded). Records exist: list the decisions this design honors. With applicable principles but no records, write `None recorded yet` for the architecture sub-entry and offer to draft the first ADR for a significant decision. With neither applicable principles nor architecture records, write `skip: no applicable principles or ADRs` and offer to draft the first ADR for a significant decision (technology choices spanning features, data ownership, cross-service contracts).
|
|
40
50
|
- **Known deviations** — where this deviates from guidance and why that's acceptable.
|
|
41
51
|
- **Doc impact** — which configured `docs.sources` surfaces the customer-visible changes touch, folded into the build order as tasks; internal-only: `skip: <reason>`.
|
|
42
52
|
- **Assessment triggers** — what would prompt revisiting these choices.
|
|
@@ -57,7 +67,7 @@ Scaffold from `.safeword/templates/impl-plan-template.md` (sibling to `ticket.md
|
|
|
57
67
|
|
|
58
68
|
## Exit: review, then (optionally) the user
|
|
59
69
|
|
|
60
|
-
1. **Independent review first.**
|
|
70
|
+
1. **Independent review first.** At review time, run `bun .safeword/hooks/resolve-project-knowledge.ts`, then run `safeword review run plan-implementation impl-plan.md spec.md ticket.md feature-file principles-file personas-file surfaces-file` with the current files identified by the resolver. The shared coordinator sends that bounded packet to the opposite headless agent when available; its typed verdict, failure classification, and independence level are authoritative, so do not substitute a private subagent. Give the reviewer the current `spec.md`, configured principles file, configured personas file, and configured surfaces file in that packet. The reviewer refutes the plan: challenge whether it selected the actually applicable principles, whether each concrete consequence follows from its principle, whether the proposed proof can prove that consequence, whether conflicts belong in Known deviations, whether the design fulfills each persona's JTBD, and whether any affected surface was omitted or lacks credible proof. Also check wrong-direction design, missed scenarios, and editorial padding via the deletion test. Fix findings, re-resolve the sources, re-review, then stamp the exit with the returned agent provenance (`write-review-stamp.ts --author-agent "author-agent" --reviewer-agent "actual-reviewer" --independence "independence" --phase plan-implementation`, where the review gate is enabled). Add `--model` only when the executed reviewer reports a verifiable model identifier; the coordinator never invents one. Human handoff happens **only after** this review passes — raw planning output is never presented for approval. Exception, any time: information only the user has (intent, priorities, constraints not in code or docs) routes to the user the moment the gap appears — `$safeword:elicit`.
|
|
61
71
|
2. **`designApprovalGate`** (in `.safeword/config.json`): **absent or off** — the reviewed plan advances autonomously; do not ask. **Enabled** — present the reviewed plan (riskiest assumption, build order, decisions) and wait for user approval before `implement`.
|
|
62
72
|
3. **Sessions without an interactive user** (cloud/headless — Claude Code on the Web, Codex Cloud, Cursor Cloud Agents): an enabled approval gate must not stall the container. Record the auto-decision as pending approval in the ticket work log and surface the reviewed plan in the session's reviewable output (PR description / session summary) — approval lands at PR review. Note: Cursor Cloud Agents run `preToolUse` hooks but not stop hooks, so enforcement rides the transition gate there, not stop-time nudges.
|
|
63
73
|
4. **Update frontmatter:** `phase: implement`. The pre-tool transition gate verifies `impl-plan.md` parses valid with status `planned` — a missing or invalid plan blocks the move with the fix named. A `phase_skips` justification satisfies phase provenance only — a new-flow feature (spec.md present) still needs the valid plan to enter implement.
|
|
@@ -153,7 +153,7 @@ Then reconcile the plan.
|
|
|
153
153
|
All scenarios complete → reconcile `impl-plan.md` against what actually shipped, **before** advancing to verify (the stop hook blocks `verify`/`done` while the plan still says `planned`):
|
|
154
154
|
|
|
155
155
|
1. **Walk the Decisions table** — for each row ask "did we actually do this, or did we change our mind?" Update changed rows: new choice, new rationale, the abandoned choice moves into Alternatives considered.
|
|
156
|
-
2. **Walk
|
|
156
|
+
2. **Walk Design alignment** — for applicable project principles and architecture claims, ask "did the implementation honor each stated consequence, and does its proof pass?" Move anything that deviated into **Known deviations** with the reason.
|
|
157
157
|
3. **Refresh Assessment triggers** — add triggers the implementation surfaced (e.g., "works at current scale, degrades past 10x").
|
|
158
158
|
4. **Flip the status line** to `**Status:** implemented`. The phase hook stamps the transition with real time (Claude Code — on other harnesses add a short transition entry yourself); log the reconciliation outcome ({N} decisions updated, {M} deviations recorded) as a narrative work-log entry.
|
|
159
159
|
|
|
@@ -169,20 +169,20 @@ surfaces a real spec, scope, value, or risk decision.
|
|
|
169
169
|
Off by default. When `.safeword/config.json` sets `architectureReviewGate: true`, the stop hook blocks `verify`/`done` for a new-flow feature until its `impl-plan.md` design has been **independently reviewed** — the same propose-then-challenge discipline the scenario-gate applies to scenarios, now applied to the design. Two requirements:
|
|
170
170
|
|
|
171
171
|
1. **Cited evidence.** The Decisions section must carry a citation — a URL or a `[n]` source-reference marker — proving the choice was weighed against real evidence (the `$safeword:figure-it-out` trace), or an auditable `skip: <reason>`.
|
|
172
|
-
2. **A fresh-context review.**
|
|
172
|
+
2. **A fresh-context review.** Run `safeword review run plan-implementation impl-plan.md ticket-spec feature-file` so the shared coordinator gives only the bounded design evidence to the preferred opposite headless agent. Its typed result must satisfy the configured policy; a private subagent result cannot satisfy this gate. On a pass, stamp it:
|
|
173
173
|
|
|
174
174
|
```bash
|
|
175
|
-
bun .safeword/hooks/write-review-stamp.ts impl-plan
|
|
175
|
+
bun .safeword/hooks/write-review-stamp.ts --author-agent "author-agent" --reviewer-agent "actual-reviewer" --independence "independence" impl-plan
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
The stamp binds to the plan's current content, so editing the design after review invalidates it — re-review and re-stamp.
|
|
179
179
|
|
|
180
|
-
**Cross-model (`crossModelReview: true`).** The reviewer must run on a **different model than the author** — a same-model reviewer shares the author's blind spots (correlated errors). Prefer one of comparable-or-better capability; never weaker.
|
|
180
|
+
**Cross-model (`crossModelReview: true`).** The reviewer must run on a **different model than the author** — a same-model reviewer shares the author's blind spots (correlated errors). Prefer one of comparable-or-better capability; never weaker. Record a model only when the executed reviewer reports a verifiable identifier; the cross-agent coordinator does not guess a default model:
|
|
181
181
|
|
|
182
182
|
```bash
|
|
183
|
-
bun .safeword/hooks/write-review-stamp.ts --
|
|
183
|
+
bun .safeword/hooks/write-review-stamp.ts --author-agent "author-agent" --reviewer-agent "actual-reviewer" --model "verified-model" --independence "independence" impl-plan
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
The gate compares that tag against the author model (captured at SessionStart) and enforces **different only** — "comparable-or-better" is your judgment, not gate-checked. An absent tag fails closed.
|
|
186
|
+
The gate compares that tag against the author model (captured at SessionStart) and enforces **different only** — "comparable-or-better" is your judgment, not gate-checked. An absent tag fails closed. When `crossAgentReview` is `require`, degraded evidence and skips also fail closed; restore the opposite reviewer and rerun the coordinator. (This gate is stricter than quality-review's advisory loop, which may accept a labeled same-agent result under the default `prefer` policy.)
|
|
187
187
|
|
|
188
188
|
**Avoid bloat.**
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: closeout
|
|
3
|
+
description: Close a completed local delivery safely. Use when wrapping up a
|
|
4
|
+
finished coding session by verifying it, merging only with explicit authority,
|
|
5
|
+
running the mandatory retrospective, and cleaning the exact merged branch and
|
|
6
|
+
worktree. Do NOT use for cloud-agent tasks, unmerged work, or cleanup without
|
|
7
|
+
a pull request.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Closeout
|
|
11
|
+
|
|
12
|
+
Close a completed local GitHub delivery from observed state. Never compress the
|
|
13
|
+
workflow into “merge succeeded, so we are done.”
|
|
14
|
+
|
|
15
|
+
## 1. Prove delivery readiness
|
|
16
|
+
|
|
17
|
+
Run `$safeword:verify` for the current pull request head. Then observe the pull request
|
|
18
|
+
directly with structured `gh pr view --json` output. Require all of these before
|
|
19
|
+
any merge:
|
|
20
|
+
|
|
21
|
+
- local verification covers the current pull request head;
|
|
22
|
+
- all required checks pass;
|
|
23
|
+
- review requirements are satisfied; and
|
|
24
|
+
- the pull request is not a draft.
|
|
25
|
+
|
|
26
|
+
Collect and report every blocker. Missing, stale, failing, pending, unknown, or
|
|
27
|
+
ambiguous evidence means **no merge or cleanup**. A merge command's exit status
|
|
28
|
+
never proves that the pull request is merged.
|
|
29
|
+
|
|
30
|
+
## 2. Respect merge authority
|
|
31
|
+
|
|
32
|
+
Invocation alone grants no merge authority. Read authority only from the current user request;
|
|
33
|
+
historical, implied, or previously consumed authority is not available to a
|
|
34
|
+
resumed closeout.
|
|
35
|
+
|
|
36
|
+
- **No authority:** report that the delivery is ready and stop before merging.
|
|
37
|
+
- **Normal merge:** only an explicit current request for a normal merge permits a
|
|
38
|
+
policy-compliant `gh pr merge`. Never escalate a blocked normal merge.
|
|
39
|
+
- **Administrative merge:** only an explicit current request to perform an
|
|
40
|
+
administrative merge or bypass repository requirements permits `--admin`.
|
|
41
|
+
|
|
42
|
+
Merge authority is consumed when the merge action is attempted. Entering a merge
|
|
43
|
+
queue or enabling auto-merge consumes it too; later runs observe that queued
|
|
44
|
+
action and do not repeat it.
|
|
45
|
+
|
|
46
|
+
## 3. Re-observe merge truth and resume
|
|
47
|
+
|
|
48
|
+
After every merge command—success or error—re-observe the exact pull request:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
gh pr view PR_NUMBER --json state,mergedAt,mergeCommit,headRefName,headRefOid
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Continue only when `state` is exactly `MERGED` and the observed head still
|
|
55
|
+
matches the recorded pull request head. Queued, automatic, pending, unknown, or
|
|
56
|
+
unobservable results are not merge proof; report the recovery check and stop.
|
|
57
|
+
|
|
58
|
+
If the command reported an error but fresh observation proves the expected head
|
|
59
|
+
was merged, report that the remote merge succeeded, do not retry it, and proceed
|
|
60
|
+
to the mandatory retrospective. On every invocation, re-observe durable state
|
|
61
|
+
and continue only the unfinished suffix. Treat an absent cleanup target as
|
|
62
|
+
complete only after proving it was the exact planned target. If the pull request
|
|
63
|
+
is merged, its retrospective is complete, and its exact branch and worktree are
|
|
64
|
+
already absent, report that the session is already closed.
|
|
65
|
+
|
|
66
|
+
## 4. Complete the current session's retrospective
|
|
67
|
+
|
|
68
|
+
After merge is independently confirmed, invoke the cleanup guard in preview
|
|
69
|
+
mode. Its host hook supplies a short-lived, single-consumer binding to this exact
|
|
70
|
+
session (and Cursor transcript). A missing or expired binding fails closed;
|
|
71
|
+
there is no newest-session fallback and callers cannot nominate another receipt,
|
|
72
|
+
session, transcript, or spool.
|
|
73
|
+
|
|
74
|
+
The guard runs `safeword retro run --json` itself and accepts only a
|
|
75
|
+
successful result whose `data.agent_filing_needed` is `false` and whose derived
|
|
76
|
+
current session has an empty filing spool. Zero substantial findings and every
|
|
77
|
+
finding successfully filed are both complete outcomes.
|
|
78
|
+
|
|
79
|
+
Failed extraction, failed filing, pending drafts, malformed output, or an
|
|
80
|
+
identity mismatch means no cleanup. Report every failure and its recovery
|
|
81
|
+
action. A request to skip retro does not create a bypass: preserve the worktree
|
|
82
|
+
and branches and explain that the retrospective is required before cleanup.
|
|
83
|
+
|
|
84
|
+
## 5. Preview, confirm, and apply exact cleanup
|
|
85
|
+
|
|
86
|
+
Run the guard from the delivery worktree; preview is the default:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
bun .safeword/scripts/closeout-cleanup.ts --pr PR_NUMBER
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The preview reruns the project's verification, build, typecheck, BDD, and
|
|
93
|
+
dependency plans and binds the resulting repository state and exact PR identity
|
|
94
|
+
to `PLAN_DIGEST`. Report the complete operation list and all blockers. Do not
|
|
95
|
+
apply a blocked plan.
|
|
96
|
+
|
|
97
|
+
With the user's cleanup intent already established by invoking closeout, apply
|
|
98
|
+
only the unchanged preview:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
bun .safeword/scripts/closeout-cleanup.ts --pr PR_NUMBER --yes --plan PLAN_DIGEST
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The guard re-observes identity and executes only this order: worktree, remote
|
|
105
|
+
branch, local branch. It never passes `--force` to `git worktree remove`; remote
|
|
106
|
+
deletion uses an exact `--force-with-lease`, and squash/rebase-safe local deletion
|
|
107
|
+
uses `git update-ref -d` with the recorded old OID. Never use merge-time branch
|
|
108
|
+
deletion. Changed, dirty, locked, stale, protected, default, main, ambiguous, or
|
|
109
|
+
other-worktree targets are preserved and reported with a recovery action.
|
|
110
|
+
|
|
111
|
+
## 6. Report the durable result
|
|
112
|
+
|
|
113
|
+
Claim the session complete only after fresh observation proves every state.
|
|
114
|
+
Report:
|
|
115
|
+
|
|
116
|
+
- verification and the exact verified head;
|
|
117
|
+
- merged state and merge commit;
|
|
118
|
+
- retrospective completion and filing result;
|
|
119
|
+
- remote branch, local branch, and worktree state; and
|
|
120
|
+
- unresolved items (explicitly `none` when empty).
|
|
121
|
+
|
|
122
|
+
When blocked or partially complete, report every blocker and its recovery action,
|
|
123
|
+
including simultaneous blockers. Never hide a successful remote merge behind a
|
|
124
|
+
later local cleanup failure, and never describe a planned deletion as completed.
|
|
@@ -48,6 +48,56 @@ If in a BDD workflow, read the current ticket from `<namespace-root>/tickets/` a
|
|
|
48
48
|
| verify | Flaky-test & regression patterns, coverage gaps |
|
|
49
49
|
| done | CI/CD patterns, release checklists |
|
|
50
50
|
|
|
51
|
+
### Project-principle challenge
|
|
52
|
+
|
|
53
|
+
For a BDD ticket, run `bun .safeword/hooks/resolve-project-knowledge.ts` at the
|
|
54
|
+
start of each pass and read the current `principles`, `personas`, and `surfaces`
|
|
55
|
+
paths and content it returns (including overrides such as `paths.principles`).
|
|
56
|
+
Do not substitute labels or intake-era content.
|
|
57
|
+
With `impl-plan.md`, read those sources alongside the plan and work-product.
|
|
58
|
+
Treat the plan's
|
|
59
|
+
**principle → concrete consequence → proof** entries as claims to refute, not a
|
|
60
|
+
compliance checklist:
|
|
61
|
+
|
|
62
|
+
- Challenge applicability, including a principle the plan may have omitted;
|
|
63
|
+
report only omissions that would materially change behavior, design, proof,
|
|
64
|
+
or a deliberate deviation.
|
|
65
|
+
- Check that each consequence actually follows from the principle and appears
|
|
66
|
+
in the shipped work; check that the named proof demonstrates that consequence
|
|
67
|
+
rather than adjacent mechanics.
|
|
68
|
+
- An experiential principle is not proven by tests alone. Require the
|
|
69
|
+
user-facing signal the plan named—such as a persona walkthrough, usability
|
|
70
|
+
observation, or Rave Moment check—and state any evidence limitation.
|
|
71
|
+
- For sourcing or architecture principles, independently check current options,
|
|
72
|
+
extension boundaries, and compatibility claims against primary sources; do
|
|
73
|
+
not accept the plan's research summary as its own proof.
|
|
74
|
+
- Treat an intentional conflict as valid only when Known deviations names it
|
|
75
|
+
and explains the trade-off.
|
|
76
|
+
|
|
77
|
+
This is the judgment gate. `$safeword:audit` later checks trace integrity as observable
|
|
78
|
+
facts only; it does not decide whether a principle was applicable or wise.
|
|
79
|
+
|
|
80
|
+
### Persona and surface challenge
|
|
81
|
+
|
|
82
|
+
For a BDD ticket, read `spec.md` plus the configured persona and surface
|
|
83
|
+
inventories (`paths.personas` and `paths.surfaces`). Challenge whether the
|
|
84
|
+
shipped behavior fulfills each persona's JTBD and Rules, rather than merely
|
|
85
|
+
resolving a persona code. Then reconcile every affected surface against the
|
|
86
|
+
plan, scenarios, and verification output:
|
|
87
|
+
|
|
88
|
+
- Require one concrete proof result per affected surface, or a named `skip:`
|
|
89
|
+
with its limitation; an `@surface.*` tag alone is coverage intent, not surface
|
|
90
|
+
evidence.
|
|
91
|
+
- Check the surface evidence used the real surface boundary or names why that
|
|
92
|
+
boundary could not run. A generic unit test does not prove runtime, client,
|
|
93
|
+
protocol, or deployment parity.
|
|
94
|
+
- Challenge omitted personas or surfaces only when the source artifacts and
|
|
95
|
+
ticket scope make the omission material; do not turn either inventory into a
|
|
96
|
+
universal checklist.
|
|
97
|
+
|
|
98
|
+
Persona fulfillment and proof fidelity are review judgments. `$safeword:audit` owns only
|
|
99
|
+
unknown references, stale tags, and dead evidence links.
|
|
100
|
+
|
|
51
101
|
## 2. Research Angles
|
|
52
102
|
|
|
53
103
|
Run each angle that applies — angle _diversity_ is the lever, not search volume: **source-currency** + **risk/security** (this section), **supersession** + **primary-source docs** (§3). If the user gave a focus or scope restriction, apply it to **every** angle — don't use it only for the first search.
|
|
@@ -119,17 +169,21 @@ Run the review in passes until **Critical issues** come back None. A couple of p
|
|
|
119
169
|
|
|
120
170
|
Each pass:
|
|
121
171
|
|
|
122
|
-
1. **
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
172
|
+
1. **Run the shared independent-review coordinator.** After gathering any
|
|
173
|
+
current-source evidence needed by §1–3, pass only the bounded work-product
|
|
174
|
+
and scope to the host-owned coordinator:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
safeword review run quality-review changed-file [more-changed-files...]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Claude-authored work prefers headless Codex; Codex-authored work prefers
|
|
181
|
+
headless Claude. The coordinator uses a neutral snapshot, checks reviewer
|
|
182
|
+
provenance, preserves the exact preferred-route failure, and labels any
|
|
183
|
+
permitted same-agent fallback as degraded. Treat its typed result as the
|
|
184
|
+
review verdict. If it blocks, follow its one recovery action; do not invent
|
|
185
|
+
a private subagent route or mint passing evidence yourself.
|
|
186
|
+
|
|
133
187
|
2. **Triage.** Fix every **Critical issue** this pass. Apply the **Suggested
|
|
134
188
|
improvements** worth the change; list the rest — don't chase them.
|
|
135
189
|
3. **Decide.** Stop when **Critical issues = None**; remaining suggestions are
|
|
@@ -48,9 +48,14 @@ the host project.
|
|
|
48
48
|
|
|
49
49
|
4. After every successful comment or create, append exactly one compact JSON ack
|
|
50
50
|
`{"signature":"<signature>","issue":<number>}` to the sibling `.acks.jsonl`
|
|
51
|
-
file
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
file, then re-read it and exact-match that signature and destination. Remove
|
|
52
|
+
the draft only when the append succeeded and the exact ack is visible. If the
|
|
53
|
+
append or verification fails, leave the draft in place.
|
|
54
|
+
5. Create at most five new issues per run. Drain only by running
|
|
55
|
+
`bun .safeword/hooks/lib/drain-retro-spool.ts "<spool-path>"`; never rewrite or
|
|
56
|
+
delete the spool directly. The helper removes only drafts whose valid ack is
|
|
57
|
+
reader-visible, so unfiled or unacknowledged drafts remain. If tracker write
|
|
58
|
+
access is unavailable, leave the spool unchanged and report
|
|
59
|
+
`retro-filer: cannot file - <reason>`.
|
|
55
60
|
|
|
56
61
|
Finish with one line of counts: `retro-filer: filed 2, commented 1, remaining 0`.
|