@antoneeo/agentic-sdlc-skill 1.31.0 → 1.33.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/CHANGELOG.md CHANGED
@@ -2,30 +2,139 @@
2
2
 
3
3
  Tutte le modifiche significative a questa skill saranno documentate in questo file.
4
4
 
5
- ## [1.31.0] - 2026-09-05
6
-
7
- ### Changed
8
- - **Execute-Before-Specify now covers text-about-text (SKILL.md, Phase 3).** A
9
- deliverable that is itself text -- doctrine, a schema, a prompt, a reviewer
10
- definition -- is probed the same way as code: replay it against the recorded
11
- case that motivated it (the incident artifact, the tool-usage transcript, the
12
- review that missed the defect), red under the old text, green under the new.
13
- "No probe is possible" is shown, never declared. The exemption an earlier
14
- proposal would have granted was rejected on evidence: the unit cited as
15
- unprobeable text was a code unit that modified six production modules and
16
- shipped four assertion harnesses, while doctrine and prompt changes have been
17
- measured here by replay (three headless probes of a prompt change; an ad-hoc
18
- checklist that caught in one round what ten rounds missed). Paid for per this
19
- skill's own `vision.md` cumulative-ratchet rule: 67 words of illustration and
20
- rationale deleted from the same paragraph, net -2 words.
21
- - **Form budget belongs to the first draft (shared spine `review.md`,
22
- byte-identical x3).** The lean operative form is the FIRST draft's form, not
23
- the round-3 rescue: the review request states the artifact's line count
24
- against a budget the author fixed before drafting, and an artifact over budget
25
- is the reviewer's first finding, before content. The ~1,250 -> ~500 line
26
- measurement already in the file is its anchor. Spine delta is synced in the
27
- repo; kb and mkt ship it at their next release.
28
-
5
+ ## [1.33.0] - 2026-09-12
6
+
7
+ ### Added
8
+ - **F-048: the capability floor, and what may be delegated at all.** A review
9
+ run below the capability its judgement needs certifies the omission it was
10
+ there to catch. `review.md` now carries a floor — which tier may run which
11
+ role — with the rule that a tier may be lowered only where a **threshold
12
+ signal** scores the cheap answer, and an arbitration for the case where the
13
+ only independent rung sits under it (independence wins, both facts recorded).
14
+ `dispatch.md` gains the family-wide delegation boundary, keyed on whether a
15
+ pass's output is falsifiable and on its read/report ratio: a task whose brief
16
+ cannot be expressed as POINTERS is not delegable. `REVIEW_LOG` gains a
17
+ `model` column — tiers are client-relative capability levels, never provider
18
+ names. External evidence: cascade routing pays only where a threshold signal
19
+ exists, and multi-agent execution costs 3-15x the tokens and buys context
20
+ isolation rather than savings.
21
+ - **F-049: the floor reaches the AUTHOR, not only the gates.** A session's
22
+ floor is the highest floor among the roles it performs itself, and authoring
23
+ a governed artifact is a deep-floor role — its output is judgement and
24
+ nothing downstream scores it. Fails open by construction: a session that
25
+ cannot determine its own tier owes nothing. The reliably working half is
26
+ addressed to the user, in each package's README.
27
+ - **F-050: `benefit` — what the process caught, beside what it costs to read.**
28
+ The product's central claim becomes computable instead of asserted. It always
29
+ exits 0 and carries no verdict: a measurement that can fail a build becomes a
30
+ target, and a targeted measurement stops measuring.
31
+ - **F-051: the Hybrid seam leaves the mandatory read.** The devPNT ownership
32
+ matrix, triage equivalence, feature-state mapping and shadow discipline move
33
+ to a triggered `hybrid.md`; `SKILL.md` keeps a pointer carrying the trigger
34
+ and the consequence. Conservation is guarded by a digest stamped in the moved
35
+ file and computed from the PRE-MOVE source.
36
+
37
+ ### Fixed
38
+ - **F-053: nine defects a review on a DIFFERENT model found after six units
39
+ shipped.** Each of those six was reviewed in isolation, and each by the same
40
+ model family as its author; six rows reading "all findings folded" are one
41
+ loop, not two eyes. The scoped re-review `review.md` mandates had never been
42
+ run for seven unreleased rows — it has been now, late, and each row states
43
+ both verdicts WITH its limitation, because 35 findings across six of them
44
+ have no surviving per-finding record and no late round can certify them.
45
+ `benefit` printed "the share above is a floor, not a ceiling", which is
46
+ backwards — folding the post-implementation rows LOWERS the design share —
47
+ and excluded 46 of 117 rows in silence; it now prints a computed interval,
48
+ names the rows that state no count, and prints the read-cost TOTAL with the
49
+ support files itemised, because printing only the two terms let the one that
50
+ FELL be quoted while the one that GREW stayed lumped.
51
+ - **The mechanism behind five of those units' probes, recorded as an ADR.** Ten
52
+ assertions across six units were satisfiable by a LITERAL, because the probe
53
+ looked for a SHAPE in the output instead of recomputing the VALUE and
54
+ comparing. Every probe over a computed output now recomputes and compares and
55
+ carries a positive control on synthetic data; every probe over prose is
56
+ labelled a wording anchor.
57
+
58
+ ### Read cost
59
+ - `SKILL.md` **-7.9%** (49,413 -> 45,518 B) for a Standalone session. A Hybrid
60
+ L3 session reads **+5.6%** (`SKILL.md` + `hybrid.md`), and the package's
61
+ support files grow **+10.8%**: the cost did not fall so much as MOVE out of
62
+ the file the report prints. Stated here because the Vision's ceremony clause
63
+ counts relocated cost.
64
+
65
+ ## [1.32.1] - 2026-09-06
66
+
67
+ ### Fixed
68
+ - **F-046 shipped a hook that wired nowhere.** `wireRemindHookInto` used the
69
+ ORIENT hook's opt-out marker (`orient-hook-wired`) as its own. That file is
70
+ present on every machine that ever installed the skill, so the installer read
71
+ it as "the user opted out of the per-turn reminder" and never wrote the hook —
72
+ for everyone. Two smaller faults in the same function: the marker was checked
73
+ BEFORE testing whether the hook was already present, and no marker was ever
74
+ written after a successful wire, so the real opt-out could never arm. The hook
75
+ now has its own `remind-hook-wired` marker, checked after the presence test and
76
+ written only on success. Regression pinned in `scripts/test_clients.js` (red
77
+ against 1.32.0: an orient-marked machine got no hook).
78
+
79
+ ## [1.32.0] - 2026-09-06
80
+
81
+ ### Added
82
+ - **F-046: the protocol reaches every turn (`remind`, UserPromptSubmit, wired by
83
+ default).** `orient` fires once at session start and decays; a session that
84
+ never loads the skill never had the protocol at all. Measured 2026-09-06: a
85
+ release ran against a `GUIDE_release.md` the session never consulted, because
86
+ `SKILL.md` -- where the duty is written -- had not been read. `remind` prints
87
+ ONE constant line at every prompt, and its first duty is that one: decide
88
+ whether the skill governs the work in front of you and, if it does, LOAD it
89
+ once. The carrier is kb's F-041 item B, LIFTED into the shared spine rather
90
+ than duplicated, so all three lenses share one machine; each lens declares its
91
+ own line in `set_profile(remind_line=...)`. Installing the package wires it
92
+ machine-wide on Claude Code alongside the orientation hook, never instead of
93
+ it; removing the hook entry is a standing opt-out. Per-turn cost disclosed and
94
+ accepted by the owner (`vision/rulings.md` r19, the "no ceremony ratchet"
95
+ Non-Goal's second door), and bounded to stay flat by a contract the new shared
96
+ `scripts/test_remind.py` guards: constant text, zero reads, one line under 500
97
+ characters, argv ignored whole, always exit 0.
98
+
99
+ ### Changed
100
+ - **`guides.md` said something false about code guides.** It claimed `stale`
101
+ works unchanged for `source_kind: code` because "the code-excerpt snapshot
102
+ drifts when the code changes". A snapshot is a frozen copy and never drifts:
103
+ freshness is NOT mechanized there, and the duty is the author's twice -- when
104
+ you MODIFY code a comprehension guide describes, and when you merely READ one
105
+ before trusting it. Measured 2026-09-06: the guided module had gained 388
106
+ lines and lost 71 across four commits with `stale` silent.
107
+
108
+ - **The guide question moves to the analysis phase (SKILL.md).** Two lines in the
109
+ ANALYSIS -- does a CURRENT guide cover what I am about to touch, and did
110
+ understanding this force a model of a high-complexity component none covers.
111
+ The Phase-5 Comprehension checkpoint stays the backstop for a signal that only
112
+ became visible later; it is no longer the moment of first asking.
113
+
114
+ ## [1.31.0] - 2026-09-05
115
+
116
+ ### Changed
117
+ - **Execute-Before-Specify now covers text-about-text (SKILL.md, Phase 3).** A
118
+ deliverable that is itself text -- doctrine, a schema, a prompt, a reviewer
119
+ definition -- is probed the same way as code: replay it against the recorded
120
+ case that motivated it (the incident artifact, the tool-usage transcript, the
121
+ review that missed the defect), red under the old text, green under the new.
122
+ "No probe is possible" is shown, never declared. The exemption an earlier
123
+ proposal would have granted was rejected on evidence: the unit cited as
124
+ unprobeable text was a code unit that modified six production modules and
125
+ shipped four assertion harnesses, while doctrine and prompt changes have been
126
+ measured here by replay (three headless probes of a prompt change; an ad-hoc
127
+ checklist that caught in one round what ten rounds missed). Paid for per this
128
+ skill's own `vision.md` cumulative-ratchet rule: 67 words of illustration and
129
+ rationale deleted from the same paragraph, net -2 words.
130
+ - **Form budget belongs to the first draft (shared spine `review.md`,
131
+ byte-identical x3).** The lean operative form is the FIRST draft's form, not
132
+ the round-3 rescue: the review request states the artifact's line count
133
+ against a budget the author fixed before drafting, and an artifact over budget
134
+ is the reviewer's first finding, before content. The ~1,250 -> ~500 line
135
+ measurement already in the file is its anchor. Spine delta is synced in the
136
+ repo; kb and mkt ship it at their next release.
137
+
29
138
  ## [1.30.0] - 2026-09-01
30
139
 
31
140
  ### Added
package/README.md CHANGED
@@ -16,8 +16,8 @@
16
16
  - **devPNT symbiosis**: when devPNT is available, Master Plan, Action Plan, M-VISION, and governed artifacts become the authoritative planning layer, with independent fresh-context reviews of technical artifacts and diffs.
17
17
  - **Independent review, twice**: the design is reviewed before it is implemented and the diff before the work is declared done — by somebody other than its author. Three rungs of independence (fresh-context subagent > one-shot run > a declared self-pass, legal only when no higher rung is usable: absent, or permission-gated and declined — a gated rung is asked about, never silently skipped, and the log says which), capped at 3 rounds, one log line per review, and a PASS is invalid on "found nothing" — it must state where each constraint is satisfied.
18
18
  - **Question discipline**: a question to the user is legal only when the agent searched first and names the search with its result, and names the decision the answer unblocks. Otherwise it proceeds on a declared assumption — same evidence duty, batched, never a stream of "shall I proceed?".
19
- - **Installed support files**: Claude, Codex, Gemini, and Google Antigravity receive the full skill folder, including `templates.md`, `architect.md`, `guides.md`, `vision.md`, `tdd.md`, `debugging.md`, `elicitation.md`, `review.md`, `dispatch.md`, `routing.md`, `ENFORCEMENT.md`, and the validator's two files, `scripts/sdlc_check.py` + `scripts/sdlc_core.py`.
20
- - **Mechanical checks**: optional validator for document structure, generated feature history, stale audit areas, and protected-path gates — `check`, `validate`, `index`, `stale`, `mark`, `gate`, `plan`, `orient`, `migrate`.
19
+ - **Installed support files**: Claude, Codex, Gemini, and Google Antigravity receive the full skill folder, including `templates.md`, `architect.md`, `guides.md`, `vision.md`, `tdd.md`, `debugging.md`, `elicitation.md`, `review.md`, `dispatch.md`, `routing.md`, `hybrid.md`, `ENFORCEMENT.md`, and the validator's two files, `scripts/sdlc_check.py` + `scripts/sdlc_core.py`.
20
+ - **Mechanical checks**: optional validator for document structure, generated feature history, stale audit areas, and protected-path gates — `check`, `validate`, `index`, `stale`, `mark`, `benefit`, `gate`, `plan`, `orient`, `migrate`. `benefit` reports what the review gates have already caught, beside what the doctrine costs to read — it always exits 0 and carries no verdict, because a measurement that can fail a build becomes a target.
21
21
 
22
22
  ## Installation
23
23
 
@@ -84,6 +84,7 @@ skills/agentic-sdlc-skill/
84
84
  ├── review.md
85
85
  ├── dispatch.md
86
86
  ├── routing.md
87
+ ├── hybrid.md
87
88
  ├── ENFORCEMENT.md
88
89
  └── scripts/
89
90
  ├── sdlc_check.py
@@ -138,3 +139,32 @@ For native Gemini Agent Skills, the npm installer now copies the skill folder in
138
139
  Created by **Antonio Pinto** ([GitHub](https://github.com/Antoneeo)).
139
140
 
140
141
  MIT (c) 2026 Antonio Pinto.
142
+
143
+ ## Which model to run it on
144
+
145
+ The skill names **capability tiers**, never providers — a model name in doctrine
146
+ rots at the next release. The binding is yours to make, and the rule is one line:
147
+
148
+ > **A session's floor is the highest floor among the roles it performs itself.**
149
+
150
+ Authoring a governed artifact — the vision, the analysis, the use cases, the
151
+ threat model — is a **deep-tier** role: its output is judgement, and nothing
152
+ downstream scores it. So a session that will DESIGN wants your strongest model.
153
+ A session that only executes an already-approved plan, or does small maintenance,
154
+ can sit a tier lower. The cheapest tier is the wrong choice for the main session
155
+ whatever the task, because the failure there is not a wrong answer — it is
156
+ **silently not applying the process**: a triage never run, a router verdict
157
+ declared without the lookup, a gate nobody noticed. That failure is invisible to
158
+ every check in here.
159
+
160
+ **The reviewer's tier is not automatically yours.** On some clients a subagent
161
+ inherits the session's model; on others it takes one from its own definition, so
162
+ a strong session can be reviewed by a weak one — and a weak session can buy a
163
+ strong review. Set it deliberately; the
164
+ `model` column in the review log is where the choice becomes visible.
165
+
166
+ **Avoid one combination**: authoring below the floor AND reviewing below the floor
167
+ on the same unit. One disclosed weakness is a disclosed weakness; two is an
168
+ artifact nobody competent ever read. Where your client offers nothing better, the
169
+ review still runs and both facts are recorded — a disclosed worst case beats
170
+ skipping the review.
@@ -1,6 +1,6 @@
1
- {
2
- "name": "agentic-sdlc-skill",
3
- "version": "1.31.0",
4
- "description": "Documentation-First SDLC protocol with triage, Vision governance and optional devPNT integration.",
5
- "author": "Antonio Pinto (https://github.com/Antoneeo)"
6
- }
1
+ {
2
+ "name": "agentic-sdlc-skill",
3
+ "version": "1.33.0",
4
+ "description": "Documentation-First SDLC protocol with triage, Vision governance and optional devPNT integration.",
5
+ "author": "Antonio Pinto (https://github.com/Antoneeo)"
6
+ }
package/package.json CHANGED
@@ -1,50 +1,51 @@
1
- {
2
- "name": "@antoneeo/agentic-sdlc-skill",
3
- "version": "1.31.0",
4
- "description": "Documentation-First SDLC protocol for Claude Code, Gemini CLI, Google Antigravity and Codex with risk triage, Vision governance, installed support files and optional devPNT integration.",
5
- "keywords": [
6
- "claude-code",
7
- "claude-skill",
8
- "gemini-cli",
9
- "skill",
10
- "sdlc",
11
- "documentation",
12
- "ai-agent"
13
- ],
14
- "author": "Antonio Pinto (https://github.com/Antoneeo)",
15
- "license": "MIT",
16
- "publishConfig": {
17
- "access": "public"
18
- },
19
- "bin": {
20
- "agentic-sdlc-init": "scripts/init.js",
21
- "agentic-sdlc-install-skill": "scripts/postinstall.js"
22
- },
23
- "scripts": {
24
- "postinstall": "node scripts/postinstall.js",
25
- "preuninstall": "node scripts/preuninstall.js"
26
- },
27
- "files": [
28
- "skills/agentic-sdlc-skill/SKILL.md",
29
- "skills/agentic-sdlc-skill/templates.md",
30
- "skills/agentic-sdlc-skill/architect.md",
31
- "skills/agentic-sdlc-skill/guides.md",
32
- "skills/agentic-sdlc-skill/vision.md",
33
- "skills/agentic-sdlc-skill/tdd.md",
34
- "skills/agentic-sdlc-skill/debugging.md",
35
- "skills/agentic-sdlc-skill/elicitation.md",
36
- "skills/agentic-sdlc-skill/review.md",
37
- "skills/agentic-sdlc-skill/dispatch.md",
38
- "skills/agentic-sdlc-skill/routing.md",
39
- "skills/agentic-sdlc-skill/ENFORCEMENT.md",
40
- "skills/agentic-sdlc-skill/scripts/sdlc_check.py",
41
- "skills/agentic-sdlc-skill/scripts/sdlc_core.py",
42
- "gemini-extension.json",
43
- "README.md",
44
- "CHANGELOG.md",
45
- "scripts/lib.js",
46
- "scripts/init.js",
47
- "scripts/postinstall.js",
48
- "scripts/preuninstall.js"
49
- ]
50
- }
1
+ {
2
+ "name": "@antoneeo/agentic-sdlc-skill",
3
+ "version": "1.33.0",
4
+ "description": "Documentation-First SDLC protocol for Claude Code, Gemini CLI, Google Antigravity and Codex with risk triage, Vision governance, installed support files and optional devPNT integration.",
5
+ "keywords": [
6
+ "claude-code",
7
+ "claude-skill",
8
+ "gemini-cli",
9
+ "skill",
10
+ "sdlc",
11
+ "documentation",
12
+ "ai-agent"
13
+ ],
14
+ "author": "Antonio Pinto (https://github.com/Antoneeo)",
15
+ "license": "MIT",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "bin": {
20
+ "agentic-sdlc-init": "scripts/init.js",
21
+ "agentic-sdlc-install-skill": "scripts/postinstall.js"
22
+ },
23
+ "scripts": {
24
+ "postinstall": "node scripts/postinstall.js",
25
+ "preuninstall": "node scripts/preuninstall.js"
26
+ },
27
+ "files": [
28
+ "skills/agentic-sdlc-skill/SKILL.md",
29
+ "skills/agentic-sdlc-skill/templates.md",
30
+ "skills/agentic-sdlc-skill/architect.md",
31
+ "skills/agentic-sdlc-skill/guides.md",
32
+ "skills/agentic-sdlc-skill/vision.md",
33
+ "skills/agentic-sdlc-skill/tdd.md",
34
+ "skills/agentic-sdlc-skill/debugging.md",
35
+ "skills/agentic-sdlc-skill/elicitation.md",
36
+ "skills/agentic-sdlc-skill/review.md",
37
+ "skills/agentic-sdlc-skill/dispatch.md",
38
+ "skills/agentic-sdlc-skill/hybrid.md",
39
+ "skills/agentic-sdlc-skill/routing.md",
40
+ "skills/agentic-sdlc-skill/ENFORCEMENT.md",
41
+ "skills/agentic-sdlc-skill/scripts/sdlc_check.py",
42
+ "skills/agentic-sdlc-skill/scripts/sdlc_core.py",
43
+ "gemini-extension.json",
44
+ "README.md",
45
+ "CHANGELOG.md",
46
+ "scripts/lib.js",
47
+ "scripts/init.js",
48
+ "scripts/postinstall.js",
49
+ "scripts/preuninstall.js"
50
+ ]
51
+ }
package/scripts/lib.js CHANGED
@@ -639,6 +639,105 @@ function removeGlobalOrientHooks(removedRoots) {
639
639
  return removedFrom;
640
640
  }
641
641
 
642
+ // --- Per-turn reminder hook (F-046) ----------------------------------------
643
+ // `orient` fires once and decays; a session that never loads the skill never
644
+ // had the protocol at all. This hook re-arms one constant line every prompt.
645
+ // It is wired ALONGSIDE the orient hook and never instead of it, and it is its
646
+ // own function because `wireOrientHook` returns early when the session hook is
647
+ // already there -- which is the state of every existing installation.
648
+ // Owner-accepted per-turn cost: `ai_docs/vision/rulings.md` r19.
649
+
650
+ const REMIND_HOOK_TIMEOUT = 5;
651
+
652
+ function remindHookCommand(python, validator) {
653
+ return python + ' "' + validator + '" remind';
654
+ }
655
+
656
+ function findRemindHook(settings) {
657
+ const groups = settings && settings.hooks && settings.hooks.UserPromptSubmit;
658
+ if (!Array.isArray(groups)) return null;
659
+ for (const group of groups) {
660
+ if (!group || typeof group !== 'object') continue;
661
+ const inner = Array.isArray(group.hooks) ? group.hooks : [group];
662
+ for (const h of inner) {
663
+ const cmd = h && typeof h.command === 'string' ? h.command : '';
664
+ if (ORIENT_ENTRY_POINTS.some((n) => cmd.includes(n)) && / remind(\s|$)/.test(cmd)) {
665
+ return cmd;
666
+ }
667
+ }
668
+ }
669
+ return null;
670
+ }
671
+
672
+ // Writes the hook into `target` (an already-chosen settings file) unless it is
673
+ // there or the user opted out. Returns a code, never throws: an installer must
674
+ // not die on someone's settings file.
675
+ function remindMarkerPath() {
676
+ const root = process.env.AGENTIC_SDLC_KB_ROOT
677
+ || path.join(os.homedir(), '.agentic-sdlc');
678
+ return path.join(root, 'remind-hook-wired');
679
+ }
680
+ function remindMarkerTargets() {
681
+ try {
682
+ return fs.readFileSync(remindMarkerPath(), 'utf8')
683
+ .split(/\r?\n/).map((x) => x.trim()).filter(Boolean);
684
+ } catch (e) {
685
+ return [];
686
+ }
687
+ }
688
+ function remindMarkerHas(target) {
689
+ return remindMarkerTargets().some((t) => pathsEqual(t, target));
690
+ }
691
+ function remindMarkerAdd(target) {
692
+ try {
693
+ if (remindMarkerHas(target)) return;
694
+ fs.mkdirSync(path.dirname(remindMarkerPath()), { recursive: true });
695
+ fs.appendFileSync(remindMarkerPath(), target + String.fromCharCode(10), 'utf8');
696
+ } catch (e) { /* fail-open */ }
697
+ }
698
+
699
+ function wireRemindHookInto(target, python, validator) {
700
+ if (!python) return { code: 'no-python' };
701
+ if (!validator || ORIENT_UNSAFE_IN_PATH.test(validator)) return { code: 'unsafe-path', validator };
702
+ const state = orientSettingsState(target);
703
+ if (!state.ok) return { code: 'malformed', target, why: state.why };
704
+ const settings0 = state.settings;
705
+ // Order matters, and the first version had it wrong too: the hook being
706
+ // PRESENT is `already`, and only its ABSENCE plus our marker means the user
707
+ // removed it -- a standing opt-out. Marker-first would refuse to re-check a
708
+ // hook someone still has.
709
+ const present = findRemindHook(settings0);
710
+ if (present) return { code: 'already', target, command: present };
711
+ if (remindMarkerHas(target)) return { code: 'opted-out', target };
712
+ const settings = settings0;
713
+ const existing = null;
714
+ if (existing) return { code: 'already', target, command: existing };
715
+ const command = remindHookCommand(python, validator);
716
+ if (!settings.hooks) settings.hooks = {};
717
+ if (!Array.isArray(settings.hooks.UserPromptSubmit)) settings.hooks.UserPromptSubmit = [];
718
+ settings.hooks.UserPromptSubmit.push({
719
+ hooks: [{ type: 'command', command, timeout: REMIND_HOOK_TIMEOUT }],
720
+ });
721
+ try {
722
+ fs.mkdirSync(path.dirname(target), { recursive: true });
723
+ fs.writeFileSync(target, JSON.stringify(settings, null, 2) + String.fromCharCode(10), 'utf8');
724
+ } catch (e) {
725
+ return { code: 'write-failed', target, command, error: e.message };
726
+ }
727
+ remindMarkerAdd(target);
728
+ return { code: 'wired', target, command };
729
+ }
730
+
731
+
732
+ // The machine-global twin of wireGlobalOrientHook, same target and validator.
733
+ function wireGlobalRemindHook(options) {
734
+ const client = options.client;
735
+ const validator = path.join(skillTarget(client), 'scripts', ORIENT_ENTRY_POINT);
736
+ if (!fs.existsSync(validator)) return { code: 'no-validator', validator };
737
+ return wireRemindHookInto(path.join(client.home, 'settings.json'), options.python, validator);
738
+ }
739
+
740
+
642
741
  module.exports = {
643
742
  PACKAGE_ROOT,
644
743
  SKILL_SOURCE,
@@ -649,6 +748,12 @@ module.exports = {
649
748
  clientDetected,
650
749
  skillTarget,
651
750
  wireOrientHook,
751
+ wireRemindHookInto,
752
+ wireGlobalRemindHook,
753
+ remindMarkerHas,
754
+ remindMarkerAdd,
755
+ remindHookCommand,
756
+ findRemindHook,
652
757
  wireGlobalOrientHook,
653
758
  removeGlobalOrientHooks,
654
759
  detectPython,
@@ -3,7 +3,7 @@
3
3
  const fs = require('fs');
4
4
  const {
5
5
  SKILL_SOURCE, CLIENTS, clientDetected, skillTarget, copyRecursive,
6
- wireGlobalOrientHook, detectPython,
6
+ wireGlobalOrientHook, wireGlobalRemindHook, detectPython,
7
7
  } = require('./lib');
8
8
 
9
9
  function installSkill(client) {
@@ -39,6 +39,18 @@ for (const client of CLIENTS) {
39
39
  // marker remembers. A convenience must never fail an npm install: wrapped.
40
40
  if (client.key === 'claude' && installed) {
41
41
  try {
42
+ // F-046: the per-turn reminder, wired alongside and never instead of
43
+ // the session hook. `orient` decays; this one re-arms one constant line
44
+ // every prompt, and its first duty is the one that was missing -- decide
45
+ // whether the skill governs the work and, if so, load it once, because
46
+ // an unread protocol cannot be applied. Owner-accepted per-turn cost:
47
+ // ai_docs/vision/rulings.md r19.
48
+ const rr = wireGlobalRemindHook({ client, python: detectPython() });
49
+ if (rr.code === 'wired') {
50
+ console.log('🔗 Per-turn protocol reminder wired for every project on this machine');
51
+ console.log(` (${rr.target}). One constant line per prompt; remove that hook`);
52
+ console.log(' entry to opt out — it will not be re-added.');
53
+ }
42
54
  const r = wireGlobalOrientHook({ client, python: detectPython() });
43
55
  if (r.code === 'wired') {
44
56
  console.log('🔗 Session orientation wired for every project on this machine');
@@ -57,7 +57,7 @@ Semantics: exit code 2 + message on stderr ⇒ the write is blocked and the mess
57
57
  - The paths in `--protected` are prefixes relative to the project root, separated by `;`.
58
58
  - `ai_docs/`, `tests/` and `test/` are always excluded from blocking.
59
59
  - The hook assumes the working directory is the project root (standard behavior of Claude Code hooks).
60
- - **Hybrid/devPNT projects**: add `--hybrid` to the gate command. Governed designs live in the devPNT DB, so the gate also unlocks when an approved E-TDD shadow (`ai_docs/solutions/SHADOW_*tdd*.md`, exported before implementation — see the SKILL.md shadow discipline) is present. Without the flag the gate would block legitimate governed work. The flag is deliberately explicit: never auto-detected.
60
+ - **Hybrid/devPNT projects**: add `--hybrid` to the gate command. Governed designs live in the devPNT DB, so the gate also unlocks when an approved E-TDD shadow (`ai_docs/solutions/SHADOW_*tdd*.md`, exported before implementation — see `hybrid.md` §Shadow discipline) is present. Without the flag the gate would block legitimate governed work. The flag is deliberately explicit: never auto-detected.
61
61
 
62
62
  ## 4. SessionStart hook (orientation, recommended default)
63
63
 
@@ -157,6 +157,46 @@ Gemini CLI — wire the same command into its startup-hook mechanism if present;
157
157
  - **Hybrid/devPNT projects**: add `--hybrid` — the hook then appends a one-line pointer to run `devpnt_mcp_get_bootstrap` for the Master Plan / Knowledge Layer and does not replicate them; the filesystem orientation (router + handoff + README) still emits.
158
158
  - Like the CI gate (§2), if you copied the validator into the repo, the hook references that copy — keep both files current when you update the skill.
159
159
 
160
+ ### Per-turn reminder: `remind` (UserPromptSubmit -- wired by default)
161
+
162
+ `orient` fires once, at session start; a long session drifts after it, and a session
163
+ that never loads the skill never had the protocol at all. Measured (F-046, 2026-09-06):
164
+ a release ran against a `GUIDE_release.md` the session never consulted, because
165
+ `SKILL.md` -- where the duty is written -- had not been read. `sdlc_check.py remind` prints
166
+ ONE constant line at every prompt, and its first duty is that one: decide whether the
167
+ skill governs the work in front of you and, if it does, load it once.
168
+
169
+ Cost: 478 characters, ~80 tokens per prompt, paid on every turn including
170
+ trivial ones. That is admissible only because the owner accepted it explicitly
171
+ (`ai_docs/vision/rulings.md` r19, the "no ceremony ratchet" Non-Goal's second door) --
172
+ and the acceptance was for a FLAT cost. Hence the contract, guarded by
173
+ `scripts/test_remind.py`: the line is **constant and reads nothing** (so nothing repo-
174
+ or session-controlled rides into the agent's context through it, and the cost cannot
175
+ grow with the session), it is **one line under 500 characters**, and it **can never
176
+ break a prompt** (argv ignored whole, always exit 0). A trivial turn pays a yes/no
177
+ judgement, never a load.
178
+
179
+ Installing the package wires it machine-wide on Claude Code, alongside the orientation
180
+ hook and never instead of it; **removing that hook entry is a standing opt-out.** To
181
+ wire it by hand:
182
+
183
+ ```json
184
+ {
185
+ "hooks": {
186
+ "UserPromptSubmit": [
187
+ {
188
+ "hooks": [
189
+ {
190
+ "type": "command",
191
+ "command": "python \"C:\Users\<user>\.claude\skills\agentic-sdlc\scripts\sdlc_check.py\" remind"
192
+ }
193
+ ]
194
+ }
195
+ ]
196
+ }
197
+ }
198
+ ```
199
+
160
200
  ## 5. Skill eval battery (release gate)
161
201
 
162
202
  **Skill development only.** `test_*.py` and `evals/` are deliberately absent from the npm `files` allowlist — they never reach an installed consumer, so this section applies to whoever builds the skill, not to a project that uses it. (Consumers get `sdlc_check.py` + `sdlc_core.py`; §1–§4 are theirs.)
@@ -176,3 +216,12 @@ It aggregates the test files (`test_plan.py` + `test_session_start.py` + `test_s
176
216
  **Optional CI** (same shape as §2, not mandatory): add a `run:` step invoking the `unittest discover` command above.
177
217
 
178
218
  **T10 note:** if you copied the validator (both files) and the `test_*.py` battery into the repo for CI, that copy is authoritative — keep it current when you update the skill.
219
+
220
+ ## `benefit` is a report, never a CI gate
221
+
222
+ `sdlc_check.py benefit` reports what the review gates caught and what the
223
+ doctrine costs to read. It always exits 0 and emits no warning: **never wire
224
+ it into CI**. It is the criterion by which future units are judged, and a
225
+ measurement that can fail a build becomes a target -- a targeted measurement
226
+ stops measuring. Run it when deciding whether a proposed rule is worth its
227
+ ceremony, not on every push.