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 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.