@antoneeo/agentic-sdlc-skill 1.38.0 → 1.40.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 +12 -0
- package/README.md +3 -1
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/scripts/init.js +6 -6
- package/skills/agentic-sdlc-skill/ENFORCEMENT.md +5 -5
- package/skills/agentic-sdlc-skill/SKILL.md +6 -1
- package/skills/agentic-sdlc-skill/debugging.md +5 -5
- package/skills/agentic-sdlc-skill/elicitation.md +8 -5
- package/skills/agentic-sdlc-skill/hybrid.md +11 -6
- package/skills/agentic-sdlc-skill/review.md +9 -1
- package/skills/agentic-sdlc-skill/scripts/knowledge.py +68 -28
- package/skills/agentic-sdlc-skill/scripts/sdlc_check.py +211 -1
- package/skills/agentic-sdlc-skill/scripts/sdlc_core.py +53 -6
- package/skills/agentic-sdlc-skill/templates.md +125 -0
- package/skills/agentic-sdlc-skill/vision.md +245 -245
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Tutte le modifiche significative a questa skill saranno documentate in questo file.
|
|
4
4
|
|
|
5
|
+
## [1.40.0] - 2026-10-17
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- F1: closing the last open workstream now empties the generated registry `audit/handoff.md` instead of leaving its stale row behind: with zero `HANDOFF_*.md` sources `index` rewrites it empty (keeping `project_notes.md`), and `validate` reports a generated registry that still has rows but no sources as an error.
|
|
9
|
+
- F-069: `graph`, `check`, `stale` and the session-start count are faster on a mature knowledge base, with byte-identical output. Citations of superseded claim ids are found with one pass per living document instead of one scan per (document, id) pair, and one check run reads and resolves each cited extraction once instead of once per claim row. On a synthetic ledger of 2183 rows and 1000 living documents, `graph` drops from 14 s to 4 s. No new flag.
|
|
10
|
+
|
|
11
|
+
## [1.39.0] - 2026-10-13
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- F-067: every L3 unit now keeps a verbatim, append-only request record `audit/requests/REQUEST_[feature].md`, started before the Vision Gate: the owner's opening words and every later statement that settles something (answers, approvals, costs, rulings). Artifacts cite its entries instead of paraphrasing; the shared `review.md` asks for the record and makes an owner statement with no resolving entry a finding. Secrets, personal data and confidential third-party or employer information are redacted. `review-map` classes the record as evidence.
|
|
15
|
+
- F-066: every L3 closure now ships `MERGE_REVIEW_[feature].md` for the integrator (what to review, what was verified by which gate, what only a human can judge) and `E2E_TEST_[feature].md` for human testers in staging after the merge (regression scenarios always, new-behavior scenarios when behavior changed). New code-lens command `sdlc_check.py review-map [--base REF]` classes every changed file REVIEW / DESIGN / EVIDENCE / GENERATED; GENERATED is learned by running the project's own `index` on a throwaway copy, so it cannot drift from the writers.
|
|
16
|
+
|
|
5
17
|
## [1.38.0] - 2026-10-08
|
|
6
18
|
|
|
7
19
|
### Changed
|
package/README.md
CHANGED
|
@@ -26,6 +26,8 @@ Vendoring requires all three files: the entry point, `sdlc_core.py`, `knowledge.
|
|
|
26
26
|
- **Execution disciplines**: explicit TDD (RED/GREEN/REFACTOR), evidence-first debugging with hypotheses ranked by likelihood and verification cost, supported causal questioning and clean Poka-Yoke correction with regression checks; an L3 spec-elicitation round and a single code-review definition wired into the workflow phases.
|
|
27
27
|
- **Operative + comprehension guides + agent-global KB**: distil user-provided indications into source-faithful operative `GUIDE_*.md` (`source_kind: document`), and let the agent autonomously author **code-comprehension guides** (`source_kind: code`) for complex components — a source-faithful mental-model map that survives across sessions, so the next session doesn't re-derive and break the component from partial understanding. Consulted before work; shared cross-project via `~/.agentic-sdlc`.
|
|
28
28
|
- **Several people, one project**: the workstream registry (`audit/handoff.md`) is **generated** from one file per open workstream, so two people opening or closing two workstreams on two branches edit two different files and their merge is clean. Row-per-workstream alone was not enough — a file-global `Date:` header defeats row-level ownership — so the header is derived from the sources and no writer touches it. The generated view can still conflict; that conflict is resolved by re-running `index`, never by hand, and `validate` refuses CLEAN until the file matches its sources. The append-only review log gets `merge=union` (a built-in driver, no per-clone configuration). It all works with no VCS at all: it is files and a generator.
|
|
29
|
+
- **Merge review brief and E2E script**: every L3 closure ships `MERGE_REVIEW_[feature].md` for the integrator — what to review, what was verified by which gate, what only a human can judge — with a map from `sdlc_check.py review-map` that classes each changed file REVIEW / DESIGN / EVIDENCE / GENERATED (generated indexes are skipped, `check` proves them), and `E2E_TEST_[feature].md` for human testers after the merge: regression scenarios always, new-behavior scenarios when behavior changed.
|
|
30
|
+
- **Verbatim request record**: every L3 starts `audit/requests/REQUEST_[feature].md` before the Vision Gate — the owner's own words and every later decision (answers, approvals, costs, rulings), append-only and redacted for secrets — so analyses cite what was asked instead of paraphrasing it, and reviewers can verify owner statements instead of trusting the author.
|
|
29
31
|
- **Opt-in subagent execution**: an approved design projects into a validated executable plan an orchestrator can drive through subagents.
|
|
30
32
|
- **Self-activating**: a SessionStart hook emits repo-sourced orientation; a deterministic self-eval battery guards the skill's own doctrine as the release gate.
|
|
31
33
|
- **Standalone complete**: works fully with local `ai_docs/` without requiring devPNT.
|
|
@@ -33,7 +35,7 @@ Vendoring requires all three files: the entry point, `sdlc_core.py`, `knowledge.
|
|
|
33
35
|
- **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, who receives the whole review mandate in a fixed block copied verbatim, never a paraphrase of it. 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.
|
|
34
36
|
- **Question discipline**: a real doubt is asked when it emerges, before its answer is written into any document — grouped, with the pros and cons of each option. A choice whose pros clearly win is taken without asking, and the weighing is written next to it; a fact is settled by evidence or asked, never weighed. A question is legal only when the agent searched first, names the search with its result, and names the decision it unblocks — never a stream of "shall I proceed?".
|
|
35
37
|
- **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`, `memory.md`, and the validator's three files, `scripts/sdlc_check.py` + `scripts/sdlc_core.py` + `scripts/knowledge.py` — plus the `LICENSE` and `NOTICE` it ships under.
|
|
36
|
-
- **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
|
|
38
|
+
- **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`, `review-map` (code lens: classes the files of a change for the merge review brief). `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.
|
|
37
39
|
|
|
38
40
|
## Installation
|
|
39
41
|
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antoneeo/agentic-sdlc-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.0",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
package/scripts/init.js
CHANGED
|
@@ -203,16 +203,16 @@ in the skill's \`routing.md\`: it decides which lens's method and validation rul
|
|
|
203
203
|
that unit. L1 never reaches it. Never refer to a document whose meaning differs by lens
|
|
204
204
|
("threat model", "vision", \`principles.md\`, \`handoff.md\`) by its bare name.
|
|
205
205
|
|
|
206
|
-
Select the owning lens by the unit's purpose, then apply only its risk scale.
|
|
207
|
-
The project's always-on pointer stays intact: consult the selected skill rather than
|
|
208
|
-
merging multiple mandatory ladders. All lenses already carry shared project memory
|
|
209
|
-
(\`memory.md\`); another installation is not needed for cross-domain recall.
|
|
206
|
+
Select the owning lens by the unit's purpose, then apply only its risk scale.
|
|
207
|
+
The project's always-on pointer stays intact: consult the selected skill rather than
|
|
208
|
+
merging multiple mandatory ladders. All lenses already carry shared project memory
|
|
209
|
+
(\`memory.md\`); another installation is not needed for cross-domain recall.
|
|
210
210
|
This file is NOT auto-loaded by any client: it is a note for you, deliberately additive.
|
|
211
|
-
Delete this note once the routing pointer is integrated.
|
|
211
|
+
Delete this note once the routing pointer is integrated.
|
|
212
212
|
`, 'multi-lens routing note');
|
|
213
213
|
if (wrote && protocolPreexisting) {
|
|
214
214
|
console.log(' ⚠️ A protocol pointer already existed and was NOT overwritten.');
|
|
215
|
-
console.log(' Integrate the routing pointer from AGENTIC_MULTI_LENS.md; keep one risk scale per unit.');
|
|
215
|
+
console.log(' Integrate the routing pointer from AGENTIC_MULTI_LENS.md; keep one risk scale per unit.');
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -14,17 +14,17 @@ python "<skill_dir>/scripts/sdlc_check.py" check
|
|
|
14
14
|
|
|
15
15
|
## 2. Check in CI (recommended for teams)
|
|
16
16
|
|
|
17
|
-
Copy all three validator files into the repository: `scripts/sdlc_check.py`, `scripts/sdlc_core.py`, and `scripts/knowledge.py`, keeping them side by side. Then add to the pipeline:
|
|
17
|
+
Copy all three validator files into the repository: `scripts/sdlc_check.py`, `scripts/sdlc_core.py`, and `scripts/knowledge.py`, keeping them side by side. Then add to the pipeline:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
python tools/sdlc_check.py validate --strict
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
The validator ships as **three files**: the domain entry point, `sdlc_core.py` and `knowledge.py`. Keep all three together. The core alone still runs but omits shared-memory/KB checks and domain-specific overlays; it is not an equivalent CI gate. `check` includes the knowledge surface when present.
|
|
23
|
+
The validator ships as **three files**: the domain entry point, `sdlc_core.py` and `knowledge.py`. Keep all three together. The core alone still runs but omits shared-memory/KB checks and domain-specific overlays; it is not an equivalent CI gate. `check` includes the knowledge surface when present.
|
|
24
24
|
|
|
25
25
|
Effect: an unregenerated index, invalid frontmatter, a missing security section or incoherent states **block the pipeline** instead of relying on the agent's memory. `--strict` also fails on warnings and on a missing `ai_docs/`, so a wrong working directory cannot produce a green pipeline. This works because documents travel in the same PR as the code (Phase 5 rule).
|
|
26
26
|
|
|
27
|
-
Note: the copy in the repo is the authoritative one for CI; update it when you update the skill — all three files, together.
|
|
27
|
+
Note: the copy in the repo is the authoritative one for CI; update it when you update the skill — all three files, together.
|
|
28
28
|
|
|
29
29
|
**Projects whose docs root is not `ai_docs/`.** Pass `--docs-dir <name>` (e.g. `--docs-dir mkt_docs`) on any subcommand, or set `AGENTIC_SDLC_DOCS_DIR`. Without either, the validator walks up from the working directory and takes the nearest root it recognizes. If it finds two side by side — the shape of a half-finished migration — it refuses and names both rather than validating half a project and printing a verdict. `ai_docs/` remains the default and the recommended root: the parameter exists so a legacy tree can be read and migrated, not so a second one can be kept.
|
|
30
30
|
|
|
@@ -155,7 +155,7 @@ Gemini CLI — wire the same command into its startup-hook mechanism if present;
|
|
|
155
155
|
**Usage notes:**
|
|
156
156
|
- The hook assumes the working directory is the project root (standard Claude Code hook behavior); it also accepts `--root <path>`.
|
|
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
|
-
- Like the CI gate (§2), if you copied the validator into the repo, the hook references that copy — keep all three files current when you update the skill.
|
|
158
|
+
- Like the CI gate (§2), if you copied the validator into the repo, the hook references that copy — keep all three files current when you update the skill.
|
|
159
159
|
|
|
160
160
|
### Per-turn reminder: `remind` (UserPromptSubmit -- wired by default)
|
|
161
161
|
|
|
@@ -215,7 +215,7 @@ It aggregates the test files (`test_plan.py` + `test_session_start.py` + `test_s
|
|
|
215
215
|
|
|
216
216
|
**Optional CI** (same shape as §2, not mandatory): add a `run:` step invoking the `unittest discover` command above.
|
|
217
217
|
|
|
218
|
-
**T10 note:** if you copied the validator (all three files) and the `test_*.py` battery into the repo for CI, that copy is authoritative — keep it current when you update the skill.
|
|
218
|
+
**T10 note:** if you copied the validator (all three files) and the `test_*.py` battery into the repo for CI, that copy is authoritative — keep it current when you update the skill.
|
|
219
219
|
|
|
220
220
|
## `benefit` is a report, never a CI gate
|
|
221
221
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agentic-sdlc
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.40.0
|
|
4
4
|
description: Documentation-First SDLC protocol with risk-proportional triage, Vision as a guide, a complete Standalone mode and optional symbiosis with devPNT. Use for features, significant bugs, refactors, audits and documented maintenance.
|
|
5
5
|
author: Antonio Pinto (https://github.com/Antoneeo)
|
|
6
6
|
copyright: (c) 2026 Antonio Pinto
|
|
@@ -84,7 +84,10 @@ Triage decides IF documentation is due; this table decides WHICH document each e
|
|
|
84
84
|
| Document | Write trigger | Phase |
|
|
85
85
|
|---|---|---|
|
|
86
86
|
| `solutions/ANALYSIS_[feature].md` | Every L3, after elicitation and before any code. On topic match with an existing analysis, update that one instead of a new file -- a revision re-reads the WHOLE document and rewrites it to current state (history in the Diary), never an appended delta section. A capability the architect pass splits out as its own unit of change (`architect.md` §4) gets its own ANALYSIS, and the two documents name each other. | 3 |
|
|
87
|
+
| `audit/requests/REQUEST_[feature].md` | Every L3, the moment the level is declared — before the Vision Gate and the first question: R1 quotes the owner's opening words verbatim; every later owner statement that settles something for the unit (answer, approval, cost, ruling, merge) is appended before acting on it. Append-only, never deleted; artifacts cite its entries, a paraphrase never replacing the citation (`templates.md`). | 1 → 5 |
|
|
87
88
|
| `solutions/SPIKE_[topic].md` | Closing any Spike — including a failed one (a negative outcome is still an outcome). | — |
|
|
89
|
+
| `solutions/E2E_TEST_[feature].md` | Every L3, before the closure review (it is part of the reviewed diff): the human tester's post-merge script — new-behavior scenarios when behavior changed, regression scenarios always (`templates.md`). | 5 |
|
|
90
|
+
| `solutions/MERGE_REVIEW_[feature].md` | Every L3, after the closure review: the integrator's brief — what to review (`sdlc_check.py review-map`), what was verified by which gate, what only a human can judge (`templates.md`). The PR description links it. | 5 |
|
|
88
91
|
| `vision/features/VISION_[feature].md` | Feature known multi-milestone at analysis time, OR the retroactive trigger: you are about to create the SECOND `ANALYSIS_*` on the same theme — extract the shared feature vision first, then let both analyses reference it. | 3 |
|
|
89
92
|
| `audit/handoff.md` (workstream registry) | **Never by hand — generated by `sdlc_check.py index` from the `HANDOFF_*.md` sources**, and `validate` errors when the two disagree. Regenerate at every L3 closure and at session end; the `Date:` header is derived, so no writer touches it. It is an inventory for lookup, not a work board: no assignment, no due dates, no ordering, no holder. | 5 / session end |
|
|
90
93
|
| `audit/HANDOFF_[feature].md` | **One per OPEN workstream, with or without volatile state** — it is the authored home of that workstream's registry row (frontmatter `workstream`/`level`/`branch`/`status`/`since`/`next`/`details`/`updated`), so no file means no row. Also carries the resume logistics; **the ANALYSIS Diary keeps the durable narrative (DRY)**, and this file is DELETED at closure — deleting it *is* removing the row. | 4 / 5 / session end |
|
|
@@ -148,6 +151,7 @@ devPNT is not there, work Standalone and nothing is lost.
|
|
|
148
151
|
|
|
149
152
|
Standalone:
|
|
150
153
|
- Read `project_vision.md`, `roadmap.md`, `principles.md`.
|
|
154
|
+
- Compare them with the request as recorded in `audit/requests/REQUEST_[feature].md`, not with a paraphrase of it.
|
|
151
155
|
- If a document declares `Status: DRAFT`, treat it as a hypothesis: flag conflicts, but do not block an explicit user request.
|
|
152
156
|
- If it declares `Status: APPROVED` and the request conflicts, stop and ask for a choice: update the Vision or modify/reject the request.
|
|
153
157
|
- Never promote a Vision to `APPROVED` without the user's confirmation.
|
|
@@ -229,6 +233,7 @@ Hybrid L3:
|
|
|
229
233
|
- guides created or changed: `sdlc_check.py index` regenerates BOTH manifests (`ai_docs/INDEX.md` and the guide router `ai_docs/reference/INDEX.md`) in one run.
|
|
230
234
|
- If an architectural decision was taken (new pattern, layer or contract change, structural dependency), record an ADR before DONE — Standalone in `architecture/`, Hybrid propose the ADR/KL update in the devPNT DB. No decision, no ADR (Write Triggers).
|
|
231
235
|
- In Standalone, if the project adopts `sdlc_check.py`, run `python <skill_dir>/scripts/sdlc_check.py check --root <project_root>` or the equivalent local copy.
|
|
236
|
+
- **Merge review and E2E script (L3).** The integrator and the tester need different documents at different moments, so both are written at every L3 closure, in this order: `E2E_TEST_[feature].md` before the closure review; `MERGE_REVIEW_[feature].md` after it; then `index`, `sdlc_check.py review-map --base <base>`, its table pasted into the brief, and `index` again (the brief's catalog hash changed; the map's files did not, its line counts are as of the run). Without the brief an integrator cannot tell the code to review from the indexes `check` already proves, nor the claims a gate verified from the ones left to them (Write Triggers; templates: `templates.md`).
|
|
232
237
|
- Updated documents must travel in the same commit/PR as the code they describe.
|
|
233
238
|
- **Branch/worktree hygiene**: an L3 ran on its own branch (Phase 4) — close it with an explicit merge decision (merge, keep open, or discard), and once the user has chosen, PROPOSE the branch/worktree cleanup their choice implies; an orphan branch left behind with nothing said is the failure this bullet prevents — the cleanup itself is theirs to authorize (next bullet). In Hybrid, the running devPNT server locks `.devpnt/*.db`, so the merge is done from a separate git worktree or via a ref-only push, never an in-place branch switch in the primary worktree.
|
|
234
239
|
- **Destructive guards (integration is the user's; destruction is explicit).** The integration choice — merge, push/PR, keep — belongs to the user. Discard happens ONLY on the user's explicit request, and the confirmation names exactly what dies: the branch, its commits, the worktree path. Never force-push without explicit authorization; a rejected push means the remote moved — investigate, don't force. Never clean up a worktree this workflow did not create — the host or another workflow owns it. Repository-specific release/finish commands are the project guide layer's (the router in `## Operative Guides`): the skill owns this discipline, the matched `GUIDE_*.md` owns the commands — cite it, never restate it.
|
|
@@ -34,11 +34,11 @@ proof that it caused this incident.
|
|
|
34
34
|
Do not repeat an invalidated hypothesis unless new evidence reopens it.
|
|
35
35
|
|
|
36
36
|
3. **Test and trace the mechanism.** Reproduce and isolate the smallest faithful
|
|
37
|
-
failing case when feasible; bisect inputs, paths or changes when informative.
|
|
38
|
-
Skip a reproduction already known to omit the incident's causal conditions;
|
|
39
|
-
choose a faithful alternative or disclose the gap. Stop diagnostic checks when
|
|
40
|
-
further results cannot change the causal or fix decision; this does not replace
|
|
41
|
-
the regression and recovery verification in step 5.
|
|
37
|
+
failing case when feasible; bisect inputs, paths or changes when informative.
|
|
38
|
+
Skip a reproduction already known to omit the incident's causal conditions;
|
|
39
|
+
choose a faithful alternative or disclose the gap. Stop diagnostic checks when
|
|
40
|
+
further results cannot change the causal or fix decision; this does not replace
|
|
41
|
+
the regression and recovery verification in step 5.
|
|
42
42
|
If the incident is intermittent or inaccessible, use captured traces and
|
|
43
43
|
targeted diagnostic observations instead of declaring investigation impossible.
|
|
44
44
|
Add minimal instrumentation when evidence is insufficient. Prefer read-only
|
|
@@ -67,15 +67,17 @@ Ask it before the first write that would embed its answer — in an analysis, pl
|
|
|
67
67
|
guide or code — grouped with every doubt open at that point, in one numbered set,
|
|
68
68
|
with the client's structured-question facility where it has one. Never defer a
|
|
69
69
|
doubt to the deliverable, where the user must find it inside the document; never
|
|
70
|
-
drip one question per turn. The round below is this rule's planned occasion.
|
|
71
|
-
every answer
|
|
70
|
+
drip one question per turn. The round below is this rule's planned occasion. At L3
|
|
71
|
+
record every answer verbatim in the request record (`audit/requests/REQUEST_[unit].md`)
|
|
72
|
+
and fold it into the artifact citing that entry (§Reflect); an intent choice with
|
|
72
73
|
neither a source nor a weighing is a finding (`review.md` §Reviewing).
|
|
73
74
|
|
|
74
75
|
**Declared assumptions exist only where no question can be asked:**
|
|
75
76
|
|
|
76
77
|
- **Unattended** — the user is not reachable (the Unattended path above).
|
|
77
|
-
- **Delegated** — the user's own words handed you this choice ("your call");
|
|
78
|
-
|
|
78
|
+
- **Delegated** — the user's own words handed you this choice ("your call"); cite
|
|
79
|
+
their entry in the request record, or quote them where the unit has none (below
|
|
80
|
+
L3). A general "go ahead" is not a delegation.
|
|
79
81
|
|
|
80
82
|
Each states **what it is taken from** and **the alternative it excludes**, and is
|
|
81
83
|
listed where the user will read it: an assumption recorded alone is a decision
|
|
@@ -193,7 +195,8 @@ round). Cover:
|
|
|
193
195
|
|
|
194
196
|
## Reflect
|
|
195
197
|
|
|
196
|
-
|
|
198
|
+
At L3, append the answers verbatim to the request record first
|
|
199
|
+
(`audit/requests/REQUEST_[unit].md`, template in `templates.md`). Then fold them into the ANALYSIS `## Objective` / `## Vision-Alignment`
|
|
197
200
|
sections (Standalone) or into the D-UC/E-ISP (Hybrid) — do not leave them
|
|
198
201
|
sitting only in the chat transcript. The written document, not the
|
|
199
202
|
conversation, is what the next session and the next reviewer will read.
|
|
@@ -9,12 +9,15 @@ write triggers are `SKILL.md`'s, and they are identical in both modes.
|
|
|
9
9
|
|
|
10
10
|
Moved out of `SKILL.md` by F-051 so a Standalone session stops paying for a seam
|
|
11
11
|
it cannot reach. **The content below is the relocated text, unchanged except
|
|
12
|
-
for
|
|
13
|
-
review; the agent review precedes the proposal — `ADR_2026-10-07_agent_review_precedes_human`)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
for three declared amendments**: F-065 rewrote the review rows (devPNT performs no
|
|
13
|
+
review; the agent review precedes the proposal — `ADR_2026-10-07_agent_review_precedes_human`);
|
|
14
|
+
F-066 added one ownership-matrix row (merge review brief and E2E script, always
|
|
15
|
+
filesystem); F-067 added one (the request record, always filesystem). The digest
|
|
16
|
+
certifies the amended block, re-stamped each time only after the pre-edit block
|
|
17
|
+
matched the previous digest (F-066: `b700966f…0681`; F-067: `3636fe4a…9c9a`)
|
|
18
|
+
and the diff showed only the declared rows changed.
|
|
19
|
+
|
|
20
|
+
<!-- moved-block-sha256: 19641538bf1357bfad7197ff1f6a36f856534efe10690675efa31abb173cf9fe -->
|
|
18
21
|
### Hybrid in symbiosis with devPNT
|
|
19
22
|
|
|
20
23
|
Use this mode when the `devpnt_*` tools are available and point at the current project.
|
|
@@ -59,6 +62,8 @@ process; it never replaces it.
|
|
|
59
62
|
| Review log | `audit/reviews/REVIEW_LOG.md` | devPNT `REVIEW_LOG.md` (same path) | always filesystem |
|
|
60
63
|
| Operative guides | `ai_docs/reference/` | `ai_docs/reference/` — **filesystem-first even in Hybrid** | devPNT bootstrap may point at their index; it never copies their content |
|
|
61
64
|
| Handoff | `audit/handoff.md` | `audit/handoff.md` | always filesystem |
|
|
65
|
+
| Request record | `audit/requests/REQUEST_[feature].md` | same path; D-UC, E-ISP and M-VISION cite its entries; an approval given in devPNT is named by its proposal, not quoted | always filesystem: devPNT holds no owner chat statements |
|
|
66
|
+
| Merge review brief, E2E script | `solutions/MERGE_REVIEW_[feature].md`, `solutions/E2E_TEST_[feature].md` | same paths; they cite the E-TDD shadow and the devPNT doc_keys | always filesystem: they travel in the PR with the code |
|
|
62
67
|
|
|
63
68
|
### Triage equivalence (one threshold, two vocabularies)
|
|
64
69
|
|
|
@@ -270,6 +270,10 @@ The binding inputs, by review type:
|
|
|
270
270
|
**against** them, not only for internal consistency.
|
|
271
271
|
- **For a closure review, the diff and the test evidence**: the run output that
|
|
272
272
|
backs every completion claim, dated after the final relevant change.
|
|
273
|
+
- **For a design or closure review of an L3/E3 unit, the request record**
|
|
274
|
+
(`audit/requests/REQUEST_[unit].md`): the owner's own words, verbatim, that the
|
|
275
|
+
artifact's owner statements must resolve to. Without it, every such statement is
|
|
276
|
+
a CANNOT VERIFY.
|
|
273
277
|
- **For a design review, the threat model too** (same sources as above). Why this
|
|
274
278
|
one and not the whole set: file coverage crosses the impact-analysis→design hop on
|
|
275
279
|
a mechanical gate (every impacted file needs a design block), so a dropped file is
|
|
@@ -398,7 +402,11 @@ When you are the reviewer:
|
|
|
398
402
|
intent choice written with no owner-authored source and no weighing, a weighing
|
|
399
403
|
that names no rejected option or turns on an owner priority not on record, and a
|
|
400
404
|
fact or owner-held datum settled by a weighing instead of evidence are findings;
|
|
401
|
-
so is a cited source that does not say what the line claims.
|
|
405
|
+
so is a cited source that does not say what the line claims. An owner statement
|
|
406
|
+
the artifact relies on — an answer, an approval, a cost acceptance, a ruling, a
|
|
407
|
+
delegation — that resolves to no entry of the unit's request record, or that the
|
|
408
|
+
record contradicts, is a finding; so is a quotation in the record carrying what
|
|
409
|
+
its template says to redact. What makes a ground
|
|
402
410
|
or an assumption legal is each lens's `elicitation.md` §The question discipline —
|
|
403
411
|
cite it, never restate it. The fix is the question, not a better justification.
|
|
404
412
|
- **Restated facts (cite, never copy).** Every governance slot has ONE owning document
|
|
@@ -336,6 +336,17 @@ def kb_check_claims(root):
|
|
|
336
336
|
if rel not in fm_cache:
|
|
337
337
|
fm_cache[rel] = _note_frontmatter(root, rel)
|
|
338
338
|
return fm_cache[rel]
|
|
339
|
+
# F-069: the same per-run memo for the source paths themselves -- each
|
|
340
|
+
# distinct path is resolved and stat'ed once, and each cited extraction
|
|
341
|
+
# read once (loc_cache, owned here, dropped when this call returns).
|
|
342
|
+
src_cache = {}
|
|
343
|
+
loc_cache = {}
|
|
344
|
+
|
|
345
|
+
def _resolved(path_s):
|
|
346
|
+
if path_s not in src_cache:
|
|
347
|
+
t = sdlc_core.confine_under(root, path_s)
|
|
348
|
+
src_cache[path_s] = (t, t is not None and t.is_file())
|
|
349
|
+
return src_cache[path_s]
|
|
339
350
|
per_file_rows = []
|
|
340
351
|
for p in sorted(topics.glob("*.md")):
|
|
341
352
|
rel = "topics/" + p.name
|
|
@@ -357,16 +368,16 @@ def kb_check_claims(root):
|
|
|
357
368
|
errors.append("%s: source %r has no locator" % (where, src))
|
|
358
369
|
continue
|
|
359
370
|
path_s, loc = src.rsplit("#", 1)
|
|
360
|
-
target =
|
|
371
|
+
target, is_file = _resolved(path_s)
|
|
361
372
|
if target is None:
|
|
362
373
|
errors.append("%s: source %r escapes the docs root" % (where, src))
|
|
363
374
|
continue
|
|
364
|
-
if not
|
|
375
|
+
if not is_file:
|
|
365
376
|
errors.append("%s: source %r does not resolve — a claim whose "
|
|
366
377
|
"origin cannot be reopened is model knowledge"
|
|
367
378
|
% (where, src))
|
|
368
379
|
continue
|
|
369
|
-
kb_check_locator(target, loc, where, errors)
|
|
380
|
+
kb_check_locator(target, loc, where, errors, loc_cache)
|
|
370
381
|
# --- provenance ---
|
|
371
382
|
prov = row["prov"]
|
|
372
383
|
# Resolved ONCE, for every provenance: the non-GIVEN classes read it
|
|
@@ -556,8 +567,14 @@ def kb_check_claims(root):
|
|
|
556
567
|
return errors, warnings, notes
|
|
557
568
|
|
|
558
569
|
|
|
559
|
-
def kb_check_locator(target, loc, where, errors):
|
|
560
|
-
"""A locator must address an existing span of the stored bytes.
|
|
570
|
+
def kb_check_locator(target, loc, where, errors, cache=None):
|
|
571
|
+
"""A locator must address an existing span of the stored bytes.
|
|
572
|
+
|
|
573
|
+
`cache` is an optional dict the CALLER owns for one run (F-069): keyed by
|
|
574
|
+
the path actually read, it holds only what the checks compare against --
|
|
575
|
+
page lengths, a line count, or False for a missing extraction -- never the
|
|
576
|
+
text. Findings are still appended per call, so per row. Without it, every
|
|
577
|
+
call reads the file, as before."""
|
|
561
578
|
m = LOC_PAGE_RE.match(loc)
|
|
562
579
|
if m:
|
|
563
580
|
page, a, b = int(m.group(1)), int(m.group(2)), int(m.group(3))
|
|
@@ -566,17 +583,24 @@ def kb_check_locator(target, loc, where, errors):
|
|
|
566
583
|
return
|
|
567
584
|
# offsets address the stored extraction (<stem>.txt beside the original)
|
|
568
585
|
ext = target if target.suffix == ".txt" else target.with_suffix(".txt")
|
|
569
|
-
|
|
586
|
+
key = ("p", ext)
|
|
587
|
+
if cache is None or key not in cache:
|
|
588
|
+
lengths = ([len(pg) for pg in sdlc_core.read_text(ext).split("\f")]
|
|
589
|
+
if ext.is_file() else False)
|
|
590
|
+
if cache is not None:
|
|
591
|
+
cache[key] = lengths
|
|
592
|
+
else:
|
|
593
|
+
lengths = cache[key]
|
|
594
|
+
if lengths is False:
|
|
570
595
|
errors.append("%s: no stored extraction %s for locator %r — offsets "
|
|
571
596
|
"must address kept bytes" % (where, ext.name, loc))
|
|
572
597
|
return
|
|
573
|
-
|
|
574
|
-
if page < 1 or page > len(pages):
|
|
598
|
+
if page < 1 or page > len(lengths):
|
|
575
599
|
errors.append("%s: locator %r addresses page %d of %d" %
|
|
576
|
-
(where, loc, page, len(
|
|
577
|
-
elif b >
|
|
600
|
+
(where, loc, page, len(lengths)))
|
|
601
|
+
elif b > lengths[page - 1]:
|
|
578
602
|
errors.append("%s: locator %r spans past the end of page %d "
|
|
579
|
-
"(%d chars)" % (where, loc, page,
|
|
603
|
+
"(%d chars)" % (where, loc, page, lengths[page - 1]))
|
|
580
604
|
return
|
|
581
605
|
m = LOC_LINE_RE.match(loc)
|
|
582
606
|
if m:
|
|
@@ -584,7 +608,13 @@ def kb_check_locator(target, loc, where, errors):
|
|
|
584
608
|
if a > b or a < 1:
|
|
585
609
|
errors.append("%s: locator %r has an invalid line range" % (where, loc))
|
|
586
610
|
return
|
|
587
|
-
|
|
611
|
+
key = ("L", target)
|
|
612
|
+
if cache is None or key not in cache:
|
|
613
|
+
n = sdlc_core.read_text(target).count("\n") + 1
|
|
614
|
+
if cache is not None:
|
|
615
|
+
cache[key] = n
|
|
616
|
+
else:
|
|
617
|
+
n = cache[key]
|
|
588
618
|
if b > n:
|
|
589
619
|
errors.append("%s: locator %r spans past line %d" % (where, loc, n))
|
|
590
620
|
return
|
|
@@ -1085,12 +1115,18 @@ KB_GENERATED_RE = re.compile(r"GENERATED by \S+ index - do not edit by hand")
|
|
|
1085
1115
|
KB_HEX12_RE = re.compile(r"^[0-9a-f]{12}$")
|
|
1086
1116
|
|
|
1087
1117
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1118
|
+
# A citation of a claim id is a run of exactly its 12 lowercase hex characters
|
|
1119
|
+
# NOT embedded in a longer hex run: a git hash sharing a substring must never
|
|
1120
|
+
# count as a citation (either side, either case). Two such bounded runs cannot
|
|
1121
|
+
# overlap, so findall returns every one of them.
|
|
1122
|
+
KB_HEX_TOKEN_RE = re.compile(r"(?<![0-9a-fA-F])[0-9a-f]{12}(?![0-9a-fA-F])")
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
def _kb_hex_tokens(text):
|
|
1126
|
+
"""The ids a text cites, extracted in one pass (F-069). Callers test
|
|
1127
|
+
membership instead of scanning the text once per id: that per-(document,
|
|
1128
|
+
id) scan made the time cycle grow with superseded ids x living documents."""
|
|
1129
|
+
return frozenset(KB_HEX_TOKEN_RE.findall(text))
|
|
1094
1130
|
|
|
1095
1131
|
|
|
1096
1132
|
def _kb_df_entries(value):
|
|
@@ -1172,19 +1208,23 @@ def kb_time_cycle(docs):
|
|
|
1172
1208
|
if (meta.get("status") or "").strip() == "SUPERSEDED":
|
|
1173
1209
|
continue
|
|
1174
1210
|
living.append((rel, text))
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1211
|
+
# One token pass per living document, and none at all on a KB with no
|
|
1212
|
+
# supersession and no validity window (the orient line runs this at every
|
|
1213
|
+
# session start).
|
|
1214
|
+
tokens = ({rel: _kb_hex_tokens(text) for rel, text in living}
|
|
1215
|
+
if superseded or windows else {})
|
|
1216
|
+
for rel, _text in living:
|
|
1217
|
+
cites = tokens[rel] if tokens else frozenset()
|
|
1218
|
+
for old in cites.intersection(superseded):
|
|
1219
|
+
succs = superseded[old]
|
|
1220
|
+
missing = tuple(x for x in succs if x not in cites)
|
|
1221
|
+
if missing:
|
|
1222
|
+
cited.append((rel, old, missing, succs))
|
|
1183
1223
|
today = _dt.date.today().isoformat()
|
|
1184
1224
|
for topic_rel, rid, until in sorted(windows):
|
|
1185
1225
|
if until <= today:
|
|
1186
|
-
by = tuple(rel for rel,
|
|
1187
|
-
if rel != topic_rel and
|
|
1226
|
+
by = tuple(rel for rel, _text in living
|
|
1227
|
+
if rel != topic_rel and rid in tokens[rel])
|
|
1188
1228
|
expired.append((topic_rel, rid, until, by))
|
|
1189
1229
|
rev = {}
|
|
1190
1230
|
node_meta = {}
|