From d3ef0985e96f4c6349abe796c67deafd363df078 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 19:39:15 +0200 Subject: [PATCH 1/8] mece: hoist report-emit invariant; session state is internal The v1.2 retest surfaced that pharaoh-mece returns a brief executive summary instead of the full MECE Analysis Report. Root cause: the session-state update was the last instruction in the skill, becoming the LLM's focal point. Reordered so the report is the final visible output. Added a top-level Output Invariant making the full report mandatory and the session-state update internal. --- skills/pharaoh-mece/SKILL.md | 58 +++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/skills/pharaoh-mece/SKILL.md b/skills/pharaoh-mece/SKILL.md index 6ee3adb..957a631 100644 --- a/skills/pharaoh-mece/SKILL.md +++ b/skills/pharaoh-mece/SKILL.md @@ -3,6 +3,17 @@ name: pharaoh-mece description: "Use when checking for gaps, redundancies, and inconsistencies in sphinx-needs requirements, or validating traceability completeness" --- +## Output invariant + +This skill's visible output is the full **MECE Analysis Report** as defined in Step 9. The report is mandatory -- every invocation MUST emit the complete report with all sections (omit only sections with no findings, but always emit the Summary section). The session-state update in Step 8 is internal bookkeeping and MUST NOT replace the report in the output. + +Failure modes: +- Returning a one-paragraph executive summary instead of the table-formatted report -> REGRESSION. Emit the full report. +- Returning only the session-state confirmation -> REGRESSION. Emit the full report. +- Returning the report and asking the user a follow-up question instead of finishing -> REGRESSION. End the turn after the report. + +Non-interactive callers (`claude -p`, CI, batch) cannot reach the report past a follow-up prompt. The skill MUST be self-terminating. + # pharaoh:mece -- MECE Analysis Analyze a sphinx-needs project for structural completeness and consistency. @@ -300,11 +311,33 @@ Schema validation: Skipped (ubc CLI not available) --- -### Step 8: Present MECE report +### Step 8: Update session state (internal) + +This step is internal bookkeeping. Perform it silently before emitting the +report in Step 9 -- do not narrate it in the visible output. + +Update the session state file (`.pharaoh/session.json`) as described in +`skills/shared/strictness.md`: + +1. Read the current `.pharaoh/session.json` (or create the default structure + if it does not exist). +2. Set `global.mece_checked` to `true`. +3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. +4. Set `updated` to the current ISO 8601 timestamp. +5. Write the file back. + +The interaction with `require_mece_on_release` is described in Section 3 +(Strictness Behavior). + +--- + +### Step 9: Emit the MECE report (visible output) -Compile all findings into a single structured report. Use the format below -exactly. Omit sections that have no findings (but mention "None found" in the -summary counts). +This is the skill's visible output. Compile all findings into a single +structured report. Use the format below exactly. Omit sections that have no +findings (but mention "None found" in the summary counts). Always emit the +Summary section. After emitting the report, end the turn -- do not ask the +user follow-up questions. ``` ## MECE Analysis Report @@ -376,22 +409,7 @@ summary counts). - **critical**: More than 5 errors, or any category has more errors than valid needs of that type. The traceability structure has significant problems. ---- - -### Step 9: Update session state - -After presenting the report, update the session state file -(`.pharaoh/session.json`) as described in `skills/shared/strictness.md`: - -1. Read the current `.pharaoh/session.json` (or create the default structure - if it does not exist). -2. Set `global.mece_checked` to `true`. -3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. -4. Set `updated` to the current ISO 8601 timestamp. -5. Write the file back. - -This records that MECE analysis was performed, which satisfies the -`require_mece_on_release` gate if `pharaoh.toml` has it enabled. +Emit the report and end the turn. --- From 435d150755190e56ff9991ac96c3fc20ce08b74a Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 19:48:20 +0200 Subject: [PATCH 2/8] change: drop second-turn ack; emit document and end turn The v1.2 retest surfaced that pharaoh-change returns only the acknowledgment prompt; the change document never reaches the non-interactive caller. Removed Section 6's ask-for-ack pattern. The skill now writes session state with acknowledged: false, emits the full document, and ends the turn. Downstream enforcing-mode skills check the session-state flag on their own; advisory-mode flows ignore it. --- skills/pharaoh-change/SKILL.md | 49 ++++++++++++++-------------------- 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/skills/pharaoh-change/SKILL.md b/skills/pharaoh-change/SKILL.md index 24b3b28..209a6dd 100644 --- a/skills/pharaoh-change/SKILL.md +++ b/skills/pharaoh-change/SKILL.md @@ -3,6 +3,16 @@ name: pharaoh-change description: "Use when analyzing the impact of changing a requirement, specification, or any sphinx-needs item, including traceability to code via codelinks" --- +## Output invariant + +This skill's visible output is the full **Change Document** as defined in Step 4. The document is mandatory. Every invocation MUST emit the complete document with all sections. The session-state update in Step 5 is internal bookkeeping and MUST NOT replace the document. + +Failure modes: +- Returning only "Acknowledge this change analysis?" -> REGRESSION. Emit the full document. +- Returning only "Session state written" -> REGRESSION. Emit the full document. + +Non-interactive callers cannot reach the document past a follow-up prompt. The skill MUST be self-terminating. Acknowledgment is checked by downstream enforcing-mode authoring skills (`pharaoh-author`, `pharaoh-req-regenerate`, etc.) against the session-state flag. They FAIL with a message naming the file path and the field to flip. + # pharaoh-change: Change Impact Analysis Analyze the full impact of a proposed change to any sphinx-needs item. Trace through ALL link types -- standard `links`, `extra_links` (implements, tests, etc.), and sphinx-codelinks -- to produce a structured Change Document listing every affected need and code file with a recommended action. @@ -296,7 +306,7 @@ For each target need ID, add or update an entry in the `changes` dictionary: Key points: - Set `change_analysis` to the current timestamp. -- Set `acknowledged` to `false`. The user must explicitly acknowledge before this gate is satisfied. +- Set `acknowledged` to `false`. Downstream enforcing-mode authoring skills check this flag and the user flips it by editing the session-state file directly. - Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. - Update the top-level `updated` timestamp. @@ -306,35 +316,16 @@ Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly f --- -## 6. Ask for Acknowledgment - -After presenting the Change Document and updating session state, ask the user to acknowledge the analysis. - -Present exactly this prompt: - -``` -Acknowledge this change analysis? Acknowledging allows proceeding to the authoring skill for the affected needs. -``` - -### If the user acknowledges - -Update `.pharaoh/session.json`: set `acknowledged` to `true` for each target need ID analyzed in this invocation. Update the `updated` timestamp. - -Respond with: - -``` -Change analysis for acknowledged. You may now proceed with the appropriate authoring skill. -``` - -### If the user does not acknowledge +## 6. End the turn -Do not update the session state. The `acknowledged` field remains `false`. +After emitting the Change Document and writing session state, end the turn. Do not ask the user any follow-up question. -If the user asks questions about the Change Document, answer them. If the user requests modifications to the analysis (e.g., "also check the impact on module X"), re-run the relevant parts of the analysis and present an updated Change Document. Then ask for acknowledgment again. +Acknowledgment is a separate concern handled by downstream authoring skills: -### If the user ignores the acknowledgment prompt +- In **advisory** strictness, no skill checks `acknowledged`. The user proceeds freely. +- In **enforcing** strictness, downstream authoring skills check `.pharaoh/session.json[changes][].acknowledged` and FAIL with a message naming the file path and the field to flip. The user edits the session-state file directly to acknowledge. -Do not force the issue. The session state remains with `acknowledged: false`. In advisory mode this has no effect. In enforcing mode, any authoring skill will check and block if acknowledgment is missing. +This split keeps `pharaoh-change` non-interactive and CI-safe. --- @@ -346,13 +337,13 @@ Follow the instructions in `skills/shared/strictness.md` for strictness handling - Always produce the full Change Document regardless of workflow state. - No gating -- this skill has no prerequisites. -- After completing the analysis, the acknowledgment step is optional. If the user skips it, other skills will show a tip but will not block. +- The `acknowledged` flag in session state remains `false`. Other skills will show a tip but will not block. ### Enforcing mode - This skill itself has no prerequisites (it is gate-free per `skills/shared/strictness.md` Section 3, "Skills with no gates"). - However, its output gates any authoring skill. In enforcing mode, authoring skills check `.pharaoh/session.json` for `acknowledged: true` on the relevant need IDs. -- Always perform the full analysis. Always update session state. Always ask for acknowledgment. +- Always perform the full analysis. Always update session state. Always end the turn after emitting the document. ### Strictness has no effect on analysis depth @@ -494,4 +485,4 @@ Code impact: Not applicable (codelinks not configured). **Step 5** -- Session state written: `REQ_001` entry with `acknowledged: false`. -**Step 6** -- User asked to acknowledge. User says "yes". Session updated: `acknowledged: true`. +**Step 6** -- Turn ends after the Change Document and session-state write. Session state holds `acknowledged: false`. The user edits `.pharaoh/session.json` directly to flip the flag before invoking an enforcing-mode authoring skill. From fe1479b40870ea4efeffcd5308094fd927bfb4de Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 19:53:37 +0200 Subject: [PATCH 3/8] req-from-code: emit only fields declared in tailoring Rules 3 and 6 used to hardcode :source_doc: and :verification: as required emit. Projects whose tailoring does not declare those fields/links saw their sphinx-build -W gate fail on undeclared options. Both rules are now tailoring-driven: emit only when the catalog (for fields) or ubproject.toml extra_links (for verification link) declares the slot for the type. Added tailoring_path as a required input. --- skills/pharaoh-req-from-code/SKILL.md | 36 ++++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/skills/pharaoh-req-from-code/SKILL.md b/skills/pharaoh-req-from-code/SKILL.md index 0dffceb..19671a4 100644 --- a/skills/pharaoh-req-from-code/SKILL.md +++ b/skills/pharaoh-req-from-code/SKILL.md @@ -40,11 +40,15 @@ Known prior failures this rule catches: A clean behavioral shall with zero backticks and one `:source_doc:` is preferred over a code-narration shall with ten backticks. -### Rule 3 — `:source_doc:` must point at the implementing source code file +### Rule 3 -- `:source_doc:` emission is tailoring-driven -Every emitted CREQ carries `:source_doc:` pointing at a real source file — typically `.py`, `.rs`, `.ts`, `.go`, `.c`, `.cpp`, `.java` under the project's source tree (e.g. `src//csv/csv2needs.py`). Pointing `:source_doc:` at the spec RST file itself or at a prose feature doc is a validation failure — the spec RST is where the requirement lives, not where the behavior is implemented. +If the project's `/artefact-catalog.yaml` declares `source_doc` in `optional_fields` or `required_fields` for the directive's type (`target_level`), emit it pointing at the implementing source code file. If the project does NOT declare `source_doc` for the type, do NOT emit it. -When a CREQ's behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. +Rationale: emitting undeclared fields produces sphinx-build warnings under `-W` and breaks the build. Section 8 of #13 wired `pharaoh-setup` to populate the catalog from `[needs.fields.X]` declarations. This skill MUST honour the catalog on output. + +When the project declares `source_doc` and the CREQ behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. + +When the project does NOT declare `source_doc`, code grounding moves to a backref comment in the source file via `pharaoh-req-codelink-annotate` (mode: backref). The CREQ stays clean of paths. ### Rule 4 — CREQ adds constraint beyond the parent feat @@ -68,9 +72,16 @@ Expected floor per typical connector module (200-500 LOC, 3-8 exception classes, Each emitted block's body has exactly one `shall` clause. Zero intra-clause conjunctions joining modal-verb phrases (`, and shall` / ` and shall` / ` or raise` / `, or ` — all splits). Multiple observable behaviors = multiple CREQs. Intra-clause conjunctions are a hard fail regardless of behavioral quality; split the block before returning. -### Rule 6 — `:verification:` field is required +### Rule 6 -- `:verification:` emission is tailoring-driven + +`verification` in this skill names whichever of two tailoring slots the project declares it as: + +1. **As a link** in `/ubproject.toml` under `[[needs.extra_links]]` with name `verification` (or a project-renamed equivalent declared in `pharaoh.toml` under `[skill.req_from_code.verification_link_name]`). When declared, emit `:verification: tc__TBD` (or the project's declared placeholder convention). +2. **As a field** in `/artefact-catalog.yaml` under `optional_fields` or `required_fields` for the directive's type. When declared, emit `:verification: `. -Every emitted CREQ carries `:verification:` with at minimum the placeholder `tc__TBD`. Absence is a schema failure. If the project uses a different link name for the req→test relation (`verifies`, `covered_by`), declare it in `[[needs.extra_links]]`; the default placeholder stays required. +If neither slot declares `verification` for the directive's type, do NOT emit `:verification:`. The req-to-test relation is then declared elsewhere. For example, `pharaoh-vplan-draft` backlinks via `:verifies:` from the test side. + +Resolution order: link declaration in `ubproject.toml` takes precedence over field declaration in the catalog. A project declaring both is over-specified. Warn but emit the link form. ### Rule 7 — Backticks are for code / protocol tokens only @@ -106,7 +117,7 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe ## Atomicity - (a) Indivisible — one file in → N reqs out. No I/O beyond file read + optional Papyrus query/write + req emit. Emits in exactly one representation per call (`rst` OR `codelinks_comment`). -- (b) Input: `{file_path, target_level, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. +- (b) Input: `{file_path, target_level, tailoring_path, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. - (c) Reward: language-parametric fixture — given `test_fixture.` (`.py` / `.cpp` / `.rs` / `.ts`) containing exactly 3 named symbols (`FooBar`, `BazQux`, `Quux`), emitted reqs must mention all 3 by canonical name. Directive name must equal `target_level`. If `parent_feat_ids` is non-empty, every emitted block MUST contain `:satisfies: , , ...` with all parents comma-joined. - (d) Reusable across reverse-engineering workflows, spec drafting, standalone CI "are there reqs for this code?" gates. - (e) Composable — strictly one phase. Never invokes `pharaoh-arch-draft`, `pharaoh-fmea`, `pharaoh-plan`. @@ -115,6 +126,7 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe - `file_path`: absolute path to the source file (any language). - `target_level`: requirement artefact directive name as declared in the consumer project's `ubproject.toml` (e.g. `"comp_req"`, `"impl"`, `"spec"`). ID prefix is `target_level` + `__` unless `[[needs.types]].prefix` overrides. +- `tailoring_path`: absolute path to the project's `.pharaoh/project/` directory. Resolved per `skills/shared/tailoring-access.md`. Used by Step 1 to read `artefact-catalog.yaml` and the project's `ubproject.toml` once and cache the per-`target_level` declarations of `source_doc` and `verification` consumed by Rules 3 and 6. - `shared_context_path` (optional): companion source file read by all agents in the fan-out (e.g. `common.cpp`). Read but NOT reverse-engineered. - `papyrus_workspace` (optional): path to `.papyrus/` for canonical-term coordination. Absent → no-memory mode (skip Steps 1 and 3). - `reporter_id`: short identifier for this agent (e.g. `req-from-code:csv2needs.py`). @@ -145,6 +157,8 @@ A single JSON object. The top-level key names the emit mode: `reqs` for `emit=rs } ``` +Both `source_doc` and `verification` are conditional emit. `source_doc` MUST be omitted (from both the JSON object and the `raw_rst` block) if the project's `artefact-catalog.yaml` does not declare `source_doc` for the directive's type. `verification` MUST be omitted if neither `[[needs.extra_links]]` in `ubproject.toml` nor the catalog declares `verification` for the type. See Rules 3 and 6. + Field semantics: - `id` — ``. `` defaults to `target_level` (`comp_req` → `comp_req__foo_01`). If `[[needs.types]].prefix` declares `"CREQ_"`, use `CREQ_foo_01`. @@ -201,7 +215,7 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i 1. `raw_rst` matches Stage 1 + Stage 2 — block is well-formed. 2. `raw_rst` directive name equals `type` and equals input `target_level`. -3. Stage 2 on `raw_rst` yields at least `id`, `status`, `source_doc`, and `verification`; values match the corresponding top-level fields. +3. Stage 2 on `raw_rst` yields at least `id` and `status`. Whichever of `source_doc` and `verification` the project's tailoring declares for the directive's type MUST also appear. The other MUST NOT. 4. If `parent_feat_ids` was provided: `satisfies` field is non-empty and lists every parent id; `raw_rst` `:satisfies:` (or tailored child→parent link name) value matches. 5. Every option in `raw_rst` is either declared in `ubproject.toml` `[[needs.types]]`, a built-in sphinx-needs option, or a Pharaoh convention option. Reject unknown names (catches typos like `subsatisfies`). 6. If `allowed_ids` was provided: every `reqs[*].id` is a member of `allowed_ids`. @@ -212,6 +226,8 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i ### Step 1: Query Papyrus for canonical terms BEFORE naming +Resolve `tailoring_path` per `skills/shared/tailoring-access.md`. Read `/artefact-catalog.yaml` and `/ubproject.toml` once. Cache the per-`target_level` declarations of `source_doc` (field) and `verification` (link or field) for use by Rules 3 and 6. + Only applies if `papyrus_workspace` is provided. For each type / function / concept you may name in a req: 1. Form a short semantic query ("what do we call the subsystem that supervises other monitors"). @@ -264,14 +280,16 @@ For each boundary-observable behavior (per Rule 5 enumeration): - `:id: _` — `` resolved in Step 4. File basename (stem, snake_case) as disambiguator. Examples: `comp_req__csv2needs_01`, `CREQ_csv2needs_01`. - `:status: draft`. - `:satisfies: , ...` — iff `parent_feat_ids` non-empty. All parents comma-joined. If `[[needs.extra_links]]` declares a different outgoing name (e.g. `realizes`), use that instead. -- `:source_doc: ` — per Rule 3. -- `:verification: tc__TBD` — per Rule 6. +- `:source_doc: ` -- emit only if the project's `artefact-catalog.yaml` declares `source_doc` for `target_level` per Rule 3. +- `:verification: tc__TBD` -- emit only if `[[needs.extra_links]]` in `ubproject.toml` declares `verification` (or the catalog declares it as a field) for `target_level` per Rule 6. Use the project's declared placeholder when one is configured. - Body — single shall clause, component subject (Rule 1), no internals (Rule 2), adds constraint (Rule 4), atomicity + no conjunctions (Atomicity rule above). Canonical names from Steps 1/3. ### Step 5b: Emit — `codelinks_comment` mode For each behavior, emit one line that sphinx-codelinks' oneline parser would read back into a need equivalent to what `rst` mode would produce. Follow tailored `needs_fields` order and escape rules. Do NOT include the language comment prefix — that is `pharaoh-req-codelink-annotate`'s concern. +Rules 3 and 6 do not gate codelinks-mode output. The `:source_doc:` and `:verification:` RST options have no counterpart in the one-line comment string. Code grounding is implicit (the comment lives in the source file itself) and the verification relation is carried via the tailored `needs_fields` (e.g. as a `links` slot or omitted entirely). Project tailoring of which fields appear in the comment is governed by `[codelinks.projects..analyse.oneline_comment_style]`, not by `artefact-catalog.yaml` or `[[needs.extra_links]]`. + The `links` field renders as `[, ...]` when `parent_feat_ids` non-empty, else `[]` (or omitted if tailored `default = []`). The body shall-clause does NOT fit on a one-line comment — implied by the title and lost in this mode. For full shall-clause text use `emit="rst"`. Target: 1-5 reqs per file (per split_strategy). Fewer than 1 only if the file has no observable behavior; more than 5 suggests over-decomposition. From 030e57aaddaab9dc3375af1fa01e9eabe1177b13 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 20:04:16 +0200 Subject: [PATCH 4/8] release: drop interactive save prompt; report is final output The interactive 1/2/3/4 file-save prompt at Step 7b traps non-interactive callers. Replaced with a save_artifacts input flag. Step 7d session-state update moved to the start of the process so the release report is the last visible turn content. Tag suggestion collapsed into the report footer. --- skills/pharaoh-release/SKILL.md | 112 +++++++++++++++++--------------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/skills/pharaoh-release/SKILL.md b/skills/pharaoh-release/SKILL.md index c42e4a8..6dd4a8f 100644 --- a/skills/pharaoh-release/SKILL.md +++ b/skills/pharaoh-release/SKILL.md @@ -3,6 +3,16 @@ name: pharaoh-release description: "Use when preparing a release, generating changelogs from requirements, or summarizing requirement changes for version management" --- +## Output invariant + +This skill's visible output is the full release report (changelog plus release summary) as defined in Step 7. The report is mandatory. Every invocation MUST emit the complete report. The session-state update is internal bookkeeping. The skill is self-terminating. No interactive prompt at the end of the turn. + +Failure modes: +- Ending the turn with a "save these release artifacts?" prompt instead of the report -> REGRESSION. Emit the full report and end the turn. +- Returning a brief summary instead of the full changelog and release summary -> REGRESSION. + +File-save behaviour is controlled by an input flag (`save_artifacts`), not an interactive prompt. See Step 7.2 below. + # pharaoh-release Generate release artifacts from sphinx-needs changes. This skill identifies which @@ -19,6 +29,10 @@ analysis). - Producing traceability coverage metrics for compliance or audit documentation. - Generating release notes that include requirement impact chains. +## Input + +- **`save_artifacts`** (optional, default `none`): one of `none` | `changelog` | `release_notes` | `both`. Controls whether the skill writes the rendered changelog/release-notes artifacts to disk in addition to emitting them in the turn output. Pass explicitly when calling non-interactively. Defaults to `none` so a bare invocation never silently writes files. + ## Prerequisites This skill has workflow gates. Follow the strictness check in Step 1 before @@ -438,87 +452,83 @@ Code files referencing needs: ### Step 7: Output and Next Steps -#### 7a. Present changelog to user +The sub-steps below run in this fixed order: session-state update first +(internal bookkeeping), then artifact writes per the `save_artifacts` input +flag (silent side effects), and finally the visible release report. The +report is the LAST instruction in the skill so it is the last visible turn +content. The skill MUST end the turn after the report. No interactive +prompts. -Display the complete changelog (from Step 5) and release summary (from Step 6) -to the user in a single output. +#### 7.1. Update session state (internal) -#### 7b. Offer to write to file +Run this BEFORE emitting any visible output. Update `.pharaoh/session.json`: -After presenting the output, ask the user: +1. Read the current session state (or create the initial structure). +2. Set `global.last_release` to the current ISO 8601 timestamp. +3. Set `updated` to the current ISO 8601 timestamp. +4. Write the updated JSON back to `.pharaoh/session.json`. -``` -Would you like to save these release artifacts? +This is internal bookkeeping. It MUST NOT produce any visible turn output. - 1. Write changelog to CHANGELOG.md (append at top) - 2. Write full release notes to docs/releases/.md - 3. Write both - 4. Do not write any files +#### 7.2. Write artifacts per `save_artifacts` input flag -Choose an option: [1/2/3/4] -``` +Branch on the `save_artifacts` input value (default `none`): -**Option 1: Append to CHANGELOG.md** +- `none`: do nothing. The output was already presented. +- `changelog`: append the changelog entry to `CHANGELOG.md` (Option 1 logic below). +- `release_notes`: write `docs/releases/.md` (Option 2 logic below). +- `both`: execute both branches in order. + +Do NOT ask the user. Callers that want to choose interactively pass the flag explicitly. + +**`changelog` branch (append to CHANGELOG.md):** 1. Check if `CHANGELOG.md` exists in the workspace root. -2. If it exists, read its current content. Insert the new changelog entry at the - top of the file, after any existing header (e.g., after a `# Changelog` line). -3. If it does not exist, create it with a `# Changelog` header followed by the - new entry. -4. Show the user what will be written and confirm before writing. +2. If it exists, read its current content. Insert the new changelog entry at the top, after any existing header (e.g. after a `# Changelog` line). +3. If it does not exist, create it with a `# Changelog` header followed by the new entry. -**Option 2: Write to docs/releases/** +**`release_notes` branch (write `docs/releases/.md`):** 1. Create the `docs/releases/` directory if it does not exist. -2. Write the full release notes (changelog + release summary) to - `docs/releases/.md`. -3. Show the user what will be written and confirm before writing. - -**Option 3: Both** +2. Write the full release notes (changelog plus release summary) to `docs/releases/.md`. -Execute both Option 1 and Option 2. +**`both` branch:** execute both branches in order. -**Option 4: No files** +#### 7.3. Emit the release report (final visible output) -Do nothing. The output was already presented on screen. +This sub-step is the LAST instruction in the skill and produces the LAST +visible turn content. After emitting the report, end the turn. Do not ask +follow-up questions. -#### 7c. Suggest git tag +Display the complete changelog (from Step 5) and release summary (from +Step 6) to the user in a single output. Append the tag suggestion below as +the final footer line of the report. -After file output is handled, suggest tagging: +**Tag suggestion footer (append at the end of the report):** ``` Suggested next step: git tag -a -m "Release " -Create this tag now? [yes/no] +(Run the tag command manually if desired. The skill does not run git tag +automatically.) ``` -If the user confirms, run the `git tag` command. Do **not** push the tag. If the -user wants to push, they must explicitly request it. - -If the user declines, do nothing. - -#### 7d. Update session state - -After the release process completes successfully (regardless of whether files were -written), update `.pharaoh/session.json`: - -1. Read the current session state (or create the initial structure). -2. Set `global.last_release` to the current ISO 8601 timestamp. -3. Set `updated` to the current ISO 8601 timestamp. -4. Write the updated JSON back to `.pharaoh/session.json`. +The skill MUST NOT execute `git tag` itself. The skill MUST NOT ask the +user whether to create the tag. The footer is informational only. --- ## Key Constraints -1. **Never auto-tag or auto-push without user confirmation.** The `git tag` and - `git push` commands must always be explicitly confirmed by the user. Never run - them silently. +1. **Never run `git tag` or `git push`.** The skill MUST NOT execute either + command. The release report includes a tag suggestion as a footer line so the + user can run it manually. The skill MUST NOT prompt the user about tagging. -2. **Never overwrite files without asking.** Before writing to `CHANGELOG.md` or - any release notes file, show the user what will be written and get explicit - confirmation. If the file already exists, show how it will be modified. +2. **File writes are gated by the `save_artifacts` input flag.** The skill MUST + NOT prompt the user before writing `CHANGELOG.md` or `docs/releases/.md`. + The flag is the contract. Default `none` means no files are written. When the + flag selects a write branch, perform the write without asking. 3. **Include traceability metrics for safety-critical audit trails.** The release summary must always include the needs inventory and traceability coverage From 16124bed0265c009fdef1892a07848f90cd17e69 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 20:09:31 +0200 Subject: [PATCH 5/8] decide: emit written-confirmation line before next-step suggestion Adds an Output Invariant that requires the visible turn output to start with 'Decision written to '. Without this line the LLM was prone to collapsing visible output to just the next-step suggestion, leaving non-interactive callers without an audit trail of which decision was recorded. Session-state update reordered to run before visible output. --- skills/pharaoh-decide/SKILL.md | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/skills/pharaoh-decide/SKILL.md b/skills/pharaoh-decide/SKILL.md index b402ae5..0e0ef0c 100644 --- a/skills/pharaoh-decide/SKILL.md +++ b/skills/pharaoh-decide/SKILL.md @@ -3,6 +3,17 @@ name: pharaoh-decide description: "Use when recording a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements" --- +## Output invariant + +This skill's visible output MUST contain, in order: + +1. Confirmation line: `Decision written to ` +2. Optional follow-up suggestion (Step 7 content) + +The confirmation is mandatory. The suggestion is optional and is suppressed when the skill is called by `pharaoh:spec` (per existing Step 7 logic). Returning only the suggestion without the confirmation line is a REGRESSION. + +Session-state update is internal bookkeeping and runs before the visible output. + # pharaoh-decide Record design decisions as traceable sphinx-needs `decision` directives. Each decision captures the chosen option, rejected alternatives, rationale, and explicit links to the requirements or specifications it affects. This skill ensures every decision has proper `decided_by`, `alternatives`, and `rationale` fields. @@ -175,7 +186,9 @@ Decisions --- -### Step 6: Update Session State +### Step 6: Update Session State (internal) + +This step is internal bookkeeping. It MUST run before any visible output is emitted in Step 7. Do not print anything in this step. After successfully writing the decision: @@ -203,15 +216,19 @@ After successfully writing the decision: #### Standalone invocation -After writing the decision, suggest the next step: +Emit the visible turn output. The FIRST line MUST be the written-confirmation. The follow-up suggestion is appended after a blank line: ``` +Decision written to + Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` +Substitute `` with the generated ID from Step 3 and `` with the absolute or repo-relative path to the file written in Step 4 / Step 5. The confirmation line MUST appear even if the follow-up suggestion is suppressed for any reason. + #### Called by `pharaoh:spec` -Return the decision ID silently. Do not print follow-up suggestions. The calling skill manages the workflow. +Return the decision ID silently. Do not print follow-up suggestions. Do not print the written-confirmation line. The calling skill manages the workflow. --- @@ -302,9 +319,11 @@ Why was PostgreSQL chosen over the alternatives? **Step 6** -- Session state updated: `DEC_003.authored = true`. -**Step 7** -- Follow-up: +**Step 7** -- Visible output: ``` +Decision DEC_003 written to docs/decisions.rst + Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` From 298002413620150785e70002cd26f132d93252df Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 21:33:02 +0200 Subject: [PATCH 6/8] change: move document template to last major step The B2 fix in 435d150 added an Output Invariant requiring the full Change Document as visible output, but Sonnet still collapsed to a brief summary. Diagnosis: the document template was at Section 4 in the middle of the skill, with state-update and end-turn sections following it. Sonnet read the trailing instructions as the focal point and lost the template. Reorder: state update is now Section 4 (internal), document emission is Section 5 (final visible action) and the LAST major section before Strictness Behavior. The end-turn instruction is absorbed into Section 5's closing line. Sonnet now emits the full document end-to-end (verified 6110 chars vs 643 pre-refactor). --- skills/pharaoh-change/SKILL.md | 144 ++++++++++++++++----------------- 1 file changed, 71 insertions(+), 73 deletions(-) diff --git a/skills/pharaoh-change/SKILL.md b/skills/pharaoh-change/SKILL.md index 209a6dd..7e99ca3 100644 --- a/skills/pharaoh-change/SKILL.md +++ b/skills/pharaoh-change/SKILL.md @@ -5,7 +5,7 @@ description: "Use when analyzing the impact of changing a requirement, specifica ## Output invariant -This skill's visible output is the full **Change Document** as defined in Step 4. The document is mandatory. Every invocation MUST emit the complete document with all sections. The session-state update in Step 5 is internal bookkeeping and MUST NOT replace the document. +This skill's visible output is the full **Change Document** as defined in Step 5. The document is mandatory. Every invocation MUST emit the complete document with all sections. The session-state update in Step 4 is internal bookkeeping and MUST NOT replace the document. Step 5 is the LAST major section of the skill before Strictness Behavior, so the Change Document is the final visible content of the turn. Failure modes: - Returning only "Acknowledge this change analysis?" -> REGRESSION. Emit the full document. @@ -193,9 +193,67 @@ For each affected item (need or code file), classify the required action: --- -## 4. Produce the Change Document +## 4. Update Session State (internal) -Present results in the following structured format. Use markdown tables for readability. +This step is internal bookkeeping. It writes the change-analysis record to `.pharaoh/session.json` and emits NOTHING to the visible turn output. The Change Document is emitted in Step 5 (the final visible action of the turn). + +Follow the session state instructions in `skills/shared/strictness.md` (Section 4). + +### Step 4a: Read or initialize session state + +1. Check if `.pharaoh/session.json` exists. +2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: + +```json +{ + "version": 1, + "created": "", + "updated": "", + "changes": {}, + "global": { + "mece_checked": false, + "mece_timestamp": null, + "last_release": null + } +} +``` + +3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. + +### Step 4b: Record the change analysis + +For each target need ID, add or update an entry in the `changes` dictionary: + +```json +{ + "changes": { + "": { + "change_analysis": "", + "acknowledged": false, + "authored": false, + "verified": false + } + } +} +``` + +Key points: +- Set `change_analysis` to the current timestamp. +- Set `acknowledged` to `false`. Downstream enforcing-mode authoring skills check this flag and the user flips it by editing the session-state file directly. +- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. +- Update the top-level `updated` timestamp. + +### Step 4c: Write the session state + +Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). + +--- + +## 5. Emit the Change Document (final visible output) + +This is the visible output of the skill. After Step 4 has written session state, emit the full Change Document below as the final action of the turn. The document is the LAST instruction of the skill. Do NOT ask any follow-up question. End the turn after emitting. + +Use the structured format below. Use markdown tables for readability. Omit sections that have no rows but always emit the Change Request, Summary, and Recommendation header lines. ``` ## Change Document @@ -258,78 +316,20 @@ The following needs appear in the impact scope of multiple targets: - : affected by both and ``` ---- - -## 5. Update Session State - -After producing the Change Document, update the session state file so other skills can check whether change analysis was performed. - -Follow the session state instructions in `skills/shared/strictness.md` (Section 4). - -### Step 5a: Read or initialize session state - -1. Check if `.pharaoh/session.json` exists. -2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: - -```json -{ - "version": 1, - "created": "", - "updated": "", - "changes": {}, - "global": { - "mece_checked": false, - "mece_timestamp": null, - "last_release": null - } -} -``` - -3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. - -### Step 5b: Record the change analysis - -For each target need ID, add or update an entry in the `changes` dictionary: - -```json -{ - "changes": { - "": { - "change_analysis": "", - "acknowledged": false, - "authored": false, - "verified": false - } - } -} -``` - -Key points: -- Set `change_analysis` to the current timestamp. -- Set `acknowledged` to `false`. Downstream enforcing-mode authoring skills check this flag and the user flips it by editing the session-state file directly. -- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. -- Update the top-level `updated` timestamp. +### Acknowledgment is a separate concern -### Step 5c: Write the session state - -Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). - ---- - -## 6. End the turn - -After emitting the Change Document and writing session state, end the turn. Do not ask the user any follow-up question. - -Acknowledgment is a separate concern handled by downstream authoring skills: +Acknowledgment is NOT part of this skill's output. Do not ask the user to acknowledge the analysis. Downstream behavior: - In **advisory** strictness, no skill checks `acknowledged`. The user proceeds freely. - In **enforcing** strictness, downstream authoring skills check `.pharaoh/session.json[changes][].acknowledged` and FAIL with a message naming the file path and the field to flip. The user edits the session-state file directly to acknowledge. This split keeps `pharaoh-change` non-interactive and CI-safe. +End the turn after emitting the Change Document. + --- -## 7. Strictness Behavior +## 6. Strictness Behavior Follow the instructions in `skills/shared/strictness.md` for strictness handling. The specifics for this skill: @@ -351,7 +351,7 @@ Both advisory and enforcing modes perform the same analysis. Strictness only aff --- -## 8. Using ubc diff +## 7. Using ubc diff If the ubc CLI is available (detected in Step 2), use `ubc diff` to supplement or replace parts of the manual impact analysis. @@ -389,7 +389,7 @@ If `ubc diff` does not provide impact tracing (older version), use it only for i --- -## 9. Edge Cases +## 8. Edge Cases ### Target need does not exist @@ -447,7 +447,7 @@ Handled in Step 2a. If the user says "change the brake response time requirement --- -## 10. Complete Workflow Example +## 9. Complete Workflow Example To illustrate the full process, here is a walkthrough using the Brake System test fixture. @@ -481,8 +481,6 @@ Transitive: Code impact: Not applicable (codelinks not configured). -**Step 4** -- Change Document produced with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. - -**Step 5** -- Session state written: `REQ_001` entry with `acknowledged: false`. +**Step 4** -- Session state written: `REQ_001` entry with `acknowledged: false`. No visible output from this step. -**Step 6** -- Turn ends after the Change Document and session-state write. Session state holds `acknowledged: false`. The user edits `.pharaoh/session.json` directly to flip the flag before invoking an enforcing-mode authoring skill. +**Step 5** -- Change Document emitted with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. Turn ends after emission. Session state holds `acknowledged: false`. The user edits `.pharaoh/session.json` directly to flip the flag before invoking an enforcing-mode authoring skill. From 312119cf173aec1af69ed68025a3ca0f2d11c1b7 Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Tue, 5 May 2026 21:46:39 +0200 Subject: [PATCH 7/8] chore(release): bump version to 1.2.1 --- .claude-plugin/plugin.json | 2 +- .github/plugin/marketplace.json | 2 +- skills/pharaoh-change/SKILL.md | 179 ++++++++++++++------------ skills/pharaoh-decide/SKILL.md | 27 +--- skills/pharaoh-mece/SKILL.md | 58 +++------ skills/pharaoh-release/SKILL.md | 112 ++++++++-------- skills/pharaoh-req-from-code/SKILL.md | 36 ++---- 7 files changed, 181 insertions(+), 235 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 85a3617..0b4f7af 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "pharaoh", "description": "AI assistant framework for sphinx-needs projects: change analysis, traceability, MECE, authoring, verification, and release management", - "version": "1.2.0", + "version": "1.2.1", "author": { "name": "useblocks" }, diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index 83992de..f64cfca 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -8,7 +8,7 @@ { "name": "pharaoh", "description": "AI assistant framework for sphinx-needs projects", - "version": "1.2.0", + "version": "1.2.1", "source": "./", "author": { "name": "useblocks" diff --git a/skills/pharaoh-change/SKILL.md b/skills/pharaoh-change/SKILL.md index 7e99ca3..24b3b28 100644 --- a/skills/pharaoh-change/SKILL.md +++ b/skills/pharaoh-change/SKILL.md @@ -3,16 +3,6 @@ name: pharaoh-change description: "Use when analyzing the impact of changing a requirement, specification, or any sphinx-needs item, including traceability to code via codelinks" --- -## Output invariant - -This skill's visible output is the full **Change Document** as defined in Step 5. The document is mandatory. Every invocation MUST emit the complete document with all sections. The session-state update in Step 4 is internal bookkeeping and MUST NOT replace the document. Step 5 is the LAST major section of the skill before Strictness Behavior, so the Change Document is the final visible content of the turn. - -Failure modes: -- Returning only "Acknowledge this change analysis?" -> REGRESSION. Emit the full document. -- Returning only "Session state written" -> REGRESSION. Emit the full document. - -Non-interactive callers cannot reach the document past a follow-up prompt. The skill MUST be self-terminating. Acknowledgment is checked by downstream enforcing-mode authoring skills (`pharaoh-author`, `pharaoh-req-regenerate`, etc.) against the session-state flag. They FAIL with a message naming the file path and the field to flip. - # pharaoh-change: Change Impact Analysis Analyze the full impact of a proposed change to any sphinx-needs item. Trace through ALL link types -- standard `links`, `extra_links` (implements, tests, etc.), and sphinx-codelinks -- to produce a structured Change Document listing every affected need and code file with a recommended action. @@ -193,67 +183,9 @@ For each affected item (need or code file), classify the required action: --- -## 4. Update Session State (internal) - -This step is internal bookkeeping. It writes the change-analysis record to `.pharaoh/session.json` and emits NOTHING to the visible turn output. The Change Document is emitted in Step 5 (the final visible action of the turn). - -Follow the session state instructions in `skills/shared/strictness.md` (Section 4). - -### Step 4a: Read or initialize session state - -1. Check if `.pharaoh/session.json` exists. -2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: - -```json -{ - "version": 1, - "created": "", - "updated": "", - "changes": {}, - "global": { - "mece_checked": false, - "mece_timestamp": null, - "last_release": null - } -} -``` - -3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. - -### Step 4b: Record the change analysis - -For each target need ID, add or update an entry in the `changes` dictionary: - -```json -{ - "changes": { - "": { - "change_analysis": "", - "acknowledged": false, - "authored": false, - "verified": false - } - } -} -``` - -Key points: -- Set `change_analysis` to the current timestamp. -- Set `acknowledged` to `false`. Downstream enforcing-mode authoring skills check this flag and the user flips it by editing the session-state file directly. -- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. -- Update the top-level `updated` timestamp. - -### Step 4c: Write the session state - -Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). - ---- - -## 5. Emit the Change Document (final visible output) - -This is the visible output of the skill. After Step 4 has written session state, emit the full Change Document below as the final action of the turn. The document is the LAST instruction of the skill. Do NOT ask any follow-up question. End the turn after emitting. +## 4. Produce the Change Document -Use the structured format below. Use markdown tables for readability. Omit sections that have no rows but always emit the Change Request, Summary, and Recommendation header lines. +Present results in the following structured format. Use markdown tables for readability. ``` ## Change Document @@ -316,20 +248,97 @@ The following needs appear in the impact scope of multiple targets: - : affected by both and ``` -### Acknowledgment is a separate concern +--- + +## 5. Update Session State + +After producing the Change Document, update the session state file so other skills can check whether change analysis was performed. + +Follow the session state instructions in `skills/shared/strictness.md` (Section 4). + +### Step 5a: Read or initialize session state + +1. Check if `.pharaoh/session.json` exists. +2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: + +```json +{ + "version": 1, + "created": "", + "updated": "", + "changes": {}, + "global": { + "mece_checked": false, + "mece_timestamp": null, + "last_release": null + } +} +``` + +3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. + +### Step 5b: Record the change analysis + +For each target need ID, add or update an entry in the `changes` dictionary: + +```json +{ + "changes": { + "": { + "change_analysis": "", + "acknowledged": false, + "authored": false, + "verified": false + } + } +} +``` + +Key points: +- Set `change_analysis` to the current timestamp. +- Set `acknowledged` to `false`. The user must explicitly acknowledge before this gate is satisfied. +- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. +- Update the top-level `updated` timestamp. + +### Step 5c: Write the session state + +Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). + +--- + +## 6. Ask for Acknowledgment + +After presenting the Change Document and updating session state, ask the user to acknowledge the analysis. + +Present exactly this prompt: + +``` +Acknowledge this change analysis? Acknowledging allows proceeding to the authoring skill for the affected needs. +``` + +### If the user acknowledges -Acknowledgment is NOT part of this skill's output. Do not ask the user to acknowledge the analysis. Downstream behavior: +Update `.pharaoh/session.json`: set `acknowledged` to `true` for each target need ID analyzed in this invocation. Update the `updated` timestamp. -- In **advisory** strictness, no skill checks `acknowledged`. The user proceeds freely. -- In **enforcing** strictness, downstream authoring skills check `.pharaoh/session.json[changes][].acknowledged` and FAIL with a message naming the file path and the field to flip. The user edits the session-state file directly to acknowledge. +Respond with: -This split keeps `pharaoh-change` non-interactive and CI-safe. +``` +Change analysis for acknowledged. You may now proceed with the appropriate authoring skill. +``` + +### If the user does not acknowledge + +Do not update the session state. The `acknowledged` field remains `false`. -End the turn after emitting the Change Document. +If the user asks questions about the Change Document, answer them. If the user requests modifications to the analysis (e.g., "also check the impact on module X"), re-run the relevant parts of the analysis and present an updated Change Document. Then ask for acknowledgment again. + +### If the user ignores the acknowledgment prompt + +Do not force the issue. The session state remains with `acknowledged: false`. In advisory mode this has no effect. In enforcing mode, any authoring skill will check and block if acknowledgment is missing. --- -## 6. Strictness Behavior +## 7. Strictness Behavior Follow the instructions in `skills/shared/strictness.md` for strictness handling. The specifics for this skill: @@ -337,13 +346,13 @@ Follow the instructions in `skills/shared/strictness.md` for strictness handling - Always produce the full Change Document regardless of workflow state. - No gating -- this skill has no prerequisites. -- The `acknowledged` flag in session state remains `false`. Other skills will show a tip but will not block. +- After completing the analysis, the acknowledgment step is optional. If the user skips it, other skills will show a tip but will not block. ### Enforcing mode - This skill itself has no prerequisites (it is gate-free per `skills/shared/strictness.md` Section 3, "Skills with no gates"). - However, its output gates any authoring skill. In enforcing mode, authoring skills check `.pharaoh/session.json` for `acknowledged: true` on the relevant need IDs. -- Always perform the full analysis. Always update session state. Always end the turn after emitting the document. +- Always perform the full analysis. Always update session state. Always ask for acknowledgment. ### Strictness has no effect on analysis depth @@ -351,7 +360,7 @@ Both advisory and enforcing modes perform the same analysis. Strictness only aff --- -## 7. Using ubc diff +## 8. Using ubc diff If the ubc CLI is available (detected in Step 2), use `ubc diff` to supplement or replace parts of the manual impact analysis. @@ -389,7 +398,7 @@ If `ubc diff` does not provide impact tracing (older version), use it only for i --- -## 8. Edge Cases +## 9. Edge Cases ### Target need does not exist @@ -447,7 +456,7 @@ Handled in Step 2a. If the user says "change the brake response time requirement --- -## 9. Complete Workflow Example +## 10. Complete Workflow Example To illustrate the full process, here is a walkthrough using the Brake System test fixture. @@ -481,6 +490,8 @@ Transitive: Code impact: Not applicable (codelinks not configured). -**Step 4** -- Session state written: `REQ_001` entry with `acknowledged: false`. No visible output from this step. +**Step 4** -- Change Document produced with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. + +**Step 5** -- Session state written: `REQ_001` entry with `acknowledged: false`. -**Step 5** -- Change Document emitted with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. Turn ends after emission. Session state holds `acknowledged: false`. The user edits `.pharaoh/session.json` directly to flip the flag before invoking an enforcing-mode authoring skill. +**Step 6** -- User asked to acknowledge. User says "yes". Session updated: `acknowledged: true`. diff --git a/skills/pharaoh-decide/SKILL.md b/skills/pharaoh-decide/SKILL.md index 0e0ef0c..b402ae5 100644 --- a/skills/pharaoh-decide/SKILL.md +++ b/skills/pharaoh-decide/SKILL.md @@ -3,17 +3,6 @@ name: pharaoh-decide description: "Use when recording a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements" --- -## Output invariant - -This skill's visible output MUST contain, in order: - -1. Confirmation line: `Decision written to ` -2. Optional follow-up suggestion (Step 7 content) - -The confirmation is mandatory. The suggestion is optional and is suppressed when the skill is called by `pharaoh:spec` (per existing Step 7 logic). Returning only the suggestion without the confirmation line is a REGRESSION. - -Session-state update is internal bookkeeping and runs before the visible output. - # pharaoh-decide Record design decisions as traceable sphinx-needs `decision` directives. Each decision captures the chosen option, rejected alternatives, rationale, and explicit links to the requirements or specifications it affects. This skill ensures every decision has proper `decided_by`, `alternatives`, and `rationale` fields. @@ -186,9 +175,7 @@ Decisions --- -### Step 6: Update Session State (internal) - -This step is internal bookkeeping. It MUST run before any visible output is emitted in Step 7. Do not print anything in this step. +### Step 6: Update Session State After successfully writing the decision: @@ -216,19 +203,15 @@ After successfully writing the decision: #### Standalone invocation -Emit the visible turn output. The FIRST line MUST be the written-confirmation. The follow-up suggestion is appended after a blank line: +After writing the decision, suggest the next step: ``` -Decision written to - Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` -Substitute `` with the generated ID from Step 3 and `` with the absolute or repo-relative path to the file written in Step 4 / Step 5. The confirmation line MUST appear even if the follow-up suggestion is suppressed for any reason. - #### Called by `pharaoh:spec` -Return the decision ID silently. Do not print follow-up suggestions. Do not print the written-confirmation line. The calling skill manages the workflow. +Return the decision ID silently. Do not print follow-up suggestions. The calling skill manages the workflow. --- @@ -319,11 +302,9 @@ Why was PostgreSQL chosen over the alternatives? **Step 6** -- Session state updated: `DEC_003.authored = true`. -**Step 7** -- Visible output: +**Step 7** -- Follow-up: ``` -Decision DEC_003 written to docs/decisions.rst - Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` diff --git a/skills/pharaoh-mece/SKILL.md b/skills/pharaoh-mece/SKILL.md index 957a631..6ee3adb 100644 --- a/skills/pharaoh-mece/SKILL.md +++ b/skills/pharaoh-mece/SKILL.md @@ -3,17 +3,6 @@ name: pharaoh-mece description: "Use when checking for gaps, redundancies, and inconsistencies in sphinx-needs requirements, or validating traceability completeness" --- -## Output invariant - -This skill's visible output is the full **MECE Analysis Report** as defined in Step 9. The report is mandatory -- every invocation MUST emit the complete report with all sections (omit only sections with no findings, but always emit the Summary section). The session-state update in Step 8 is internal bookkeeping and MUST NOT replace the report in the output. - -Failure modes: -- Returning a one-paragraph executive summary instead of the table-formatted report -> REGRESSION. Emit the full report. -- Returning only the session-state confirmation -> REGRESSION. Emit the full report. -- Returning the report and asking the user a follow-up question instead of finishing -> REGRESSION. End the turn after the report. - -Non-interactive callers (`claude -p`, CI, batch) cannot reach the report past a follow-up prompt. The skill MUST be self-terminating. - # pharaoh:mece -- MECE Analysis Analyze a sphinx-needs project for structural completeness and consistency. @@ -311,33 +300,11 @@ Schema validation: Skipped (ubc CLI not available) --- -### Step 8: Update session state (internal) - -This step is internal bookkeeping. Perform it silently before emitting the -report in Step 9 -- do not narrate it in the visible output. - -Update the session state file (`.pharaoh/session.json`) as described in -`skills/shared/strictness.md`: - -1. Read the current `.pharaoh/session.json` (or create the default structure - if it does not exist). -2. Set `global.mece_checked` to `true`. -3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. -4. Set `updated` to the current ISO 8601 timestamp. -5. Write the file back. - -The interaction with `require_mece_on_release` is described in Section 3 -(Strictness Behavior). - ---- - -### Step 9: Emit the MECE report (visible output) +### Step 8: Present MECE report -This is the skill's visible output. Compile all findings into a single -structured report. Use the format below exactly. Omit sections that have no -findings (but mention "None found" in the summary counts). Always emit the -Summary section. After emitting the report, end the turn -- do not ask the -user follow-up questions. +Compile all findings into a single structured report. Use the format below +exactly. Omit sections that have no findings (but mention "None found" in the +summary counts). ``` ## MECE Analysis Report @@ -409,7 +376,22 @@ user follow-up questions. - **critical**: More than 5 errors, or any category has more errors than valid needs of that type. The traceability structure has significant problems. -Emit the report and end the turn. +--- + +### Step 9: Update session state + +After presenting the report, update the session state file +(`.pharaoh/session.json`) as described in `skills/shared/strictness.md`: + +1. Read the current `.pharaoh/session.json` (or create the default structure + if it does not exist). +2. Set `global.mece_checked` to `true`. +3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. +4. Set `updated` to the current ISO 8601 timestamp. +5. Write the file back. + +This records that MECE analysis was performed, which satisfies the +`require_mece_on_release` gate if `pharaoh.toml` has it enabled. --- diff --git a/skills/pharaoh-release/SKILL.md b/skills/pharaoh-release/SKILL.md index 6dd4a8f..c42e4a8 100644 --- a/skills/pharaoh-release/SKILL.md +++ b/skills/pharaoh-release/SKILL.md @@ -3,16 +3,6 @@ name: pharaoh-release description: "Use when preparing a release, generating changelogs from requirements, or summarizing requirement changes for version management" --- -## Output invariant - -This skill's visible output is the full release report (changelog plus release summary) as defined in Step 7. The report is mandatory. Every invocation MUST emit the complete report. The session-state update is internal bookkeeping. The skill is self-terminating. No interactive prompt at the end of the turn. - -Failure modes: -- Ending the turn with a "save these release artifacts?" prompt instead of the report -> REGRESSION. Emit the full report and end the turn. -- Returning a brief summary instead of the full changelog and release summary -> REGRESSION. - -File-save behaviour is controlled by an input flag (`save_artifacts`), not an interactive prompt. See Step 7.2 below. - # pharaoh-release Generate release artifacts from sphinx-needs changes. This skill identifies which @@ -29,10 +19,6 @@ analysis). - Producing traceability coverage metrics for compliance or audit documentation. - Generating release notes that include requirement impact chains. -## Input - -- **`save_artifacts`** (optional, default `none`): one of `none` | `changelog` | `release_notes` | `both`. Controls whether the skill writes the rendered changelog/release-notes artifacts to disk in addition to emitting them in the turn output. Pass explicitly when calling non-interactively. Defaults to `none` so a bare invocation never silently writes files. - ## Prerequisites This skill has workflow gates. Follow the strictness check in Step 1 before @@ -452,83 +438,87 @@ Code files referencing needs: ### Step 7: Output and Next Steps -The sub-steps below run in this fixed order: session-state update first -(internal bookkeeping), then artifact writes per the `save_artifacts` input -flag (silent side effects), and finally the visible release report. The -report is the LAST instruction in the skill so it is the last visible turn -content. The skill MUST end the turn after the report. No interactive -prompts. +#### 7a. Present changelog to user -#### 7.1. Update session state (internal) - -Run this BEFORE emitting any visible output. Update `.pharaoh/session.json`: - -1. Read the current session state (or create the initial structure). -2. Set `global.last_release` to the current ISO 8601 timestamp. -3. Set `updated` to the current ISO 8601 timestamp. -4. Write the updated JSON back to `.pharaoh/session.json`. +Display the complete changelog (from Step 5) and release summary (from Step 6) +to the user in a single output. -This is internal bookkeeping. It MUST NOT produce any visible turn output. +#### 7b. Offer to write to file -#### 7.2. Write artifacts per `save_artifacts` input flag +After presenting the output, ask the user: -Branch on the `save_artifacts` input value (default `none`): +``` +Would you like to save these release artifacts? -- `none`: do nothing. The output was already presented. -- `changelog`: append the changelog entry to `CHANGELOG.md` (Option 1 logic below). -- `release_notes`: write `docs/releases/.md` (Option 2 logic below). -- `both`: execute both branches in order. + 1. Write changelog to CHANGELOG.md (append at top) + 2. Write full release notes to docs/releases/.md + 3. Write both + 4. Do not write any files -Do NOT ask the user. Callers that want to choose interactively pass the flag explicitly. +Choose an option: [1/2/3/4] +``` -**`changelog` branch (append to CHANGELOG.md):** +**Option 1: Append to CHANGELOG.md** 1. Check if `CHANGELOG.md` exists in the workspace root. -2. If it exists, read its current content. Insert the new changelog entry at the top, after any existing header (e.g. after a `# Changelog` line). -3. If it does not exist, create it with a `# Changelog` header followed by the new entry. +2. If it exists, read its current content. Insert the new changelog entry at the + top of the file, after any existing header (e.g., after a `# Changelog` line). +3. If it does not exist, create it with a `# Changelog` header followed by the + new entry. +4. Show the user what will be written and confirm before writing. -**`release_notes` branch (write `docs/releases/.md`):** +**Option 2: Write to docs/releases/** 1. Create the `docs/releases/` directory if it does not exist. -2. Write the full release notes (changelog plus release summary) to `docs/releases/.md`. +2. Write the full release notes (changelog + release summary) to + `docs/releases/.md`. +3. Show the user what will be written and confirm before writing. + +**Option 3: Both** -**`both` branch:** execute both branches in order. +Execute both Option 1 and Option 2. -#### 7.3. Emit the release report (final visible output) +**Option 4: No files** -This sub-step is the LAST instruction in the skill and produces the LAST -visible turn content. After emitting the report, end the turn. Do not ask -follow-up questions. +Do nothing. The output was already presented on screen. -Display the complete changelog (from Step 5) and release summary (from -Step 6) to the user in a single output. Append the tag suggestion below as -the final footer line of the report. +#### 7c. Suggest git tag -**Tag suggestion footer (append at the end of the report):** +After file output is handled, suggest tagging: ``` Suggested next step: git tag -a -m "Release " -(Run the tag command manually if desired. The skill does not run git tag -automatically.) +Create this tag now? [yes/no] ``` -The skill MUST NOT execute `git tag` itself. The skill MUST NOT ask the -user whether to create the tag. The footer is informational only. +If the user confirms, run the `git tag` command. Do **not** push the tag. If the +user wants to push, they must explicitly request it. + +If the user declines, do nothing. + +#### 7d. Update session state + +After the release process completes successfully (regardless of whether files were +written), update `.pharaoh/session.json`: + +1. Read the current session state (or create the initial structure). +2. Set `global.last_release` to the current ISO 8601 timestamp. +3. Set `updated` to the current ISO 8601 timestamp. +4. Write the updated JSON back to `.pharaoh/session.json`. --- ## Key Constraints -1. **Never run `git tag` or `git push`.** The skill MUST NOT execute either - command. The release report includes a tag suggestion as a footer line so the - user can run it manually. The skill MUST NOT prompt the user about tagging. +1. **Never auto-tag or auto-push without user confirmation.** The `git tag` and + `git push` commands must always be explicitly confirmed by the user. Never run + them silently. -2. **File writes are gated by the `save_artifacts` input flag.** The skill MUST - NOT prompt the user before writing `CHANGELOG.md` or `docs/releases/.md`. - The flag is the contract. Default `none` means no files are written. When the - flag selects a write branch, perform the write without asking. +2. **Never overwrite files without asking.** Before writing to `CHANGELOG.md` or + any release notes file, show the user what will be written and get explicit + confirmation. If the file already exists, show how it will be modified. 3. **Include traceability metrics for safety-critical audit trails.** The release summary must always include the needs inventory and traceability coverage diff --git a/skills/pharaoh-req-from-code/SKILL.md b/skills/pharaoh-req-from-code/SKILL.md index 19671a4..0dffceb 100644 --- a/skills/pharaoh-req-from-code/SKILL.md +++ b/skills/pharaoh-req-from-code/SKILL.md @@ -40,15 +40,11 @@ Known prior failures this rule catches: A clean behavioral shall with zero backticks and one `:source_doc:` is preferred over a code-narration shall with ten backticks. -### Rule 3 -- `:source_doc:` emission is tailoring-driven +### Rule 3 — `:source_doc:` must point at the implementing source code file -If the project's `/artefact-catalog.yaml` declares `source_doc` in `optional_fields` or `required_fields` for the directive's type (`target_level`), emit it pointing at the implementing source code file. If the project does NOT declare `source_doc` for the type, do NOT emit it. +Every emitted CREQ carries `:source_doc:` pointing at a real source file — typically `.py`, `.rs`, `.ts`, `.go`, `.c`, `.cpp`, `.java` under the project's source tree (e.g. `src//csv/csv2needs.py`). Pointing `:source_doc:` at the spec RST file itself or at a prose feature doc is a validation failure — the spec RST is where the requirement lives, not where the behavior is implemented. -Rationale: emitting undeclared fields produces sphinx-build warnings under `-W` and breaks the build. Section 8 of #13 wired `pharaoh-setup` to populate the catalog from `[needs.fields.X]` declarations. This skill MUST honour the catalog on output. - -When the project declares `source_doc` and the CREQ behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. - -When the project does NOT declare `source_doc`, code grounding moves to a backref comment in the source file via `pharaoh-req-codelink-annotate` (mode: backref). The CREQ stays clean of paths. +When a CREQ's behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. ### Rule 4 — CREQ adds constraint beyond the parent feat @@ -72,16 +68,9 @@ Expected floor per typical connector module (200-500 LOC, 3-8 exception classes, Each emitted block's body has exactly one `shall` clause. Zero intra-clause conjunctions joining modal-verb phrases (`, and shall` / ` and shall` / ` or raise` / `, or ` — all splits). Multiple observable behaviors = multiple CREQs. Intra-clause conjunctions are a hard fail regardless of behavioral quality; split the block before returning. -### Rule 6 -- `:verification:` emission is tailoring-driven - -`verification` in this skill names whichever of two tailoring slots the project declares it as: - -1. **As a link** in `/ubproject.toml` under `[[needs.extra_links]]` with name `verification` (or a project-renamed equivalent declared in `pharaoh.toml` under `[skill.req_from_code.verification_link_name]`). When declared, emit `:verification: tc__TBD` (or the project's declared placeholder convention). -2. **As a field** in `/artefact-catalog.yaml` under `optional_fields` or `required_fields` for the directive's type. When declared, emit `:verification: `. +### Rule 6 — `:verification:` field is required -If neither slot declares `verification` for the directive's type, do NOT emit `:verification:`. The req-to-test relation is then declared elsewhere. For example, `pharaoh-vplan-draft` backlinks via `:verifies:` from the test side. - -Resolution order: link declaration in `ubproject.toml` takes precedence over field declaration in the catalog. A project declaring both is over-specified. Warn but emit the link form. +Every emitted CREQ carries `:verification:` with at minimum the placeholder `tc__TBD`. Absence is a schema failure. If the project uses a different link name for the req→test relation (`verifies`, `covered_by`), declare it in `[[needs.extra_links]]`; the default placeholder stays required. ### Rule 7 — Backticks are for code / protocol tokens only @@ -117,7 +106,7 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe ## Atomicity - (a) Indivisible — one file in → N reqs out. No I/O beyond file read + optional Papyrus query/write + req emit. Emits in exactly one representation per call (`rst` OR `codelinks_comment`). -- (b) Input: `{file_path, target_level, tailoring_path, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. +- (b) Input: `{file_path, target_level, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. - (c) Reward: language-parametric fixture — given `test_fixture.` (`.py` / `.cpp` / `.rs` / `.ts`) containing exactly 3 named symbols (`FooBar`, `BazQux`, `Quux`), emitted reqs must mention all 3 by canonical name. Directive name must equal `target_level`. If `parent_feat_ids` is non-empty, every emitted block MUST contain `:satisfies: , , ...` with all parents comma-joined. - (d) Reusable across reverse-engineering workflows, spec drafting, standalone CI "are there reqs for this code?" gates. - (e) Composable — strictly one phase. Never invokes `pharaoh-arch-draft`, `pharaoh-fmea`, `pharaoh-plan`. @@ -126,7 +115,6 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe - `file_path`: absolute path to the source file (any language). - `target_level`: requirement artefact directive name as declared in the consumer project's `ubproject.toml` (e.g. `"comp_req"`, `"impl"`, `"spec"`). ID prefix is `target_level` + `__` unless `[[needs.types]].prefix` overrides. -- `tailoring_path`: absolute path to the project's `.pharaoh/project/` directory. Resolved per `skills/shared/tailoring-access.md`. Used by Step 1 to read `artefact-catalog.yaml` and the project's `ubproject.toml` once and cache the per-`target_level` declarations of `source_doc` and `verification` consumed by Rules 3 and 6. - `shared_context_path` (optional): companion source file read by all agents in the fan-out (e.g. `common.cpp`). Read but NOT reverse-engineered. - `papyrus_workspace` (optional): path to `.papyrus/` for canonical-term coordination. Absent → no-memory mode (skip Steps 1 and 3). - `reporter_id`: short identifier for this agent (e.g. `req-from-code:csv2needs.py`). @@ -157,8 +145,6 @@ A single JSON object. The top-level key names the emit mode: `reqs` for `emit=rs } ``` -Both `source_doc` and `verification` are conditional emit. `source_doc` MUST be omitted (from both the JSON object and the `raw_rst` block) if the project's `artefact-catalog.yaml` does not declare `source_doc` for the directive's type. `verification` MUST be omitted if neither `[[needs.extra_links]]` in `ubproject.toml` nor the catalog declares `verification` for the type. See Rules 3 and 6. - Field semantics: - `id` — ``. `` defaults to `target_level` (`comp_req` → `comp_req__foo_01`). If `[[needs.types]].prefix` declares `"CREQ_"`, use `CREQ_foo_01`. @@ -215,7 +201,7 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i 1. `raw_rst` matches Stage 1 + Stage 2 — block is well-formed. 2. `raw_rst` directive name equals `type` and equals input `target_level`. -3. Stage 2 on `raw_rst` yields at least `id` and `status`. Whichever of `source_doc` and `verification` the project's tailoring declares for the directive's type MUST also appear. The other MUST NOT. +3. Stage 2 on `raw_rst` yields at least `id`, `status`, `source_doc`, and `verification`; values match the corresponding top-level fields. 4. If `parent_feat_ids` was provided: `satisfies` field is non-empty and lists every parent id; `raw_rst` `:satisfies:` (or tailored child→parent link name) value matches. 5. Every option in `raw_rst` is either declared in `ubproject.toml` `[[needs.types]]`, a built-in sphinx-needs option, or a Pharaoh convention option. Reject unknown names (catches typos like `subsatisfies`). 6. If `allowed_ids` was provided: every `reqs[*].id` is a member of `allowed_ids`. @@ -226,8 +212,6 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i ### Step 1: Query Papyrus for canonical terms BEFORE naming -Resolve `tailoring_path` per `skills/shared/tailoring-access.md`. Read `/artefact-catalog.yaml` and `/ubproject.toml` once. Cache the per-`target_level` declarations of `source_doc` (field) and `verification` (link or field) for use by Rules 3 and 6. - Only applies if `papyrus_workspace` is provided. For each type / function / concept you may name in a req: 1. Form a short semantic query ("what do we call the subsystem that supervises other monitors"). @@ -280,16 +264,14 @@ For each boundary-observable behavior (per Rule 5 enumeration): - `:id: _` — `` resolved in Step 4. File basename (stem, snake_case) as disambiguator. Examples: `comp_req__csv2needs_01`, `CREQ_csv2needs_01`. - `:status: draft`. - `:satisfies: , ...` — iff `parent_feat_ids` non-empty. All parents comma-joined. If `[[needs.extra_links]]` declares a different outgoing name (e.g. `realizes`), use that instead. -- `:source_doc: ` -- emit only if the project's `artefact-catalog.yaml` declares `source_doc` for `target_level` per Rule 3. -- `:verification: tc__TBD` -- emit only if `[[needs.extra_links]]` in `ubproject.toml` declares `verification` (or the catalog declares it as a field) for `target_level` per Rule 6. Use the project's declared placeholder when one is configured. +- `:source_doc: ` — per Rule 3. +- `:verification: tc__TBD` — per Rule 6. - Body — single shall clause, component subject (Rule 1), no internals (Rule 2), adds constraint (Rule 4), atomicity + no conjunctions (Atomicity rule above). Canonical names from Steps 1/3. ### Step 5b: Emit — `codelinks_comment` mode For each behavior, emit one line that sphinx-codelinks' oneline parser would read back into a need equivalent to what `rst` mode would produce. Follow tailored `needs_fields` order and escape rules. Do NOT include the language comment prefix — that is `pharaoh-req-codelink-annotate`'s concern. -Rules 3 and 6 do not gate codelinks-mode output. The `:source_doc:` and `:verification:` RST options have no counterpart in the one-line comment string. Code grounding is implicit (the comment lives in the source file itself) and the verification relation is carried via the tailored `needs_fields` (e.g. as a `links` slot or omitted entirely). Project tailoring of which fields appear in the comment is governed by `[codelinks.projects..analyse.oneline_comment_style]`, not by `artefact-catalog.yaml` or `[[needs.extra_links]]`. - The `links` field renders as `[, ...]` when `parent_feat_ids` non-empty, else `[]` (or omitted if tailored `default = []`). The body shall-clause does NOT fit on a one-line comment — implied by the title and lost in this mode. For full shall-clause text use `emit="rst"`. Target: 1-5 reqs per file (per split_strategy). Fewer than 1 only if the file has no observable behavior; more than 5 suggests over-decomposition. From 3c72803a6d5a58cb6237f70aa2dacda36f8c439a Mon Sep 17 00:00:00 2001 From: Bartosz Burda Date: Wed, 6 May 2026 07:54:38 +0200 Subject: [PATCH 8/8] fix(skills): restore B-task SKILL.md fixes inadvertently reverted in 312119c Commit 312119c (chore(release): bump version to 1.2.1) accidentally included reverted versions of the 5 skill files modified in commits d3ef098, 435d150, fe1479b, 030e57a, 16124be, and 2980024. Restored content from 2980024. The version bump in plugin.json and marketplace.json is preserved. --- skills/pharaoh-change/SKILL.md | 179 ++++++++++++-------------- skills/pharaoh-decide/SKILL.md | 27 +++- skills/pharaoh-mece/SKILL.md | 58 ++++++--- skills/pharaoh-release/SKILL.md | 112 ++++++++-------- skills/pharaoh-req-from-code/SKILL.md | 36 ++++-- 5 files changed, 233 insertions(+), 179 deletions(-) diff --git a/skills/pharaoh-change/SKILL.md b/skills/pharaoh-change/SKILL.md index 24b3b28..7e99ca3 100644 --- a/skills/pharaoh-change/SKILL.md +++ b/skills/pharaoh-change/SKILL.md @@ -3,6 +3,16 @@ name: pharaoh-change description: "Use when analyzing the impact of changing a requirement, specification, or any sphinx-needs item, including traceability to code via codelinks" --- +## Output invariant + +This skill's visible output is the full **Change Document** as defined in Step 5. The document is mandatory. Every invocation MUST emit the complete document with all sections. The session-state update in Step 4 is internal bookkeeping and MUST NOT replace the document. Step 5 is the LAST major section of the skill before Strictness Behavior, so the Change Document is the final visible content of the turn. + +Failure modes: +- Returning only "Acknowledge this change analysis?" -> REGRESSION. Emit the full document. +- Returning only "Session state written" -> REGRESSION. Emit the full document. + +Non-interactive callers cannot reach the document past a follow-up prompt. The skill MUST be self-terminating. Acknowledgment is checked by downstream enforcing-mode authoring skills (`pharaoh-author`, `pharaoh-req-regenerate`, etc.) against the session-state flag. They FAIL with a message naming the file path and the field to flip. + # pharaoh-change: Change Impact Analysis Analyze the full impact of a proposed change to any sphinx-needs item. Trace through ALL link types -- standard `links`, `extra_links` (implements, tests, etc.), and sphinx-codelinks -- to produce a structured Change Document listing every affected need and code file with a recommended action. @@ -183,9 +193,67 @@ For each affected item (need or code file), classify the required action: --- -## 4. Produce the Change Document +## 4. Update Session State (internal) + +This step is internal bookkeeping. It writes the change-analysis record to `.pharaoh/session.json` and emits NOTHING to the visible turn output. The Change Document is emitted in Step 5 (the final visible action of the turn). + +Follow the session state instructions in `skills/shared/strictness.md` (Section 4). + +### Step 4a: Read or initialize session state + +1. Check if `.pharaoh/session.json` exists. +2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: + +```json +{ + "version": 1, + "created": "", + "updated": "", + "changes": {}, + "global": { + "mece_checked": false, + "mece_timestamp": null, + "last_release": null + } +} +``` + +3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. + +### Step 4b: Record the change analysis + +For each target need ID, add or update an entry in the `changes` dictionary: + +```json +{ + "changes": { + "": { + "change_analysis": "", + "acknowledged": false, + "authored": false, + "verified": false + } + } +} +``` + +Key points: +- Set `change_analysis` to the current timestamp. +- Set `acknowledged` to `false`. Downstream enforcing-mode authoring skills check this flag and the user flips it by editing the session-state file directly. +- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. +- Update the top-level `updated` timestamp. + +### Step 4c: Write the session state + +Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). + +--- + +## 5. Emit the Change Document (final visible output) + +This is the visible output of the skill. After Step 4 has written session state, emit the full Change Document below as the final action of the turn. The document is the LAST instruction of the skill. Do NOT ask any follow-up question. End the turn after emitting. -Present results in the following structured format. Use markdown tables for readability. +Use the structured format below. Use markdown tables for readability. Omit sections that have no rows but always emit the Change Request, Summary, and Recommendation header lines. ``` ## Change Document @@ -248,97 +316,20 @@ The following needs appear in the impact scope of multiple targets: - : affected by both and ``` ---- - -## 5. Update Session State - -After producing the Change Document, update the session state file so other skills can check whether change analysis was performed. - -Follow the session state instructions in `skills/shared/strictness.md` (Section 4). - -### Step 5a: Read or initialize session state - -1. Check if `.pharaoh/session.json` exists. -2. If it does not exist, create the `.pharaoh/` directory and initialize the session state: - -```json -{ - "version": 1, - "created": "", - "updated": "", - "changes": {}, - "global": { - "mece_checked": false, - "mece_timestamp": null, - "last_release": null - } -} -``` - -3. If it exists, read and parse it. If the JSON is malformed, warn the user and re-initialize. - -### Step 5b: Record the change analysis - -For each target need ID, add or update an entry in the `changes` dictionary: - -```json -{ - "changes": { - "": { - "change_analysis": "", - "acknowledged": false, - "authored": false, - "verified": false - } - } -} -``` - -Key points: -- Set `change_analysis` to the current timestamp. -- Set `acknowledged` to `false`. The user must explicitly acknowledge before this gate is satisfied. -- Do not overwrite `authored` or `verified` if the entry already exists -- preserve those values. -- Update the top-level `updated` timestamp. - -### Step 5c: Write the session state - -Write the updated JSON to `.pharaoh/session.json`. Ensure the JSON is properly formatted (indented for readability). - ---- - -## 6. Ask for Acknowledgment - -After presenting the Change Document and updating session state, ask the user to acknowledge the analysis. - -Present exactly this prompt: - -``` -Acknowledge this change analysis? Acknowledging allows proceeding to the authoring skill for the affected needs. -``` - -### If the user acknowledges +### Acknowledgment is a separate concern -Update `.pharaoh/session.json`: set `acknowledged` to `true` for each target need ID analyzed in this invocation. Update the `updated` timestamp. +Acknowledgment is NOT part of this skill's output. Do not ask the user to acknowledge the analysis. Downstream behavior: -Respond with: +- In **advisory** strictness, no skill checks `acknowledged`. The user proceeds freely. +- In **enforcing** strictness, downstream authoring skills check `.pharaoh/session.json[changes][].acknowledged` and FAIL with a message naming the file path and the field to flip. The user edits the session-state file directly to acknowledge. -``` -Change analysis for acknowledged. You may now proceed with the appropriate authoring skill. -``` - -### If the user does not acknowledge - -Do not update the session state. The `acknowledged` field remains `false`. +This split keeps `pharaoh-change` non-interactive and CI-safe. -If the user asks questions about the Change Document, answer them. If the user requests modifications to the analysis (e.g., "also check the impact on module X"), re-run the relevant parts of the analysis and present an updated Change Document. Then ask for acknowledgment again. - -### If the user ignores the acknowledgment prompt - -Do not force the issue. The session state remains with `acknowledged: false`. In advisory mode this has no effect. In enforcing mode, any authoring skill will check and block if acknowledgment is missing. +End the turn after emitting the Change Document. --- -## 7. Strictness Behavior +## 6. Strictness Behavior Follow the instructions in `skills/shared/strictness.md` for strictness handling. The specifics for this skill: @@ -346,13 +337,13 @@ Follow the instructions in `skills/shared/strictness.md` for strictness handling - Always produce the full Change Document regardless of workflow state. - No gating -- this skill has no prerequisites. -- After completing the analysis, the acknowledgment step is optional. If the user skips it, other skills will show a tip but will not block. +- The `acknowledged` flag in session state remains `false`. Other skills will show a tip but will not block. ### Enforcing mode - This skill itself has no prerequisites (it is gate-free per `skills/shared/strictness.md` Section 3, "Skills with no gates"). - However, its output gates any authoring skill. In enforcing mode, authoring skills check `.pharaoh/session.json` for `acknowledged: true` on the relevant need IDs. -- Always perform the full analysis. Always update session state. Always ask for acknowledgment. +- Always perform the full analysis. Always update session state. Always end the turn after emitting the document. ### Strictness has no effect on analysis depth @@ -360,7 +351,7 @@ Both advisory and enforcing modes perform the same analysis. Strictness only aff --- -## 8. Using ubc diff +## 7. Using ubc diff If the ubc CLI is available (detected in Step 2), use `ubc diff` to supplement or replace parts of the manual impact analysis. @@ -398,7 +389,7 @@ If `ubc diff` does not provide impact tracing (older version), use it only for i --- -## 9. Edge Cases +## 8. Edge Cases ### Target need does not exist @@ -456,7 +447,7 @@ Handled in Step 2a. If the user says "change the brake response time requirement --- -## 10. Complete Workflow Example +## 9. Complete Workflow Example To illustrate the full process, here is a walkthrough using the Brake System test fixture. @@ -490,8 +481,6 @@ Transitive: Code impact: Not applicable (codelinks not configured). -**Step 4** -- Change Document produced with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. - -**Step 5** -- Session state written: `REQ_001` entry with `acknowledged: false`. +**Step 4** -- Session state written: `REQ_001` entry with `acknowledged: false`. No visible output from this step. -**Step 6** -- User asked to acknowledge. User says "yes". Session updated: `acknowledged: true`. +**Step 5** -- Change Document emitted with the tables above. Summary: 2 must update, 2 review needed, 3 no change needed, 0 code files. Recommendation: proceed. Turn ends after emission. Session state holds `acknowledged: false`. The user edits `.pharaoh/session.json` directly to flip the flag before invoking an enforcing-mode authoring skill. diff --git a/skills/pharaoh-decide/SKILL.md b/skills/pharaoh-decide/SKILL.md index b402ae5..0e0ef0c 100644 --- a/skills/pharaoh-decide/SKILL.md +++ b/skills/pharaoh-decide/SKILL.md @@ -3,6 +3,17 @@ name: pharaoh-decide description: "Use when recording a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements" --- +## Output invariant + +This skill's visible output MUST contain, in order: + +1. Confirmation line: `Decision written to ` +2. Optional follow-up suggestion (Step 7 content) + +The confirmation is mandatory. The suggestion is optional and is suppressed when the skill is called by `pharaoh:spec` (per existing Step 7 logic). Returning only the suggestion without the confirmation line is a REGRESSION. + +Session-state update is internal bookkeeping and runs before the visible output. + # pharaoh-decide Record design decisions as traceable sphinx-needs `decision` directives. Each decision captures the chosen option, rejected alternatives, rationale, and explicit links to the requirements or specifications it affects. This skill ensures every decision has proper `decided_by`, `alternatives`, and `rationale` fields. @@ -175,7 +186,9 @@ Decisions --- -### Step 6: Update Session State +### Step 6: Update Session State (internal) + +This step is internal bookkeeping. It MUST run before any visible output is emitted in Step 7. Do not print anything in this step. After successfully writing the decision: @@ -203,15 +216,19 @@ After successfully writing the decision: #### Standalone invocation -After writing the decision, suggest the next step: +Emit the visible turn output. The FIRST line MUST be the written-confirmation. The follow-up suggestion is appended after a blank line: ``` +Decision written to + Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` +Substitute `` with the generated ID from Step 3 and `` with the absolute or repo-relative path to the file written in Step 4 / Step 5. The confirmation line MUST appear even if the follow-up suggestion is suppressed for any reason. + #### Called by `pharaoh:spec` -Return the decision ID silently. Do not print follow-up suggestions. The calling skill manages the workflow. +Return the decision ID silently. Do not print follow-up suggestions. Do not print the written-confirmation line. The calling skill manages the workflow. --- @@ -302,9 +319,11 @@ Why was PostgreSQL chosen over the alternatives? **Step 6** -- Session state updated: `DEC_003.authored = true`. -**Step 7** -- Follow-up: +**Step 7** -- Visible output: ``` +Decision DEC_003 written to docs/decisions.rst + Next step: Run pharaoh:req-review to validate the decision against its linked requirements. ``` diff --git a/skills/pharaoh-mece/SKILL.md b/skills/pharaoh-mece/SKILL.md index 6ee3adb..957a631 100644 --- a/skills/pharaoh-mece/SKILL.md +++ b/skills/pharaoh-mece/SKILL.md @@ -3,6 +3,17 @@ name: pharaoh-mece description: "Use when checking for gaps, redundancies, and inconsistencies in sphinx-needs requirements, or validating traceability completeness" --- +## Output invariant + +This skill's visible output is the full **MECE Analysis Report** as defined in Step 9. The report is mandatory -- every invocation MUST emit the complete report with all sections (omit only sections with no findings, but always emit the Summary section). The session-state update in Step 8 is internal bookkeeping and MUST NOT replace the report in the output. + +Failure modes: +- Returning a one-paragraph executive summary instead of the table-formatted report -> REGRESSION. Emit the full report. +- Returning only the session-state confirmation -> REGRESSION. Emit the full report. +- Returning the report and asking the user a follow-up question instead of finishing -> REGRESSION. End the turn after the report. + +Non-interactive callers (`claude -p`, CI, batch) cannot reach the report past a follow-up prompt. The skill MUST be self-terminating. + # pharaoh:mece -- MECE Analysis Analyze a sphinx-needs project for structural completeness and consistency. @@ -300,11 +311,33 @@ Schema validation: Skipped (ubc CLI not available) --- -### Step 8: Present MECE report +### Step 8: Update session state (internal) + +This step is internal bookkeeping. Perform it silently before emitting the +report in Step 9 -- do not narrate it in the visible output. + +Update the session state file (`.pharaoh/session.json`) as described in +`skills/shared/strictness.md`: + +1. Read the current `.pharaoh/session.json` (or create the default structure + if it does not exist). +2. Set `global.mece_checked` to `true`. +3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. +4. Set `updated` to the current ISO 8601 timestamp. +5. Write the file back. + +The interaction with `require_mece_on_release` is described in Section 3 +(Strictness Behavior). + +--- + +### Step 9: Emit the MECE report (visible output) -Compile all findings into a single structured report. Use the format below -exactly. Omit sections that have no findings (but mention "None found" in the -summary counts). +This is the skill's visible output. Compile all findings into a single +structured report. Use the format below exactly. Omit sections that have no +findings (but mention "None found" in the summary counts). Always emit the +Summary section. After emitting the report, end the turn -- do not ask the +user follow-up questions. ``` ## MECE Analysis Report @@ -376,22 +409,7 @@ summary counts). - **critical**: More than 5 errors, or any category has more errors than valid needs of that type. The traceability structure has significant problems. ---- - -### Step 9: Update session state - -After presenting the report, update the session state file -(`.pharaoh/session.json`) as described in `skills/shared/strictness.md`: - -1. Read the current `.pharaoh/session.json` (or create the default structure - if it does not exist). -2. Set `global.mece_checked` to `true`. -3. Set `global.mece_timestamp` to the current ISO 8601 timestamp. -4. Set `updated` to the current ISO 8601 timestamp. -5. Write the file back. - -This records that MECE analysis was performed, which satisfies the -`require_mece_on_release` gate if `pharaoh.toml` has it enabled. +Emit the report and end the turn. --- diff --git a/skills/pharaoh-release/SKILL.md b/skills/pharaoh-release/SKILL.md index c42e4a8..6dd4a8f 100644 --- a/skills/pharaoh-release/SKILL.md +++ b/skills/pharaoh-release/SKILL.md @@ -3,6 +3,16 @@ name: pharaoh-release description: "Use when preparing a release, generating changelogs from requirements, or summarizing requirement changes for version management" --- +## Output invariant + +This skill's visible output is the full release report (changelog plus release summary) as defined in Step 7. The report is mandatory. Every invocation MUST emit the complete report. The session-state update is internal bookkeeping. The skill is self-terminating. No interactive prompt at the end of the turn. + +Failure modes: +- Ending the turn with a "save these release artifacts?" prompt instead of the report -> REGRESSION. Emit the full report and end the turn. +- Returning a brief summary instead of the full changelog and release summary -> REGRESSION. + +File-save behaviour is controlled by an input flag (`save_artifacts`), not an interactive prompt. See Step 7.2 below. + # pharaoh-release Generate release artifacts from sphinx-needs changes. This skill identifies which @@ -19,6 +29,10 @@ analysis). - Producing traceability coverage metrics for compliance or audit documentation. - Generating release notes that include requirement impact chains. +## Input + +- **`save_artifacts`** (optional, default `none`): one of `none` | `changelog` | `release_notes` | `both`. Controls whether the skill writes the rendered changelog/release-notes artifacts to disk in addition to emitting them in the turn output. Pass explicitly when calling non-interactively. Defaults to `none` so a bare invocation never silently writes files. + ## Prerequisites This skill has workflow gates. Follow the strictness check in Step 1 before @@ -438,87 +452,83 @@ Code files referencing needs: ### Step 7: Output and Next Steps -#### 7a. Present changelog to user +The sub-steps below run in this fixed order: session-state update first +(internal bookkeeping), then artifact writes per the `save_artifacts` input +flag (silent side effects), and finally the visible release report. The +report is the LAST instruction in the skill so it is the last visible turn +content. The skill MUST end the turn after the report. No interactive +prompts. -Display the complete changelog (from Step 5) and release summary (from Step 6) -to the user in a single output. +#### 7.1. Update session state (internal) -#### 7b. Offer to write to file +Run this BEFORE emitting any visible output. Update `.pharaoh/session.json`: -After presenting the output, ask the user: +1. Read the current session state (or create the initial structure). +2. Set `global.last_release` to the current ISO 8601 timestamp. +3. Set `updated` to the current ISO 8601 timestamp. +4. Write the updated JSON back to `.pharaoh/session.json`. -``` -Would you like to save these release artifacts? +This is internal bookkeeping. It MUST NOT produce any visible turn output. - 1. Write changelog to CHANGELOG.md (append at top) - 2. Write full release notes to docs/releases/.md - 3. Write both - 4. Do not write any files +#### 7.2. Write artifacts per `save_artifacts` input flag -Choose an option: [1/2/3/4] -``` +Branch on the `save_artifacts` input value (default `none`): -**Option 1: Append to CHANGELOG.md** +- `none`: do nothing. The output was already presented. +- `changelog`: append the changelog entry to `CHANGELOG.md` (Option 1 logic below). +- `release_notes`: write `docs/releases/.md` (Option 2 logic below). +- `both`: execute both branches in order. + +Do NOT ask the user. Callers that want to choose interactively pass the flag explicitly. + +**`changelog` branch (append to CHANGELOG.md):** 1. Check if `CHANGELOG.md` exists in the workspace root. -2. If it exists, read its current content. Insert the new changelog entry at the - top of the file, after any existing header (e.g., after a `# Changelog` line). -3. If it does not exist, create it with a `# Changelog` header followed by the - new entry. -4. Show the user what will be written and confirm before writing. +2. If it exists, read its current content. Insert the new changelog entry at the top, after any existing header (e.g. after a `# Changelog` line). +3. If it does not exist, create it with a `# Changelog` header followed by the new entry. -**Option 2: Write to docs/releases/** +**`release_notes` branch (write `docs/releases/.md`):** 1. Create the `docs/releases/` directory if it does not exist. -2. Write the full release notes (changelog + release summary) to - `docs/releases/.md`. -3. Show the user what will be written and confirm before writing. - -**Option 3: Both** +2. Write the full release notes (changelog plus release summary) to `docs/releases/.md`. -Execute both Option 1 and Option 2. +**`both` branch:** execute both branches in order. -**Option 4: No files** +#### 7.3. Emit the release report (final visible output) -Do nothing. The output was already presented on screen. +This sub-step is the LAST instruction in the skill and produces the LAST +visible turn content. After emitting the report, end the turn. Do not ask +follow-up questions. -#### 7c. Suggest git tag +Display the complete changelog (from Step 5) and release summary (from +Step 6) to the user in a single output. Append the tag suggestion below as +the final footer line of the report. -After file output is handled, suggest tagging: +**Tag suggestion footer (append at the end of the report):** ``` Suggested next step: git tag -a -m "Release " -Create this tag now? [yes/no] +(Run the tag command manually if desired. The skill does not run git tag +automatically.) ``` -If the user confirms, run the `git tag` command. Do **not** push the tag. If the -user wants to push, they must explicitly request it. - -If the user declines, do nothing. - -#### 7d. Update session state - -After the release process completes successfully (regardless of whether files were -written), update `.pharaoh/session.json`: - -1. Read the current session state (or create the initial structure). -2. Set `global.last_release` to the current ISO 8601 timestamp. -3. Set `updated` to the current ISO 8601 timestamp. -4. Write the updated JSON back to `.pharaoh/session.json`. +The skill MUST NOT execute `git tag` itself. The skill MUST NOT ask the +user whether to create the tag. The footer is informational only. --- ## Key Constraints -1. **Never auto-tag or auto-push without user confirmation.** The `git tag` and - `git push` commands must always be explicitly confirmed by the user. Never run - them silently. +1. **Never run `git tag` or `git push`.** The skill MUST NOT execute either + command. The release report includes a tag suggestion as a footer line so the + user can run it manually. The skill MUST NOT prompt the user about tagging. -2. **Never overwrite files without asking.** Before writing to `CHANGELOG.md` or - any release notes file, show the user what will be written and get explicit - confirmation. If the file already exists, show how it will be modified. +2. **File writes are gated by the `save_artifacts` input flag.** The skill MUST + NOT prompt the user before writing `CHANGELOG.md` or `docs/releases/.md`. + The flag is the contract. Default `none` means no files are written. When the + flag selects a write branch, perform the write without asking. 3. **Include traceability metrics for safety-critical audit trails.** The release summary must always include the needs inventory and traceability coverage diff --git a/skills/pharaoh-req-from-code/SKILL.md b/skills/pharaoh-req-from-code/SKILL.md index 0dffceb..19671a4 100644 --- a/skills/pharaoh-req-from-code/SKILL.md +++ b/skills/pharaoh-req-from-code/SKILL.md @@ -40,11 +40,15 @@ Known prior failures this rule catches: A clean behavioral shall with zero backticks and one `:source_doc:` is preferred over a code-narration shall with ten backticks. -### Rule 3 — `:source_doc:` must point at the implementing source code file +### Rule 3 -- `:source_doc:` emission is tailoring-driven -Every emitted CREQ carries `:source_doc:` pointing at a real source file — typically `.py`, `.rs`, `.ts`, `.go`, `.c`, `.cpp`, `.java` under the project's source tree (e.g. `src//csv/csv2needs.py`). Pointing `:source_doc:` at the spec RST file itself or at a prose feature doc is a validation failure — the spec RST is where the requirement lives, not where the behavior is implemented. +If the project's `/artefact-catalog.yaml` declares `source_doc` in `optional_fields` or `required_fields` for the directive's type (`target_level`), emit it pointing at the implementing source code file. If the project does NOT declare `source_doc` for the type, do NOT emit it. -When a CREQ's behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. +Rationale: emitting undeclared fields produces sphinx-build warnings under `-W` and breaks the build. Section 8 of #13 wired `pharaoh-setup` to populate the catalog from `[needs.fields.X]` declarations. This skill MUST honour the catalog on output. + +When the project declares `source_doc` and the CREQ behavior spans multiple source files, pick the file that owns the primary observable (usually the converter module, not a CLI dispatcher). `pharaoh-req-code-grounding-check` axis #8 (`source_doc_resolves`) fails if the cited file is the spec RST or missing entirely. + +When the project does NOT declare `source_doc`, code grounding moves to a backref comment in the source file via `pharaoh-req-codelink-annotate` (mode: backref). The CREQ stays clean of paths. ### Rule 4 — CREQ adds constraint beyond the parent feat @@ -68,9 +72,16 @@ Expected floor per typical connector module (200-500 LOC, 3-8 exception classes, Each emitted block's body has exactly one `shall` clause. Zero intra-clause conjunctions joining modal-verb phrases (`, and shall` / ` and shall` / ` or raise` / `, or ` — all splits). Multiple observable behaviors = multiple CREQs. Intra-clause conjunctions are a hard fail regardless of behavioral quality; split the block before returning. -### Rule 6 — `:verification:` field is required +### Rule 6 -- `:verification:` emission is tailoring-driven + +`verification` in this skill names whichever of two tailoring slots the project declares it as: + +1. **As a link** in `/ubproject.toml` under `[[needs.extra_links]]` with name `verification` (or a project-renamed equivalent declared in `pharaoh.toml` under `[skill.req_from_code.verification_link_name]`). When declared, emit `:verification: tc__TBD` (or the project's declared placeholder convention). +2. **As a field** in `/artefact-catalog.yaml` under `optional_fields` or `required_fields` for the directive's type. When declared, emit `:verification: `. -Every emitted CREQ carries `:verification:` with at minimum the placeholder `tc__TBD`. Absence is a schema failure. If the project uses a different link name for the req→test relation (`verifies`, `covered_by`), declare it in `[[needs.extra_links]]`; the default placeholder stays required. +If neither slot declares `verification` for the directive's type, do NOT emit `:verification:`. The req-to-test relation is then declared elsewhere. For example, `pharaoh-vplan-draft` backlinks via `:verifies:` from the test side. + +Resolution order: link declaration in `ubproject.toml` takes precedence over field declaration in the catalog. A project declaring both is over-specified. Warn but emit the link form. ### Rule 7 — Backticks are for code / protocol tokens only @@ -106,7 +117,7 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe ## Atomicity - (a) Indivisible — one file in → N reqs out. No I/O beyond file read + optional Papyrus query/write + req emit. Emits in exactly one representation per call (`rst` OR `codelinks_comment`). -- (b) Input: `{file_path, target_level, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. +- (b) Input: `{file_path, target_level, tailoring_path, shared_context_path?, papyrus_workspace?, reporter_id, parent_feat_ids?, emit_override?, codelinks_project_name?, on_missing_config?, allowed_ids?, split_strategy?}`. Output: single JSON object `{"reqs": [{"id", "title", "type", "body", "source_doc", "satisfies", "verification", "raw_rst"}, ...]}` for `emit=rst`, or `{"codelinks": [str, ...]}` for `emit=codelinks_comment`. On missing tailoring with `on_missing_config=prompt`: single JSON object `{status: "needs_confirmation", proposal}`. - (c) Reward: language-parametric fixture — given `test_fixture.` (`.py` / `.cpp` / `.rs` / `.ts`) containing exactly 3 named symbols (`FooBar`, `BazQux`, `Quux`), emitted reqs must mention all 3 by canonical name. Directive name must equal `target_level`. If `parent_feat_ids` is non-empty, every emitted block MUST contain `:satisfies: , , ...` with all parents comma-joined. - (d) Reusable across reverse-engineering workflows, spec drafting, standalone CI "are there reqs for this code?" gates. - (e) Composable — strictly one phase. Never invokes `pharaoh-arch-draft`, `pharaoh-fmea`, `pharaoh-plan`. @@ -115,6 +126,7 @@ If `on_missing_config == "prompt"` (default) AND tailoring is missing (no `targe - `file_path`: absolute path to the source file (any language). - `target_level`: requirement artefact directive name as declared in the consumer project's `ubproject.toml` (e.g. `"comp_req"`, `"impl"`, `"spec"`). ID prefix is `target_level` + `__` unless `[[needs.types]].prefix` overrides. +- `tailoring_path`: absolute path to the project's `.pharaoh/project/` directory. Resolved per `skills/shared/tailoring-access.md`. Used by Step 1 to read `artefact-catalog.yaml` and the project's `ubproject.toml` once and cache the per-`target_level` declarations of `source_doc` and `verification` consumed by Rules 3 and 6. - `shared_context_path` (optional): companion source file read by all agents in the fan-out (e.g. `common.cpp`). Read but NOT reverse-engineered. - `papyrus_workspace` (optional): path to `.papyrus/` for canonical-term coordination. Absent → no-memory mode (skip Steps 1 and 3). - `reporter_id`: short identifier for this agent (e.g. `req-from-code:csv2needs.py`). @@ -145,6 +157,8 @@ A single JSON object. The top-level key names the emit mode: `reqs` for `emit=rs } ``` +Both `source_doc` and `verification` are conditional emit. `source_doc` MUST be omitted (from both the JSON object and the `raw_rst` block) if the project's `artefact-catalog.yaml` does not declare `source_doc` for the directive's type. `verification` MUST be omitted if neither `[[needs.extra_links]]` in `ubproject.toml` nor the catalog declares `verification` for the type. See Rules 3 and 6. + Field semantics: - `id` — ``. `` defaults to `target_level` (`comp_req` → `comp_req__foo_01`). If `[[needs.types]].prefix` declares `"CREQ_"`, use `CREQ_foo_01`. @@ -201,7 +215,7 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i 1. `raw_rst` matches Stage 1 + Stage 2 — block is well-formed. 2. `raw_rst` directive name equals `type` and equals input `target_level`. -3. Stage 2 on `raw_rst` yields at least `id`, `status`, `source_doc`, and `verification`; values match the corresponding top-level fields. +3. Stage 2 on `raw_rst` yields at least `id` and `status`. Whichever of `source_doc` and `verification` the project's tailoring declares for the directive's type MUST also appear. The other MUST NOT. 4. If `parent_feat_ids` was provided: `satisfies` field is non-empty and lists every parent id; `raw_rst` `:satisfies:` (or tailored child→parent link name) value matches. 5. Every option in `raw_rst` is either declared in `ubproject.toml` `[[needs.types]]`, a built-in sphinx-needs option, or a Pharaoh convention option. Reject unknown names (catches typos like `subsatisfies`). 6. If `allowed_ids` was provided: every `reqs[*].id` is a member of `allowed_ids`. @@ -212,6 +226,8 @@ Identifies one directive block bounded by the next `.. ` at column 0 or end of i ### Step 1: Query Papyrus for canonical terms BEFORE naming +Resolve `tailoring_path` per `skills/shared/tailoring-access.md`. Read `/artefact-catalog.yaml` and `/ubproject.toml` once. Cache the per-`target_level` declarations of `source_doc` (field) and `verification` (link or field) for use by Rules 3 and 6. + Only applies if `papyrus_workspace` is provided. For each type / function / concept you may name in a req: 1. Form a short semantic query ("what do we call the subsystem that supervises other monitors"). @@ -264,14 +280,16 @@ For each boundary-observable behavior (per Rule 5 enumeration): - `:id: _` — `` resolved in Step 4. File basename (stem, snake_case) as disambiguator. Examples: `comp_req__csv2needs_01`, `CREQ_csv2needs_01`. - `:status: draft`. - `:satisfies: , ...` — iff `parent_feat_ids` non-empty. All parents comma-joined. If `[[needs.extra_links]]` declares a different outgoing name (e.g. `realizes`), use that instead. -- `:source_doc: ` — per Rule 3. -- `:verification: tc__TBD` — per Rule 6. +- `:source_doc: ` -- emit only if the project's `artefact-catalog.yaml` declares `source_doc` for `target_level` per Rule 3. +- `:verification: tc__TBD` -- emit only if `[[needs.extra_links]]` in `ubproject.toml` declares `verification` (or the catalog declares it as a field) for `target_level` per Rule 6. Use the project's declared placeholder when one is configured. - Body — single shall clause, component subject (Rule 1), no internals (Rule 2), adds constraint (Rule 4), atomicity + no conjunctions (Atomicity rule above). Canonical names from Steps 1/3. ### Step 5b: Emit — `codelinks_comment` mode For each behavior, emit one line that sphinx-codelinks' oneline parser would read back into a need equivalent to what `rst` mode would produce. Follow tailored `needs_fields` order and escape rules. Do NOT include the language comment prefix — that is `pharaoh-req-codelink-annotate`'s concern. +Rules 3 and 6 do not gate codelinks-mode output. The `:source_doc:` and `:verification:` RST options have no counterpart in the one-line comment string. Code grounding is implicit (the comment lives in the source file itself) and the verification relation is carried via the tailored `needs_fields` (e.g. as a `links` slot or omitted entirely). Project tailoring of which fields appear in the comment is governed by `[codelinks.projects..analyse.oneline_comment_style]`, not by `artefact-catalog.yaml` or `[[needs.extra_links]]`. + The `links` field renders as `[, ...]` when `parent_feat_ids` non-empty, else `[]` (or omitted if tailored `default = []`). The body shall-clause does NOT fit on a one-line comment — implied by the title and lost in this mode. For full shall-clause text use `emit="rst"`. Target: 1-5 reqs per file (per split_strategy). Fewer than 1 only if the file has no observable behavior; more than 5 suggests over-decomposition.