diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 7876b29..6f35490 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": "0.1.0", + "version": "0.2.0", "author": { "name": "useblocks" }, diff --git a/.github/agents/pharaoh.activity-diagram-draft.agent.md b/.github/agents/pharaoh.activity-diagram-draft.agent.md index cb40cfe..36bba5e 100644 --- a/.github/agents/pharaoh.activity-diagram-draft.agent.md +++ b/.github/agents/pharaoh.activity-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one activity diagram showing control flow (actions, decisions, forks/joins, swimlanes) for one procedure or algorithm. +description: Use when drafting one activity diagram showing control flow (actions, decisions, forks/joins, swimlanes) for one procedure or algorithm. Typical ASPICE usage — SWE.3 Software Detailed Design. Renderer tailored via `pharaoh.toml`. Does NOT emit other diagram kinds. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.activity-diagram-draft -Use when drafting one activity diagram showing control flow (actions, decisions, forks/joins, swimlanes) for one procedure or algorithm. +Use when drafting one activity diagram showing control flow (actions, decisions, forks/joins, swimlanes) for one procedure or algorithm. Typical ASPICE usage — SWE.3 Software Detailed Design. Renderer tailored via `pharaoh.toml`. Does NOT emit other diagram kinds. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-activity-diagram-draft/SKILL.md`](../../skills/pharaoh-activity-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.api-coverage-check.agent.md b/.github/agents/pharaoh.api-coverage-check.agent.md index f76eb9c..0fac840 100644 --- a/.github/agents/pharaoh.api-coverage-check.agent.md +++ b/.github/agents/pharaoh.api-coverage-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify that every public symbol and every raise-site exception in a source file is covered by at least one need in needs.json. Reverse direction of pharaoh-req-from-code — language-parametric via the shared regex table; emits per-symbol and per-raise-site coverage plus a ratio against a tailored threshold. +description: Use when verifying that a source file is covered by the need catalogue on two axes — (1) at least one CREQ declares the file as its `:source_doc:`, and (2) every project-defined exception class raised in the file is named by some CREQ's title or content. Exception classes not defined in the project source tree (stdlib, third-party deps) are reported as `external` and do not fail the axis. Classifies non-behavioral files (constants, type aliases, bare re-exports) as skipped. Language-parametric via the shared regex table in `skills/shared/public-symbol-patterns.md` (python / rust / typescript / go / c / cpp / java). Single mechanical structural check. handoffs: [] --- # @pharaoh.api-coverage-check -Verify that every public symbol and every raise-site exception in a source file is covered by at least one need in `needs.json`. Reverse direction of `pharaoh-req-from-code` — language-parametric via the shared regex table in `skills/shared/public-symbol-patterns.md`; emits per-symbol and per-raise-site coverage plus a ratio against a tailored threshold. +Use when verifying that a source file is covered by the need catalogue on two axes — (1) at least one CREQ declares the file as its `:source_doc:`, and (2) every project-defined exception class raised in the file is named by some CREQ's title or content. Exception classes not defined in the project source tree (stdlib, third-party deps) are reported as `external` and do not fail the axis. Classifies non-behavioral files (constants, type aliases, bare re-exports) as skipped. Language-parametric via the shared regex table in `skills/shared/public-symbol-patterns.md` (python / rust / typescript / go / c / cpp / java). Single mechanical structural check. -See [`skills/pharaoh-api-coverage-check/SKILL.md`](../../skills/pharaoh-api-coverage-check/SKILL.md) for the full atomic specification — inputs, outputs, per-step process, failure modes, and composition patterns. +See [`skills/pharaoh-api-coverage-check/SKILL.md`](../../skills/pharaoh-api-coverage-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.arch-draft.agent.md b/.github/agents/pharaoh.arch-draft.agent.md index 36d408c..ccb3362 100644 --- a/.github/agents/pharaoh.arch-draft.agent.md +++ b/.github/agents/pharaoh.arch-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Draft a single sphinx-needs architecture element from one parent requirement. +description: Use when drafting a single sphinx-needs architecture element from one parent requirement. The artefact type is parameterised via `target_level` (any catalog-declared architecture type — e.g. `arch`, `swarch`, `sys-arch`, `module`, `component`, `interface`). Emits an RST directive block linking back to the parent via `:satisfies:`. handoffs: [] --- # @pharaoh.arch-draft -Draft a single sphinx-needs architecture element from one parent requirement. +Use when drafting a single sphinx-needs architecture element from one parent requirement. The artefact type is parameterised via `target_level` (any catalog-declared architecture type — e.g. `arch`, `swarch`, `sys-arch`, `module`, `component`, `interface`). Emits an RST directive block linking back to the parent via `:satisfies:`. See [`skills/pharaoh-arch-draft/SKILL.md`](../../skills/pharaoh-arch-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.arch-review.agent.md b/.github/agents/pharaoh.arch-review.agent.md index c46b8fb..ac6afb0 100644 --- a/.github/agents/pharaoh.arch-review.agent.md +++ b/.github/agents/pharaoh.arch-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single architecture element against ISO 26262-8 §6 axes. +description: Use when auditing a single architecture element against the 10 ISO 26262-8 §6 axes plus arch-specific axes (traceability back to requirement). Emits structured findings JSON. handoffs: [] --- # @pharaoh.arch-review -Audit a single architecture element against ISO 26262-8 §6 axes. +Use when auditing a single architecture element against the 10 ISO 26262-8 §6 axes plus arch-specific axes (traceability back to requirement). Emits structured findings JSON. See [`skills/pharaoh-arch-review/SKILL.md`](../../skills/pharaoh-arch-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.audit-fanout.agent.md b/.github/agents/pharaoh.audit-fanout.agent.md index e809101..c314f96 100644 --- a/.github/agents/pharaoh.audit-fanout.agent.md +++ b/.github/agents/pharaoh.audit-fanout.agent.md @@ -1,10 +1,10 @@ --- -description: Run a full project audit in parallel across atomic audit skills, sharing findings via Papyrus. +description: Use when running a full project audit in parallel by dispatching 5 atomic audit skills, each writing findings to a shared Papyrus workspace via pharaoh-finding-record for automatic deduplication. Emits the aggregated deduplicated findings list. handoffs: [] --- # @pharaoh.audit-fanout -Run a full project audit in parallel across atomic audit skills, sharing findings via Papyrus. +Use when running a full project audit in parallel by dispatching 5 atomic audit skills, each writing findings to a shared Papyrus workspace via pharaoh-finding-record for automatic deduplication. Emits the aggregated deduplicated findings list. See [`skills/pharaoh-audit-fanout/SKILL.md`](../../skills/pharaoh-audit-fanout/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.author.agent.md b/.github/agents/pharaoh.author.agent.md new file mode 100644 index 0000000..e1a8e7c --- /dev/null +++ b/.github/agents/pharaoh.author.agent.md @@ -0,0 +1,19 @@ +--- +description: Use when authoring or modifying a single sphinx-needs artefact (requirement, architecture element, test case, decision) by routing to the matching atomic drafting skill based on the project's artefact catalog. Returns the drafted RST directive with an ID, file placement suggestion, and parent link. +handoffs: + - label: Verify Authored Need + agent: pharaoh.verify + prompt: Check that the authored artefact addresses the substance of its parent + - label: Review Drafted Requirement + agent: pharaoh.req-review + prompt: Audit the drafted requirement against the ISO 26262 §6 axes + - label: Trace the Authored Need + agent: pharaoh.trace + prompt: Trace the new artefact through all link types +--- + +# @pharaoh.author + +Use when authoring or modifying a single sphinx-needs artefact (requirement, architecture element, test case, decision) by routing to the matching atomic drafting skill based on the project's artefact catalog. Returns the drafted RST directive with an ID, file placement suggestion, and parent link. + +See [`skills/pharaoh-author/SKILL.md`](../../skills/pharaoh-author/SKILL.md) for the full atomic specification — inputs, dispatch table, and composition patterns. diff --git a/.github/agents/pharaoh.block-diagram-draft.agent.md b/.github/agents/pharaoh.block-diagram-draft.agent.md index 0436607..99e72ac 100644 --- a/.github/agents/pharaoh.block-diagram-draft.agent.md +++ b/.github/agents/pharaoh.block-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one SysML-style block diagram — Block Definition Diagram (BDD) showing block structure and composition, or Internal Block Diagram (IBD) showing ports, flows, and part interconnections. +description: Use when drafting one SysML-style block diagram — Block Definition Diagram (BDD) showing block structure and composition, or Internal Block Diagram (IBD) showing ports, flows, and part interconnections. Typical ASPICE usage — SYS.2/SYS.3 for system-level architecture, and SWE.2 for software architecture on SysML-heavy projects. Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.block-diagram-draft -Use when drafting one SysML-style block diagram — Block Definition Diagram (BDD) showing block structure and composition, or Internal Block Diagram (IBD) showing ports, flows, and part interconnections. +Use when drafting one SysML-style block diagram — Block Definition Diagram (BDD) showing block structure and composition, or Internal Block Diagram (IBD) showing ports, flows, and part interconnections. Typical ASPICE usage — SYS.2/SYS.3 for system-level architecture, and SWE.2 for software architecture on SysML-heavy projects. Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-block-diagram-draft/SKILL.md`](../../skills/pharaoh-block-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.bootstrap.agent.md b/.github/agents/pharaoh.bootstrap.agent.md index bca421a..213249a 100644 --- a/.github/agents/pharaoh.bootstrap.agent.md +++ b/.github/agents/pharaoh.bootstrap.agent.md @@ -1,5 +1,5 @@ --- -description: Inject minimum sphinx-needs configuration into an existing Sphinx project so sphinx-build produces a valid needs.json. +description: Use when a Sphinx project has no sphinx-needs configured and you need minimum viable scaffolding — adding the extension and declaring need types — so that sphinx-build produces a valid needs.json for downstream Pharaoh skills. handoffs: - label: Detect and scaffold Pharaoh agent: pharaoh.setup @@ -8,6 +8,6 @@ handoffs: # @pharaoh.bootstrap -Inject the minimum sphinx-needs configuration — extension entry, need types, optional extra links — into an existing Sphinx project that does not yet have sphinx-needs configured. Does not seed RST content, does not build, does not write `pharaoh.toml`. +Use when a Sphinx project has no sphinx-needs configured and you need minimum viable scaffolding — adding the extension and declaring need types — so that sphinx-build produces a valid needs.json for downstream Pharaoh skills. See [`skills/pharaoh-bootstrap/SKILL.md`](../../skills/pharaoh-bootstrap/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.change.agent.md b/.github/agents/pharaoh.change.agent.md index 1ed8190..9ffa829 100644 --- a/.github/agents/pharaoh.change.agent.md +++ b/.github/agents/pharaoh.change.agent.md @@ -1,6 +1,12 @@ --- -description: Analyze the impact of changing a requirement, specification, or any sphinx-needs item. Traces through all link types and codelinks to produce a Change Document. +description: Use when analyzing the impact of changing a requirement, specification, or any sphinx-needs item, including traceability to code via codelinks handoffs: + - label: Author the affected needs + agent: pharaoh.author + prompt: Author the needs flagged in this change analysis + - label: Verify the affected needs + agent: pharaoh.verify + prompt: Verify the authored needs against their parents and review axes - label: MECE Check agent: pharaoh.mece prompt: Check the affected area for gaps and redundancies diff --git a/.github/agents/pharaoh.class-diagram-draft.agent.md b/.github/agents/pharaoh.class-diagram-draft.agent.md index 7eef840..5911999 100644 --- a/.github/agents/pharaoh.class-diagram-draft.agent.md +++ b/.github/agents/pharaoh.class-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one class diagram showing a bounded set of types/entities with their fields, methods, and relationships (inheritance, composition, aggregation, association). +description: Use when drafting one class diagram showing a bounded set of types/entities with their fields, methods, and relationships (inheritance, composition, aggregation, association). Renderer tailored via `pharaoh.toml`. Does NOT emit component, sequence, or state diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.class-diagram-draft -Use when drafting one class diagram showing a bounded set of types/entities with their fields, methods, and relationships (inheritance, composition, aggregation, association). +Use when drafting one class diagram showing a bounded set of types/entities with their fields, methods, and relationships (inheritance, composition, aggregation, association). Renderer tailored via `pharaoh.toml`. Does NOT emit component, sequence, or state diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-class-diagram-draft/SKILL.md`](../../skills/pharaoh-class-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.component-diagram-draft.agent.md b/.github/agents/pharaoh.component-diagram-draft.agent.md index b0bea11..e4bf231 100644 --- a/.github/agents/pharaoh.component-diagram-draft.agent.md +++ b/.github/agents/pharaoh.component-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one component-relationship diagram (nodes = sphinx-needs, edges = link relations) for a bounded scope — one feature, one module, one architectural view. +description: Use when drafting one component-relationship diagram (nodes = sphinx-needs, edges = link relations) for a bounded scope — one feature, one module, one architectural view. Renderer tailored via `pharaoh.toml`. Does NOT emit sequence, class, or state diagrams — those are separate skills. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.component-diagram-draft -Use when drafting one component-relationship diagram (nodes = sphinx-needs, edges = link relations) for a bounded scope — one feature, one module, one architectural view. +Use when drafting one component-relationship diagram (nodes = sphinx-needs, edges = link relations) for a bounded scope — one feature, one module, one architectural view. Renderer tailored via `pharaoh.toml`. Does NOT emit sequence, class, or state diagrams — those are separate skills. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-component-diagram-draft/SKILL.md`](../../skills/pharaoh-component-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.context-gather.agent.md b/.github/agents/pharaoh.context-gather.agent.md index 24926d3..8f21d82 100644 --- a/.github/agents/pharaoh.context-gather.agent.md +++ b/.github/agents/pharaoh.context-gather.agent.md @@ -1,10 +1,10 @@ --- -description: Retrieve rationale memories from a Papyrus workspace before authoring or review. +description: Use when retrieving rationale memories relevant to an authoring context from a Papyrus workspace, before invoking any draft or review skill. Returns a structured list of memories (memory_id, text, relevance_score). Does NOT draft, review, or modify artefacts. handoffs: [] --- # @pharaoh.context-gather -Retrieve rationale memories from a Papyrus workspace before authoring or review. +Use when retrieving rationale memories relevant to an authoring context from a Papyrus workspace, before invoking any draft or review skill. Returns a structured list of memories (memory_id, text, relevance_score). Does NOT draft, review, or modify artefacts. See [`skills/pharaoh-context-gather/SKILL.md`](../../skills/pharaoh-context-gather/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.coverage-gap.agent.md b/.github/agents/pharaoh.coverage-gap.agent.md index ef820ca..b95341d 100644 --- a/.github/agents/pharaoh.coverage-gap.agent.md +++ b/.github/agents/pharaoh.coverage-gap.agent.md @@ -1,10 +1,10 @@ --- -description: Detect one gap category (orphan / unverified / duplicate / contradictory / lifecycle) in a sphinx-needs corpus. +description: Use when detecting one gap category (orphan / unverified / duplicate / contradictory / lifecycle / ...) in a sphinx-needs corpus. Returns ordered list of needs falling into that gap. handoffs: [] --- # @pharaoh.coverage-gap -Detect one gap category (orphan / unverified / duplicate / contradictory / lifecycle) in a sphinx-needs corpus. +Use when detecting one gap category (orphan / unverified / duplicate / contradictory / lifecycle / ...) in a sphinx-needs corpus. Returns ordered list of needs falling into that gap. See [`skills/pharaoh-coverage-gap/SKILL.md`](../../skills/pharaoh-coverage-gap/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.decide.agent.md b/.github/agents/pharaoh.decide.agent.md index 2b6938e..4e942fb 100644 --- a/.github/agents/pharaoh.decide.agent.md +++ b/.github/agents/pharaoh.decide.agent.md @@ -1,5 +1,5 @@ --- -description: Record a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements. +description: Use when recording a design decision as a traceable sphinx-needs object with alternatives, rationale, and links to affected requirements handoffs: - label: Trace Decision agent: pharaoh.trace diff --git a/.github/agents/pharaoh.decision-record.agent.md b/.github/agents/pharaoh.decision-record.agent.md index 6b6b044..c7cccc6 100644 --- a/.github/agents/pharaoh.decision-record.agent.md +++ b/.github/agents/pharaoh.decision-record.agent.md @@ -1,10 +1,10 @@ --- -description: Record a canonical decision, fact, or preference in the shared Papyrus workspace with (type, canonical_name) dedup. +description: Use when recording a canonical decision, fact, or preference in the shared Papyrus workspace with automatic dedup on (type, canonical_name). Returns {action: wrote|duplicate, papyrus_id}. Generalizes pharaoh-finding-record beyond audit findings. handoffs: [] --- # @pharaoh.decision-record -Record a canonical decision, fact, or preference in the shared Papyrus workspace with (type, canonical_name) dedup. +Use when recording a canonical decision, fact, or preference in the shared Papyrus workspace with automatic dedup on (type, canonical_name). Returns {action: wrote|duplicate, papyrus_id}. Generalizes pharaoh-finding-record beyond audit findings. See [`skills/pharaoh-decision-record/SKILL.md`](../../skills/pharaoh-decision-record/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.decision-review.agent.md b/.github/agents/pharaoh.decision-review.agent.md index e644a61..35d3bb0 100644 --- a/.github/agents/pharaoh.decision-review.agent.md +++ b/.github/agents/pharaoh.decision-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single recorded decision against context/alternatives/consequences structure and traceability. +description: Use when auditing a single recorded decision (DR / ADR / design note) against the generic decision review axes in `shared/checklists/decision.md`. Checks context/alternatives/consequences structure, traceability to affected artefacts, rationale completeness. Emits structured findings JSON. handoffs: [] --- # @pharaoh.decision-review -Audit a single recorded decision against context/alternatives/consequences structure and traceability. +Use when auditing a single recorded decision (DR / ADR / design note) against the generic decision review axes in `shared/checklists/decision.md`. Checks context/alternatives/consequences structure, traceability to affected artefacts, rationale completeness. Emits structured findings JSON. -See [`skills/pharaoh-decision-review/SKILL.md`](../../skills/pharaoh-decision-review/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-decision-review/SKILL.md`](../../skills/pharaoh-decision-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.deployment-diagram-draft.agent.md b/.github/agents/pharaoh.deployment-diagram-draft.agent.md index 8e99724..b35581c 100644 --- a/.github/agents/pharaoh.deployment-diagram-draft.agent.md +++ b/.github/agents/pharaoh.deployment-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one deployment diagram showing physical nodes (ECUs, servers, boards), the software artefacts deployed on each, and communication channels (buses, networks). +description: Use when drafting one deployment diagram showing physical nodes (ECUs, servers, boards), the software artefacts deployed on each, and communication channels (buses, networks). Typical ASPICE usage — SYS.3 System Architectural Design; essential for automotive HW/SW allocation per ISO 26262 Part 5 (HW) and Part 6 (SW). Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.deployment-diagram-draft -Use when drafting one deployment diagram showing physical nodes (ECUs, servers, boards), the software artefacts deployed on each, and communication channels (buses, networks). +Use when drafting one deployment diagram showing physical nodes (ECUs, servers, boards), the software artefacts deployed on each, and communication channels (buses, networks). Typical ASPICE usage — SYS.3 System Architectural Design; essential for automotive HW/SW allocation per ISO 26262 Part 5 (HW) and Part 6 (SW). Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-deployment-diagram-draft/SKILL.md`](../../skills/pharaoh-deployment-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.diagram-lint.agent.md b/.github/agents/pharaoh.diagram-lint.agent.md index 4aa99bd..45014e4 100644 --- a/.github/agents/pharaoh.diagram-lint.agent.md +++ b/.github/agents/pharaoh.diagram-lint.agent.md @@ -1,5 +1,5 @@ --- -description: Walk a directory of RST files and check every `.. mermaid::` / `.. uml::` block against the real renderer parser (mmdc, plantuml). Catches silent parse failures that sphinx-build misses. +description: Use when running a terminal validation step over a directory of RST files to catch Mermaid / PlantUML parse failures that sphinx-build cannot detect. Extracts every `.. mermaid::` and `.. uml::` block and pipes it to the real renderer parser (mmdc / plantuml -checkonly). Returns structured findings. Does NOT modify the RST files. handoffs: - label: Aggregate into quality gate agent: pharaoh.quality-gate @@ -8,6 +8,6 @@ handoffs: # @pharaoh.diagram-lint -Walk a directory of RST files, extract every Mermaid / PlantUML block, and parse each block with the real renderer CLI (`mmdc -i tmp.mmd -o /dev/null`, `plantuml -checkonly`). Emits structured findings. Read-only — does not modify RST. When a renderer CLI is unavailable, degrades gracefully with a warning and install command. +Use when running a terminal validation step over a directory of RST files to catch Mermaid / PlantUML parse failures that sphinx-build cannot detect. Extracts every `.. mermaid::` and `.. uml::` block and pipes it to the real renderer parser (mmdc / plantuml -checkonly). Returns structured findings. Does NOT modify the RST files. See [`skills/pharaoh-diagram-lint/SKILL.md`](../../skills/pharaoh-diagram-lint/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.diagram-review.agent.md b/.github/agents/pharaoh.diagram-review.agent.md index 5b7d396..deb7695 100644 --- a/.github/agents/pharaoh.diagram-review.agent.md +++ b/.github/agents/pharaoh.diagram-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single diagram block (Mermaid or PlantUML) against generic + per-type axes. +description: Use when auditing a single diagram block (Mermaid or PlantUML) emitted by any diagram-emitting skill. Single review atom covering all diagram types — trace/caption/element-count/parser/required-elements checks plus LLM-judge axes for purpose clarity and granularity consistency. Per-type required-element checks dispatched based on `diagram_type` input. handoffs: [] --- # @pharaoh.diagram-review -Audit a single diagram block (Mermaid or PlantUML) against generic + per-type axes. +Use when auditing a single diagram block (Mermaid or PlantUML) emitted by any diagram-emitting skill. Single review atom covering all diagram types — trace/caption/element-count/parser/required-elements checks plus LLM-judge axes for purpose clarity and granularity consistency. Per-type required-element checks dispatched based on `diagram_type` input. -See [`skills/pharaoh-diagram-review/SKILL.md`](../../skills/pharaoh-diagram-review/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-diagram-review/SKILL.md`](../../skills/pharaoh-diagram-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.dispatch-signal-check.agent.md b/.github/agents/pharaoh.dispatch-signal-check.agent.md index 52d8c1e..60f80e4 100644 --- a/.github/agents/pharaoh.dispatch-signal-check.agent.md +++ b/.github/agents/pharaoh.dispatch-signal-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify declared execution_mode in plan.yaml matches observed artefacts in runs/. +description: Use when verifying that a plan's declared `execution_mode` matches observed subagent artefacts in `runs/`. Detects the "LLM-executor collapsed subagents into inline" failure class observed during dogfooding. One mechanical structural check. handoffs: [] --- # @pharaoh.dispatch-signal-check -Verify declared execution_mode in plan.yaml matches observed artefacts in runs/. +Use when verifying that a plan's declared `execution_mode` matches observed subagent artefacts in `runs/`. Detects the "LLM-executor collapsed subagents into inline" failure class observed during dogfooding. One mechanical structural check. -See [`skills/pharaoh-dispatch-signal-check/SKILL.md`](../../skills/pharaoh-dispatch-signal-check/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-dispatch-signal-check/SKILL.md`](../../skills/pharaoh-dispatch-signal-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.execute-plan.agent.md b/.github/agents/pharaoh.execute-plan.agent.md index 2c1cf46..2324022 100644 --- a/.github/agents/pharaoh.execute-plan.agent.md +++ b/.github/agents/pharaoh.execute-plan.agent.md @@ -1,10 +1,10 @@ --- -description: Use when executing a plan. +description: Use when executing a plan.yaml produced by pharaoh-write-plan. Reads the plan, runs each task (inline or via subagent dispatch), threads outputs between tasks per the ref grammar, validates outputs via pharaoh-output-validate, persists artefacts and report.yaml. Generic — the plan is the orchestrator, this skill is the engine. handoffs: [] --- # @pharaoh.execute-plan -Use when executing a plan. +Use when executing a plan.yaml produced by pharaoh-write-plan. Reads the plan, runs each task (inline or via subagent dispatch), threads outputs between tasks per the ref grammar, validates outputs via pharaoh-output-validate, persists artefacts and report.yaml. Generic — the plan is the orchestrator, this skill is the engine. See [`skills/pharaoh-execute-plan/SKILL.md`](../../skills/pharaoh-execute-plan/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.fault-tree-diagram-draft.agent.md b/.github/agents/pharaoh.fault-tree-diagram-draft.agent.md index e7ad53d..044a7ad 100644 --- a/.github/agents/pharaoh.fault-tree-diagram-draft.agent.md +++ b/.github/agents/pharaoh.fault-tree-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one fault tree for FTA (Fault Tree Analysis) — a top hazard event decomposed through AND/OR gates into basic events (component failures, random hardware faults, human errors). +description: Use when drafting one fault tree for FTA (Fault Tree Analysis) — a top hazard event decomposed through AND/OR gates into basic events (component failures, random hardware faults, human errors). Typical ISO 26262 usage — Part 3 Hazard Analysis & Risk Assessment, and Part 5 supporting hardware architectural metrics. Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.fault-tree-diagram-draft -Use when drafting one fault tree for FTA (Fault Tree Analysis) — a top hazard event decomposed through AND/OR gates into basic events (component failures, random hardware faults, human errors). +Use when drafting one fault tree for FTA (Fault Tree Analysis) — a top hazard event decomposed through AND/OR gates into basic events (component failures, random hardware faults, human errors). Typical ISO 26262 usage — Part 3 Hazard Analysis & Risk Assessment, and Part 5 supporting hardware architectural metrics. Renderer tailored via `pharaoh.toml`. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-fault-tree-diagram-draft/SKILL.md`](../../skills/pharaoh-fault-tree-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-balance.agent.md b/.github/agents/pharaoh.feat-balance.agent.md index 3829768..fd28551 100644 --- a/.github/agents/pharaoh.feat-balance.agent.md +++ b/.github/agents/pharaoh.feat-balance.agent.md @@ -1,10 +1,10 @@ --- -description: Use when a plan emitted by `pharaoh-write-plan` has completed its feature + comp_req emission and you need to check for granularity skew — features with too many reqs (under-decomposed feature model), too few (over-decomposed), fused sub-features (generic names like "utilities"), or redundancy (symmetric import/export pairs). +description: Use when a plan emitted by `pharaoh-write-plan` has completed its feature + comp_req emission and you need to check for granularity skew — features with too many reqs (under-decomposed feature model), too few (over-decomposed), fused sub-features (generic names like "utilities"), or redundancy (symmetric import/export pairs). Reports health and suggestions; does not mutate. handoffs: [] --- # @pharaoh.feat-balance -Use when a plan emitted by `pharaoh-write-plan` has completed its feature + comp_req emission and you need to check for granularity skew — features with too many reqs (under-decomposed feature model), too few (over-decomposed), fused sub-features (generic names like "utilities"), or redundancy (symmetric import/export pairs). +Use when a plan emitted by `pharaoh-write-plan` has completed its feature + comp_req emission and you need to check for granularity skew — features with too many reqs (under-decomposed feature model), too few (over-decomposed), fused sub-features (generic names like "utilities"), or redundancy (symmetric import/export pairs). Reports health and suggestions; does not mutate. See [`skills/pharaoh-feat-balance/SKILL.md`](../../skills/pharaoh-feat-balance/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-component-extract.agent.md b/.github/agents/pharaoh.feat-component-extract.agent.md index c29c37e..b3db215 100644 --- a/.github/agents/pharaoh.feat-component-extract.agent.md +++ b/.github/agents/pharaoh.feat-component-extract.agent.md @@ -1,10 +1,10 @@ --- -description: Use when reverse-engineering a feat and you need to derive a component composition diagram automatically from the feat + its source files. +description: Use when reverse-engineering a feat and you need to derive a component composition diagram automatically from the feat + its source files. Walks import edges between the listed files and emits a Mermaid or PlantUML diagram whose output shape is compatible with pharaoh-component-diagram-draft. Does NOT hand-author nodes or edges; extraction is rule-based. handoffs: [] --- # @pharaoh.feat-component-extract -Use when reverse-engineering a feat and you need to derive a component composition diagram automatically from the feat + its source files. +Use when reverse-engineering a feat and you need to derive a component composition diagram automatically from the feat + its source files. Walks import edges between the listed files and emits a Mermaid or PlantUML diagram whose output shape is compatible with pharaoh-component-diagram-draft. Does NOT hand-author nodes or edges; extraction is rule-based. See [`skills/pharaoh-feat-component-extract/SKILL.md`](../../skills/pharaoh-feat-component-extract/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-draft-from-docs.agent.md b/.github/agents/pharaoh.feat-draft-from-docs.agent.md index 63216a1..d2c4477 100644 --- a/.github/agents/pharaoh.feat-draft-from-docs.agent.md +++ b/.github/agents/pharaoh.feat-draft-from-docs.agent.md @@ -1,10 +1,10 @@ --- -description: Use when reading one or more existing documentation files (unstructured prose, README, tutorial) and emitting one or more feature-level RST directives (typed by `target_level`, default `feat`) that describe the user-facing capabilities documented in those files. +description: Use when reading one or more existing documentation files (unstructured prose, README, tutorial) and emitting one or more feature-level RST directives (typed by `target_level`, default `feat`) that describe the user-facing capabilities documented in those files. Does NOT read source code. Does NOT emit component requirements. Does NOT map features to files — that is `pharaoh-feat-file-map`. handoffs: [] --- # @pharaoh.feat-draft-from-docs -Use when reading one or more existing documentation files (unstructured prose, README, tutorial) and emitting one or more feature-level RST directives (typed by `target_level`, default `feat`) that describe the user-facing capabilities documented in those files. +Use when reading one or more existing documentation files (unstructured prose, README, tutorial) and emitting one or more feature-level RST directives (typed by `target_level`, default `feat`) that describe the user-facing capabilities documented in those files. Does NOT read source code. Does NOT emit component requirements. Does NOT map features to files — that is `pharaoh-feat-file-map`. See [`skills/pharaoh-feat-draft-from-docs/SKILL.md`](../../skills/pharaoh-feat-draft-from-docs/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-file-map.agent.md b/.github/agents/pharaoh.feat-file-map.agent.md index 0680f3b..5726391 100644 --- a/.github/agents/pharaoh.feat-file-map.agent.md +++ b/.github/agents/pharaoh.feat-file-map.agent.md @@ -1,10 +1,10 @@ --- -description: Use when mapping one feature (already emitted as an RST directive) to the source files that implement it. +description: Use when mapping one feature (already emitted as an RST directive) to the source files that implement it. Reads the source tree, returns a YAML entry `{feat_id: {files: [...], rationale: "..."}}`. Does NOT read docs. Does NOT emit reqs. Does NOT create or modify source files. handoffs: [] --- # @pharaoh.feat-file-map -Use when mapping one feature (already emitted as an RST directive) to the source files that implement it. +Use when mapping one feature (already emitted as an RST directive) to the source files that implement it. Reads the source tree, returns a YAML entry `{feat_id: {files: [...], rationale: "..."}}`. Does NOT read docs. Does NOT emit reqs. Does NOT create or modify source files. See [`skills/pharaoh-feat-file-map/SKILL.md`](../../skills/pharaoh-feat-file-map/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-flow-extract.agent.md b/.github/agents/pharaoh.feat-flow-extract.agent.md index 444be70..5d9cc2d 100644 --- a/.github/agents/pharaoh.feat-flow-extract.agent.md +++ b/.github/agents/pharaoh.feat-flow-extract.agent.md @@ -1,10 +1,10 @@ --- -description: Use when reverse-engineering a feat and you need to derive a sequence diagram showing the control flow from its entry point through its source files. +description: Use when reverse-engineering a feat and you need to derive a sequence diagram showing the control flow from its entry point through its source files. Walks the call graph up to a bounded depth and emits a Mermaid or PlantUML sequence diagram whose output shape matches pharaoh-sequence-diagram-draft. Complements pharaoh-feat-component-extract (static view); this is the dynamic view. handoffs: [] --- # @pharaoh.feat-flow-extract -Use when reverse-engineering a feat and you need to derive a sequence diagram showing the control flow from its entry point through its source files. +Use when reverse-engineering a feat and you need to derive a sequence diagram showing the control flow from its entry point through its source files. Walks the call graph up to a bounded depth and emits a Mermaid or PlantUML sequence diagram whose output shape matches pharaoh-sequence-diagram-draft. Complements pharaoh-feat-component-extract (static view); this is the dynamic view. See [`skills/pharaoh-feat-flow-extract/SKILL.md`](../../skills/pharaoh-feat-flow-extract/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.feat-review.agent.md b/.github/agents/pharaoh.feat-review.agent.md index af64186..73e9d33 100644 --- a/.github/agents/pharaoh.feat-review.agent.md +++ b/.github/agents/pharaoh.feat-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single feature-level need against the generic feat review axes plus any project-specific addenda. +description: Use when auditing a single feature-level need (feat) against the generic feat review axes in `shared/checklists/feat.md` plus any per-project addenda in `.pharaoh/project/checklists/feat.md`. Emits structured findings JSON — per-axis pass/fail for mechanized axes, 0-3 score for subjective axes. Mirrors `pharaoh-req-review`'s shape for feat-level artefacts. handoffs: [] --- # @pharaoh.feat-review -Audit a single feature-level need against the generic feat review axes plus any project-specific addenda. +Use when auditing a single feature-level need (feat) against the generic feat review axes in `shared/checklists/feat.md` plus any per-project addenda in `.pharaoh/project/checklists/feat.md`. Emits structured findings JSON — per-axis pass/fail for mechanized axes, 0-3 score for subjective axes. Mirrors `pharaoh-req-review`'s shape for feat-level artefacts. -See [`skills/pharaoh-feat-review/SKILL.md`](../../skills/pharaoh-feat-review/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-feat-review/SKILL.md`](../../skills/pharaoh-feat-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.finding-record.agent.md b/.github/agents/pharaoh.finding-record.agent.md index 4da1519..35e2162 100644 --- a/.github/agents/pharaoh.finding-record.agent.md +++ b/.github/agents/pharaoh.finding-record.agent.md @@ -1,10 +1,10 @@ --- -description: Record an audit finding in the shared Papyrus workspace with deterministic dedup across concurrent subagents. +description: Use when recording an audit finding in the shared Papyrus workspace with automatic dedup. Uses deterministic ID to ensure the same {category, subject_id} tuple never appears twice across concurrent subagents. Returns {action: wrote|duplicate, papyrus_id}. handoffs: [] --- # @pharaoh.finding-record -Record an audit finding in the shared Papyrus workspace with deterministic dedup across concurrent subagents. +Use when recording an audit finding in the shared Papyrus workspace with automatic dedup. Uses deterministic ID to ensure the same {category, subject_id} tuple never appears twice across concurrent subagents. Returns {action: wrote|duplicate, papyrus_id}. See [`skills/pharaoh-finding-record/SKILL.md`](../../skills/pharaoh-finding-record/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.flow.agent.md b/.github/agents/pharaoh.flow.agent.md index f670320..028d3e8 100644 --- a/.github/agents/pharaoh.flow.agent.md +++ b/.github/agents/pharaoh.flow.agent.md @@ -1,10 +1,12 @@ --- -description: Orchestrate the full V-model chain — requirement, architecture, verification plan, FMEA — with review passes. +description: Use when orchestrating the full V-model chain for one feature context across the optional ISO 26262 safety V (hazard / safety_goal / fsr), the ASPICE SYS layer (sysreq / sys-arch), the ASPICE SW layer (swreq / swarch), and the classical component V (req / comp_req then arch then vplan then fmea), each with a review pass. Auto-detects which layers to run from the project's artefact-catalog.yaml; the caller can pass a stages argument to skip layers explicitly. Dispatches to pharaoh-req-draft, pharaoh-req-review, pharaoh-arch-draft, pharaoh-arch-review, pharaoh-vplan-draft, pharaoh-vplan-review, and pharaoh-fmea — safety-V types route through pharaoh-req-draft with the appropriate target_level, no new safety-V drafting skills are introduced. handoffs: [] --- # @pharaoh.flow -Orchestrate the full V-model chain — requirement, architecture, verification plan, FMEA — with review passes. +Use when orchestrating the full V-model chain for one feature context across the optional ISO 26262 safety V (hazard / safety_goal / fsr), the ASPICE SYS layer (sysreq / sys-arch), the ASPICE SW layer (swreq / swarch), and the classical component V (req / comp_req then arch then vplan then fmea), each with a review pass. Auto-detects which layers to run from the project's artefact-catalog.yaml; the caller can pass a stages argument to skip layers explicitly. + +Dispatches to pharaoh-req-draft, pharaoh-req-review, pharaoh-arch-draft, pharaoh-arch-review, pharaoh-vplan-draft, pharaoh-vplan-review, and pharaoh-fmea. Safety-V types route through pharaoh-req-draft with the appropriate target_level (hazard, safety_goal, fsr) — no new safety-V drafting skills are introduced. See [`skills/pharaoh-flow/SKILL.md`](../../skills/pharaoh-flow/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.fmea-review.agent.md b/.github/agents/pharaoh.fmea-review.agent.md index 6768550..9f8c623 100644 --- a/.github/agents/pharaoh.fmea-review.agent.md +++ b/.github/agents/pharaoh.fmea-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single FMEA entry against severity/occurrence/detection scales, RPN correctness, and cause/effect well-formedness. +description: Use when auditing a single FMEA entry (failure-mode row) against the generic FMEA review axes in `shared/checklists/fmea.md` plus per-project addenda. Checks severity/occurrence/detection scales, RPN computation, cause/effect well-formedness, traceability to the analyzed artefact. Emits structured findings JSON. handoffs: [] --- # @pharaoh.fmea-review -Audit a single FMEA entry against severity/occurrence/detection scales, RPN correctness, and cause/effect well-formedness. +Use when auditing a single FMEA entry (failure-mode row) against the generic FMEA review axes in `shared/checklists/fmea.md` plus per-project addenda. Checks severity/occurrence/detection scales, RPN computation, cause/effect well-formedness, traceability to the analyzed artefact. Emits structured findings JSON. -See [`skills/pharaoh-fmea-review/SKILL.md`](../../skills/pharaoh-fmea-review/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-fmea-review/SKILL.md`](../../skills/pharaoh-fmea-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.fmea.agent.md b/.github/agents/pharaoh.fmea.agent.md index f990fa0..9b3f4b4 100644 --- a/.github/agents/pharaoh.fmea.agent.md +++ b/.github/agents/pharaoh.fmea.agent.md @@ -1,10 +1,10 @@ --- -description: Derive a single failure-mode entry (FMEA / DFA row) from one requirement or architecture element. +description: Use when deriving a single failure-mode entry (FMEA / DFA row) from one requirement or architecture element. Emits structured JSON with cause, effect, severity (1-10), occurrence (1-10), detection (1-10), and RPN. handoffs: [] --- # @pharaoh.fmea -Derive a single failure-mode entry (FMEA / DFA row) from one requirement or architecture element. +Use when deriving a single failure-mode entry (FMEA / DFA row) from one requirement or architecture element. Emits structured JSON with cause, effect, severity (1-10), occurrence (1-10), detection (1-10), and RPN. See [`skills/pharaoh-fmea/SKILL.md`](../../skills/pharaoh-fmea/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.gate-advisor.agent.md b/.github/agents/pharaoh.gate-advisor.agent.md index 4c9c63b..0991f5c 100644 --- a/.github/agents/pharaoh.gate-advisor.agent.md +++ b/.github/agents/pharaoh.gate-advisor.agent.md @@ -1,10 +1,10 @@ --- -description: Read a project's `pharaoh.toml` and report which phased-enablement ladder step is the recommended next gate to switch on. Advisory, read-only — walks the fixed 5-step ladder in order (`require_verification` → `require_change_analysis` → `require_mece_on_release` → `codelinks.enabled` → `strictness = "enforcing"`) and names the first unmet step plus its blocker. +description: Use when reading a project's `pharaoh.toml` to report which phased-enablement ladder step is the recommended next gate to switch on. Single mechanical advisory check — parses five flags (`strictness`, `require_verification`, `require_change_analysis`, `require_mece_on_release`, `codelinks.enabled`), walks the fixed ladder in order, and emits the first unmet step plus its blocker note. Read-only; never edits `pharaoh.toml`. handoffs: [] --- # @pharaoh.gate-advisor -Read the project's `pharaoh.toml`, parse the five ladder flags, and emit a findings JSON naming the next recommended gate to enable, the blocker that must be cleared first, and the full fixed ladder. Read-only; never edits `pharaoh.toml`. The ladder rationale lives in [`skills/shared/gate-enablement.md`](../../skills/shared/gate-enablement.md) — this atom is the tool that walks it, not the authority that defines it. +Use when reading a project's `pharaoh.toml` to report which phased-enablement ladder step is the recommended next gate to switch on. Single mechanical advisory check — parses five flags (`strictness`, `require_verification`, `require_change_analysis`, `require_mece_on_release`, `codelinks.enabled`), walks the fixed ladder in order, and emits the first unmet step plus its blocker note. Read-only; never edits `pharaoh.toml`. -See [`skills/pharaoh-gate-advisor/SKILL.md`](../../skills/pharaoh-gate-advisor/SKILL.md) for the full atomic specification — inputs, outputs, per-step process, ladder table, rationale map, tailoring extension point, and composition patterns. +See [`skills/pharaoh-gate-advisor/SKILL.md`](../../skills/pharaoh-gate-advisor/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.id-allocate.agent.md b/.github/agents/pharaoh.id-allocate.agent.md index c2d23d7..bb80390 100644 --- a/.github/agents/pharaoh.id-allocate.agent.md +++ b/.github/agents/pharaoh.id-allocate.agent.md @@ -1,10 +1,10 @@ --- -description: Use when about to dispatch a fan-out of emission subagents (pharaoh-req-from-code, pharaoh-feat-draft-from-docs) and you need to pre-allocate globally-unique sphinx-needs IDs. +description: Use when about to dispatch a fan-out of emission subagents (pharaoh-req-from-code, pharaoh-feat-draft-from-docs) and you need to pre-allocate globally-unique sphinx-needs IDs. Each subagent receives its pre-allocated pool and emits only from that pool, so parallel agents cannot collide on stem choice. Does NOT invoke emitters, does NOT write RST. handoffs: [] --- # @pharaoh.id-allocate -Use when about to dispatch a fan-out of emission subagents (pharaoh-req-from-code, pharaoh-feat-draft-from-docs) and you need to pre-allocate globally-unique sphinx-needs IDs. +Use when about to dispatch a fan-out of emission subagents (pharaoh-req-from-code, pharaoh-feat-draft-from-docs) and you need to pre-allocate globally-unique sphinx-needs IDs. Each subagent receives its pre-allocated pool and emits only from that pool, so parallel agents cannot collide on stem choice. Does NOT invoke emitters, does NOT write RST. See [`skills/pharaoh-id-allocate/SKILL.md`](../../skills/pharaoh-id-allocate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.id-convention-check.agent.md b/.github/agents/pharaoh.id-convention-check.agent.md index d2af8bf..f8e2ff2 100644 --- a/.github/agents/pharaoh.id-convention-check.agent.md +++ b/.github/agents/pharaoh.id-convention-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify that every need id in a sphinx-needs corpus matches the regex declared for its type in .pharaoh/project/id-conventions.yaml. Emits a list of violations. +description: Use when verifying that every need id in a sphinx-needs corpus matches the regex declared for its type in `.pharaoh/project/id-conventions.yaml`. Single mechanical structural check — applies the tailored per-type regex, emits a list of violations. Does NOT auto-detect how many schemes coexist — scheme policy is the tailoring author's responsibility (declare an alternation to allow multiple forms). handoffs: [] --- # @pharaoh.id-convention-check -Verify that every need id in a sphinx-needs corpus matches the regex declared for its type in `.pharaoh/project/id-conventions.yaml`. Emits a list of violations. +Use when verifying that every need id in a sphinx-needs corpus matches the regex declared for its type in `.pharaoh/project/id-conventions.yaml`. Single mechanical structural check — applies the tailored per-type regex, emits a list of violations. Does NOT auto-detect how many schemes coexist — scheme policy is the tailoring author's responsibility (declare an alternation to allow multiple forms). -See [`skills/pharaoh-id-convention-check/SKILL.md`](../../skills/pharaoh-id-convention-check/SKILL.md) for the full atomic specification — inputs, outputs, detection rule, and composition patterns. +See [`skills/pharaoh-id-convention-check/SKILL.md`](../../skills/pharaoh-id-convention-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.lifecycle-check.agent.md b/.github/agents/pharaoh.lifecycle-check.agent.md index 9122660..b7474ef 100644 --- a/.github/agents/pharaoh.lifecycle-check.agent.md +++ b/.github/agents/pharaoh.lifecycle-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify a sphinx-needs artefact's lifecycle state and the legality of a requested state transition. +description: Use when verifying a sphinx-needs artefact's current lifecycle state and the legality of a requested state transition per the project's workflows.yaml state machine. handoffs: [] --- # @pharaoh.lifecycle-check -Verify a sphinx-needs artefact's lifecycle state and the legality of a requested state transition. +Use when verifying a sphinx-needs artefact's current lifecycle state and the legality of a requested state transition per the project's workflows.yaml state machine. See [`skills/pharaoh-lifecycle-check/SKILL.md`](../../skills/pharaoh-lifecycle-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.link-completeness-check.agent.md b/.github/agents/pharaoh.link-completeness-check.agent.md index e067e80..6d91804 100644 --- a/.github/agents/pharaoh.link-completeness-check.agent.md +++ b/.github/agents/pharaoh.link-completeness-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify outgoing-link coverage across a full needs.json graph against required/optional link types declared per artefact type in artefact-catalog.yaml — missing required links, unresolved target ids, per-type policy enforcement. +description: Use when verifying outgoing-link coverage across a full needs.json graph. For each declared link type in `artefact-catalog.yaml`, confirms every need of the governed type carries a non-empty value AND every target id resolves to an existing need. Closes the "catalogue declares `verifies` required but half the reqs ship without it" failure class. handoffs: [] --- # @pharaoh.link-completeness-check -Verify outgoing-link coverage across a full needs.json graph against required/optional link types declared per artefact type in `artefact-catalog.yaml` — missing required links, unresolved target ids, per-type policy enforcement. +Use when verifying outgoing-link coverage across a full needs.json graph. For each declared link type in `artefact-catalog.yaml`, confirms every need of the governed type carries a non-empty value AND every target id resolves to an existing need. Closes the "catalogue declares `verifies` required but half the reqs ship without it" failure class. -See [`skills/pharaoh-link-completeness-check/SKILL.md`](../../skills/pharaoh-link-completeness-check/SKILL.md) for the full atomic specification — inputs, outputs, per-pass detection rules, and composition patterns. +See [`skills/pharaoh-link-completeness-check/SKILL.md`](../../skills/pharaoh-link-completeness-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.mece.agent.md b/.github/agents/pharaoh.mece.agent.md index 1c5e41c..ec4d116 100644 --- a/.github/agents/pharaoh.mece.agent.md +++ b/.github/agents/pharaoh.mece.agent.md @@ -1,5 +1,5 @@ --- -description: Check for gaps, redundancies, and inconsistencies in sphinx-needs requirements. Validates traceability completeness. +description: Use when checking for gaps, redundancies, and inconsistencies in sphinx-needs requirements, or validating traceability completeness handoffs: - label: Trace a Need agent: pharaoh.trace diff --git a/.github/agents/pharaoh.output-validate.agent.md b/.github/agents/pharaoh.output-validate.agent.md index 331ad1f..bfa1914 100644 --- a/.github/agents/pharaoh.output-validate.agent.md +++ b/.github/agents/pharaoh.output-validate.agent.md @@ -1,10 +1,10 @@ --- -description: Use when `pharaoh-execute-plan` (or any caller) has dispatched a subagent whose output must match one of the documented schemas (RST directive, sphinx-codelinks one-line comment, YAML mapping, JSON object). +description: Use when `pharaoh-execute-plan` (or any caller) has dispatched a subagent whose output must match one of the documented schemas (RST directive, sphinx-codelinks one-line comment, YAML mapping, JSON object). Returns {valid, errors, parsed, recovery}. Callers gate subagent output through this before writing anything to disk. handoffs: [] --- # @pharaoh.output-validate -Use when `pharaoh-execute-plan` (or any caller) has dispatched a subagent whose output must match one of the documented schemas (RST directive, sphinx-codelinks one-line comment, YAML mapping, JSON object). +Use when `pharaoh-execute-plan` (or any caller) has dispatched a subagent whose output must match one of the documented schemas (RST directive, sphinx-codelinks one-line comment, YAML mapping, JSON object). Returns {valid, errors, parsed, recovery}. Callers gate subagent output through this before writing anything to disk. See [`skills/pharaoh-output-validate/SKILL.md`](../../skills/pharaoh-output-validate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.papyrus-non-empty-check.agent.md b/.github/agents/pharaoh.papyrus-non-empty-check.agent.md index 4e02bf7..712d563 100644 --- a/.github/agents/pharaoh.papyrus-non-empty-check.agent.md +++ b/.github/agents/pharaoh.papyrus-non-empty-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify that a Papyrus workspace received at least N writes during a plan run. +description: Use when verifying that a Papyrus workspace actually received writes during a plan run. Single mechanical check — counts directives across `.papyrus/memory/*.rst` and returns pass/fail against a configured minimum. Wired into `pharaoh-quality-gate` to detect the "LLM-executor skipped the atomic Papyrus writes" failure class observed in prior dogfooding. handoffs: [] --- # @pharaoh.papyrus-non-empty-check -Verify that a Papyrus workspace received at least N writes during a plan run. +Use when verifying that a Papyrus workspace actually received writes during a plan run. Single mechanical check — counts directives across `.papyrus/memory/*.rst` and returns pass/fail against a configured minimum. Wired into `pharaoh-quality-gate` to detect the "LLM-executor skipped the atomic Papyrus writes" failure class observed in prior dogfooding. See [`skills/pharaoh-papyrus-non-empty-check/SKILL.md`](../../skills/pharaoh-papyrus-non-empty-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.plan.agent.md b/.github/agents/pharaoh.plan.agent.md index 8ec0bb7..027ff2b 100644 --- a/.github/agents/pharaoh.plan.agent.md +++ b/.github/agents/pharaoh.plan.agent.md @@ -1,9 +1,15 @@ --- -description: Break requirement changes into structured implementation tasks with workflow enforcement and dependency ordering. +description: Use when breaking requirement changes into structured implementation tasks with workflow enforcement and dependency ordering handoffs: - label: Start Change Analysis agent: pharaoh.change prompt: Analyze the impact of the planned changes + - label: Author the planned needs + agent: pharaoh.author + prompt: Author the needs identified in this plan, one per task + - label: Verify the authored needs + agent: pharaoh.verify + prompt: Verify the authored needs against their parents and review axes --- # @pharaoh.plan diff --git a/.github/agents/pharaoh.process-audit.agent.md b/.github/agents/pharaoh.process-audit.agent.md index 69e01de..3911cc0 100644 --- a/.github/agents/pharaoh.process-audit.agent.md +++ b/.github/agents/pharaoh.process-audit.agent.md @@ -1,10 +1,10 @@ --- -description: Run a full-corpus audit across all gap categories plus cross-artefact consistency checks. +description: Use when running a full-corpus audit against a sphinx-needs project. Orchestrates pharaoh-coverage-gap across all gap categories plus cross-artefact consistency checks. Emits a prioritised gap report. handoffs: [] --- # @pharaoh.process-audit -Run a full-corpus audit across all gap categories plus cross-artefact consistency checks. +Use when running a full-corpus audit against a sphinx-needs project. Orchestrates pharaoh-coverage-gap across all gap categories plus cross-artefact consistency checks. Emits a prioritised gap report. See [`skills/pharaoh-process-audit/SKILL.md`](../../skills/pharaoh-process-audit/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.prose-migrate.agent.md b/.github/agents/pharaoh.prose-migrate.agent.md index db1ab43..de450d1 100644 --- a/.github/agents/pharaoh.prose-migrate.agent.md +++ b/.github/agents/pharaoh.prose-migrate.agent.md @@ -1,10 +1,10 @@ --- -description: Use when a reverse-engineering run (a plan emitted by pharaoh-write-plan) finds pre-existing prose documentation files in the target output directory that would collide with generated feat RST files. +description: Use when a reverse-engineering run (a plan emitted by pharaoh-write-plan) finds pre-existing prose documentation files in the target output directory that would collide with generated feat RST files. Produces a sentence-by-sentence migration proposal — keep-as-user-guide, merge-into-feat-body, discard. Does NOT overwrite anything; the caller applies the proposal manually. handoffs: [] --- # @pharaoh.prose-migrate -Use when a reverse-engineering run (a plan emitted by pharaoh-write-plan) finds pre-existing prose documentation files in the target output directory that would collide with generated feat RST files. +Use when a reverse-engineering run (a plan emitted by pharaoh-write-plan) finds pre-existing prose documentation files in the target output directory that would collide with generated feat RST files. Produces a sentence-by-sentence migration proposal — keep-as-user-guide, merge-into-feat-body, discard. Does NOT overwrite anything; the caller applies the proposal manually. See [`skills/pharaoh-prose-migrate/SKILL.md`](../../skills/pharaoh-prose-migrate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.quality-gate.agent.md b/.github/agents/pharaoh.quality-gate.agent.md index 95a52fc..d500423 100644 --- a/.github/agents/pharaoh.quality-gate.agent.md +++ b/.github/agents/pharaoh.quality-gate.agent.md @@ -1,10 +1,10 @@ --- -description: Use when running the final validation step of any Pharaoh composition that emits artefacts (reqs, features, architecture elements). +description: Use when running the final validation step of any Pharaoh composition that emits artefacts (reqs, features, architecture elements). Consumes an aggregated review+mece+coverage summary plus a gate spec; returns pass/fail with named breaches. Never produces summaries itself — thin gate layer over upstream atomic checkers. handoffs: [] --- # @pharaoh.quality-gate -Use when running the final validation step of any Pharaoh composition that emits artefacts (reqs, features, architecture elements). +Use when running the final validation step of any Pharaoh composition that emits artefacts (reqs, features, architecture elements). Consumes an aggregated review+mece+coverage summary plus a gate spec; returns pass/fail with named breaches. Never produces summaries itself — thin gate layer over upstream atomic checkers. See [`skills/pharaoh-quality-gate/SKILL.md`](../../skills/pharaoh-quality-gate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.release.agent.md b/.github/agents/pharaoh.release.agent.md index 03d131c..089e004 100644 --- a/.github/agents/pharaoh.release.agent.md +++ b/.github/agents/pharaoh.release.agent.md @@ -1,5 +1,5 @@ --- -description: Prepare a release by generating changelogs from requirements, release summaries, and traceability coverage metrics. +description: Use when preparing a release, generating changelogs from requirements, or summarizing requirement changes for version management handoffs: - label: MECE Check agent: pharaoh.mece diff --git a/.github/agents/pharaoh.reproducibility-check.agent.md b/.github/agents/pharaoh.reproducibility-check.agent.md index ee77bd2..a42da34 100644 --- a/.github/agents/pharaoh.reproducibility-check.agent.md +++ b/.github/agents/pharaoh.reproducibility-check.agent.md @@ -1,10 +1,10 @@ --- -description: Diff two output directories produced by two runs of the same plan to confirm the build is reproducible. Consumes baseline dir, rerun dir, and optional mask rules for non-deterministic fields (timestamps, random ids); emits drifted-file list with per-file changed-field summaries. Does NOT run the plan — that is the caller's responsibility (`pharaoh-execute-plan`). +description: Use when diffing two output directories produced by running the same plan twice to confirm the build is reproducible. Consumes a baseline directory, a rerun directory, and an optional list of mask rules for known-non-deterministic fields (timestamps, randomly-generated ids); emits a list of drifted files with per-file changed-field summaries. Does NOT run the plan — running is the caller's responsibility (`pharaoh-execute-plan`). handoffs: [] --- # @pharaoh.reproducibility-check -Diff two output directories produced by running the same plan twice to confirm the build is reproducible. Consumes a baseline directory, a rerun directory, and an optional list of mask rules for known-non-deterministic fields (timestamps, randomly-generated ids); emits a list of drifted files with per-file changed-field summaries. Does NOT run the plan — running twice is the caller's responsibility (`pharaoh-execute-plan`). +Use when diffing two output directories produced by running the same plan twice to confirm the build is reproducible. Consumes a baseline directory, a rerun directory, and an optional list of mask rules for known-non-deterministic fields (timestamps, randomly-generated ids); emits a list of drifted files with per-file changed-field summaries. Does NOT run the plan — running is the caller's responsibility (`pharaoh-execute-plan`). -See [`skills/pharaoh-reproducibility-check/SKILL.md`](../../skills/pharaoh-reproducibility-check/SKILL.md) for the full atomic specification — inputs, outputs, per-step process, failure modes, and composition patterns. +See [`skills/pharaoh-reproducibility-check/SKILL.md`](../../skills/pharaoh-reproducibility-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-code-grounding-check.agent.md b/.github/agents/pharaoh.req-code-grounding-check.agent.md index f188291..c8d4075 100644 --- a/.github/agents/pharaoh.req-code-grounding-check.agent.md +++ b/.github/agents/pharaoh.req-code-grounding-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify a drafted requirement's claims against the source file it cites via :source_doc: — exception raise sites, trigger conditions, type-framework imports, named symbols, weasel adjectives, quantifier enumeration, branch count. +description: Use when verifying a single drafted requirement against the source file it cites via `:source_doc:`. Single mechanical fidelity check — compares the CREQ's claims about exceptions, triggers, types, structural symbols, backtick-quoted identifiers, grounding density, adjectives, quantifiers, and branch count against the cited source, returning per-axis findings JSON. Complements `pharaoh-req-review` (which grades prose quality) with code-grounded axes. handoffs: [] --- # @pharaoh.req-code-grounding-check -Verify a drafted requirement's claims against the source file it cites via `:source_doc:` — exception raise sites, trigger conditions, type-framework imports, named symbols, weasel adjectives, quantifier enumeration, branch count. +Use when verifying a single drafted requirement against the source file it cites via `:source_doc:`. Single mechanical fidelity check — compares the CREQ's claims about exceptions, triggers, types, structural symbols, backtick-quoted identifiers, grounding density, adjectives, quantifiers, and branch count against the cited source, returning per-axis findings JSON. Complements `pharaoh-req-review` (which grades prose quality) with code-grounded axes. -See [`skills/pharaoh-req-code-grounding-check/SKILL.md`](../../skills/pharaoh-req-code-grounding-check/SKILL.md) for the full atomic specification — inputs, outputs, per-axis detection rules, and composition patterns. +See [`skills/pharaoh-req-code-grounding-check/SKILL.md`](../../skills/pharaoh-req-code-grounding-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-codelink-annotate.agent.md b/.github/agents/pharaoh.req-codelink-annotate.agent.md index 004eb8c..c4f79b1 100644 --- a/.github/agents/pharaoh.req-codelink-annotate.agent.md +++ b/.github/agents/pharaoh.req-codelink-annotate.agent.md @@ -1,10 +1,10 @@ --- -description: Use when a requirement has been drafted (either as an RST block by `pharaoh-req-from-code` or implicitly) and you need to insert a one-line comment into the source file that carries the trace. +description: Use when a requirement has been drafted (either as an RST block by `pharaoh-req-from-code` or implicitly) and you need to insert a one-line comment into the source file that carries the trace. Two modes — `codelinks` (sphinx-codelinks-compatible multi-field `@ title, id, type, [links]` form; the comment IS the need) and `backref` (minimal `@req ID: title` pointer back to an RST-hosted need). Mode is tailored via `ubproject.toml` / `pharaoh.toml`, not hardcoded. handoffs: [] --- # @pharaoh.req-codelink-annotate -Use when a requirement has been drafted (either as an RST block by `pharaoh-req-from-code` or implicitly) and you need to insert a one-line comment into the source file that carries the trace. +Use when a requirement has been drafted (either as an RST block by `pharaoh-req-from-code` or implicitly) and you need to insert a one-line comment into the source file that carries the trace. Two modes — `codelinks` (sphinx-codelinks-compatible multi-field `@ title, id, type, [links]` form; the comment IS the need) and `backref` (minimal `@req ID: title` pointer back to an RST-hosted need). Mode is tailored via `ubproject.toml` / `pharaoh.toml`, not hardcoded. See [`skills/pharaoh-req-codelink-annotate/SKILL.md`](../../skills/pharaoh-req-codelink-annotate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-draft.agent.md b/.github/agents/pharaoh.req-draft.agent.md index 0c56ffd..6021bfd 100644 --- a/.github/agents/pharaoh.req-draft.agent.md +++ b/.github/agents/pharaoh.req-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Draft a single sphinx-needs requirement from a feature description. +description: Use when drafting a single sphinx-needs requirement-shaped artefact (req, comp_req, sysreq, swreq, hazard, safety_goal, fsr, etc.) from a feature description. The artefact type is parameterised via target_level (any catalog-declared requirement-shaped type, including ISO 26262 safety-V types). Produces a new RST directive block with ID, status=draft, and either a shall-clause body or a hazard/goal-shaped body, linking to a parent per the project's artefact-catalog. handoffs: [] --- # @pharaoh.req-draft -Draft a single sphinx-needs requirement from a feature description. +Use when drafting a single sphinx-needs requirement-shaped artefact (req, comp_req, sysreq, swreq, hazard, safety_goal, fsr, etc.) from a feature description. The artefact type is parameterised via target_level (any catalog-declared requirement-shaped type, including ISO 26262 safety-V types). Produces a new RST directive block with ID, status=draft, and either a shall-clause body or a hazard/goal-shaped body, linking to a parent per the project's artefact-catalog. See [`skills/pharaoh-req-draft/SKILL.md`](../../skills/pharaoh-req-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-from-code.agent.md b/.github/agents/pharaoh.req-from-code.agent.md index 848345a..9e7bb93 100644 --- a/.github/agents/pharaoh.req-from-code.agent.md +++ b/.github/agents/pharaoh.req-from-code.agent.md @@ -1,10 +1,10 @@ --- -description: Read one source file and emit comp_req directives describing its observable behavior, coordinating canonical names via Papyrus. +description: Use when reading one source file and emitting one or more requirement RST directives (typed by `target_level`) describing the observable behavior in that file. Queries shared Papyrus for canonical terms before naming concepts; writes newly surfaced concepts back. Does not draft architecture, plans, or FMEA. handoffs: [] --- # @pharaoh.req-from-code -Read one source file and emit comp_req directives describing its observable behavior, coordinating canonical names via Papyrus. +Use when reading one source file and emitting one or more requirement RST directives (typed by `target_level`) describing the observable behavior in that file. Queries shared Papyrus for canonical terms before naming concepts; writes newly surfaced concepts back. Does not draft architecture, plans, or FMEA. See [`skills/pharaoh-req-from-code/SKILL.md`](../../skills/pharaoh-req-from-code/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-regenerate.agent.md b/.github/agents/pharaoh.req-regenerate.agent.md index e0d48e9..28f7407 100644 --- a/.github/agents/pharaoh.req-regenerate.agent.md +++ b/.github/agents/pharaoh.req-regenerate.agent.md @@ -1,10 +1,10 @@ --- -description: Regenerate a single sphinx-needs requirement to address findings from a prior review. +description: Use when regenerating a single sphinx-needs requirement to address findings from pharaoh-req-review. Consumes the original RST + findings JSON, emits a revised RST directive that passes the flagged axes. handoffs: [] --- # @pharaoh.req-regenerate -Regenerate a single sphinx-needs requirement to address findings from a prior review. +Use when regenerating a single sphinx-needs requirement to address findings from pharaoh-req-review. Consumes the original RST + findings JSON, emits a revised RST directive that passes the flagged axes. See [`skills/pharaoh-req-regenerate/SKILL.md`](../../skills/pharaoh-req-regenerate/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.req-review.agent.md b/.github/agents/pharaoh.req-review.agent.md index f33ff28..dabf554 100644 --- a/.github/agents/pharaoh.req-review.agent.md +++ b/.github/agents/pharaoh.req-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single sphinx-needs requirement against the ISO 26262 Part 8 §6 axes. +description: Use when auditing a single sphinx-needs requirement against the 11 ISO 26262 Part 8 §6 axes. Emits structured findings JSON — per-axis pass/fail for mechanized axes, 0-3 score for subjective axes, with action items for any failure. handoffs: [] --- # @pharaoh.req-review -Audit a single sphinx-needs requirement against the ISO 26262 Part 8 §6 axes. +Use when auditing a single sphinx-needs requirement against the 11 ISO 26262 Part 8 §6 axes. Emits structured findings JSON — per-axis pass/fail for mechanized axes, 0-3 score for subjective axes, with action items for any failure. See [`skills/pharaoh-req-review/SKILL.md`](../../skills/pharaoh-req-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.review-completeness.agent.md b/.github/agents/pharaoh.review-completeness.agent.md index 2873634..df8be0e 100644 --- a/.github/agents/pharaoh.review-completeness.agent.md +++ b/.github/agents/pharaoh.review-completeness.agent.md @@ -1,10 +1,10 @@ --- -description: Inspect needs for review / approval-chain completeness; flag missing reviewer / approved_by fields. +description: Use when inspecting one or more needs for review / approval-chain completeness. Flags needs missing required :reviewer: or :approved_by: fields per the project's artefact catalog. Emits one finding per incomplete need via pharaoh-finding-record. handoffs: [] --- # @pharaoh.review-completeness -Inspect needs for review / approval-chain completeness; flag missing reviewer / approved_by fields. +Use when inspecting one or more needs for review / approval-chain completeness. Flags needs missing required :reviewer: or :approved_by: fields per the project's artefact catalog. Emits one finding per incomplete need via pharaoh-finding-record. See [`skills/pharaoh-review-completeness/SKILL.md`](../../skills/pharaoh-review-completeness/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.self-review-coverage-check.agent.md b/.github/agents/pharaoh.self-review-coverage-check.agent.md index 92beffa..e93ca48 100644 --- a/.github/agents/pharaoh.self-review-coverage-check.agent.md +++ b/.github/agents/pharaoh.self-review-coverage-check.agent.md @@ -1,10 +1,10 @@ --- -description: Verify every drafted artefact in runs/ has a matching review JSON. +description: Use when verifying that every artefact emitted during a plan run received a matching review. For every drafted artefact in `runs/`, confirms a matching `_review.json` exists and is non-empty. Closes the "draft emitted but review was skipped" failure class. handoffs: [] --- # @pharaoh.self-review-coverage-check -Verify every drafted artefact in runs/ has a matching review JSON. +Use when verifying that every artefact emitted during a plan run received a matching review. For every drafted artefact in `runs/`, confirms a matching `_review.json` exists and is non-empty. Closes the "draft emitted but review was skipped" failure class. -See [`skills/pharaoh-self-review-coverage-check/SKILL.md`](../../skills/pharaoh-self-review-coverage-check/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-self-review-coverage-check/SKILL.md`](../../skills/pharaoh-self-review-coverage-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.sequence-diagram-draft.agent.md b/.github/agents/pharaoh.sequence-diagram-draft.agent.md index 6fd0ae8..666e39c 100644 --- a/.github/agents/pharaoh.sequence-diagram-draft.agent.md +++ b/.github/agents/pharaoh.sequence-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one sequence diagram showing ordered interactions between participants (components, actors, external systems) over time. +description: Use when drafting one sequence diagram showing ordered interactions between participants (components, actors, external systems) over time. Renderer tailored via `pharaoh.toml`. Does NOT emit component, class, or state diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.sequence-diagram-draft -Use when drafting one sequence diagram showing ordered interactions between participants (components, actors, external systems) over time. +Use when drafting one sequence diagram showing ordered interactions between participants (components, actors, external systems) over time. Renderer tailored via `pharaoh.toml`. Does NOT emit component, class, or state diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-sequence-diagram-draft/SKILL.md`](../../skills/pharaoh-sequence-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.setup.agent.md b/.github/agents/pharaoh.setup.agent.md index 9ff2517..c0b857c 100644 --- a/.github/agents/pharaoh.setup.agent.md +++ b/.github/agents/pharaoh.setup.agent.md @@ -1,5 +1,5 @@ --- -description: Scaffold Pharaoh into a sphinx-needs project. Detects project structure, generates pharaoh.toml, installs Copilot agents, and recommends tooling. +description: Use when setting up Pharaoh in a sphinx-needs project for the first time, scaffolding Copilot agents, or reconfiguring project detection. Reads project state (declared types, fields, links, observed RST IDs and statuses) before imposing Pharaoh-internal defaults. handoffs: - label: Run MECE Check agent: pharaoh.mece @@ -11,7 +11,7 @@ handoffs: # @pharaoh.setup -Scaffold Pharaoh into a sphinx-needs project. Detect the project structure, generate a `pharaoh.toml` configuration file, and recommend tooling for the best experience. +Scaffold Pharaoh into a sphinx-needs project. Detect the project structure, read its declared conventions and existing artefacts, generate a `pharaoh.toml` configuration file, seed `.pharaoh/project/` tailoring descriptively from observation, and recommend tooling for the best experience. ## Data Access @@ -57,17 +57,42 @@ Data access: ubCode MCP: ``` -### Step 2: Generate pharaoh.toml +### Step 2: Generate pharaoh.toml and seed .pharaoh/project/ descriptively 1. Ask the user for strictness preference: `advisory` (default, suggests but never blocks) or `enforcing` (checks prerequisites, blocks if not met). -2. Analyze existing need IDs to detect the ID pattern (e.g., `{TYPE}_{NUMBER}` or `{TYPE}-{MODULE}-{NUMBER}`). -3. Build `required_links` from detected extra link types and their usage. -4. Check if `pharaoh.toml` already exists. If so, show a diff and ask what to do. -5. Present the generated content and get confirmation before writing. +2. **Classify project mode from declared types and RST content** — not from `needs.json` existence (a gitignored build artefact). `[[needs.types]]` declared + RST has needs with ≥10% in matured statuses → `steady-state`; types declared + RST has needs → `reverse-eng`; types declared + no needs → `greenfield`. +3. **Detect the ID pattern from up to 20 sampled IDs** in `/**/*.rst`. Recognise `{TYPE}_{NUMBER}`, `{TYPE}-{MODULE}-{NUMBER}`, and `{DOMAIN}_{NUMBER}` (leading token is not a declared type prefix — e.g. `BRAKE_CTRL_01`). Reject the heuristic `{TYPE}_{NUMBER}` default when observed IDs do not conform. +4. **Read `[needs.fields.X]` and `[needs.links.X]` from `ubproject.toml`** to populate `optional_fields`, `required_metadata_fields`, `required_links`, `optional_links`, `required_roles` per declared type for `.pharaoh/project/artefact-catalog.yaml`. Fall back to Pharaoh-internal defaults (`reviewer`, `approved_by`, `source_doc`) only when the project declares no fields. +5. **Compute `lifecycle_states` from a status histogram** of `:status:` values in existing RST files. Fall back to `[draft, reviewed, approved]` only when no `:status:` is observed anywhere. +6. **Detect ID-prefix collisions in `[[needs.types]]`.** In `advisory` strictness, WARN with a remediation hint and proceed; in `enforcing`, FAIL and refuse to write `id-conventions.yaml`. +7. **Direction-infer `required_links` from edges**, not link names. Apply the rule uniformly to every link option declared in `[needs.links.]` (no per-name allow-list). Source 1 (built `needs.json` ≥3 instances + ≥90% coverage) → Source 2 (declared `from`/`to` hint) → Source 3 (refuse to guess; emit TODO comment). +8. Check if `pharaoh.toml` already exists. If so, show a diff and ask what to do. +9. Present the generated content and get confirmation before writing. + +After writing `pharaoh.toml`, invoke `pharaoh-tailor-bootstrap` with the descriptive overrides from steps 4-7 above so `.pharaoh/project/{workflows,id-conventions,artefact-catalog}.yaml` capture what the project declares and uses, not Pharaoh-internal placeholders. ### Step 3: Configure .gitignore -Add `.pharaoh/` to `.gitignore` if not already present. Create `.gitignore` if needed. +`.pharaoh/` contains a mix of committed tailoring and ephemeral run state. Ignoring the whole tree is wrong — it hides `.pharaoh/project/` tailoring which IS shared across the team. Ignore only the ephemeral subpaths: + +| Path | Purpose | Commit? | +| ----------------------- | -------------------------------------------------------- | ------- | +| `.pharaoh/project/` | Tailoring: workflows, id-conventions, artefact-catalog, checklists | **yes** | +| `.pharaoh/runs/` | `pharaoh-execute-plan` run artefacts (report.yaml, staged RST) | no | +| `.pharaoh/plans/` | plan.yaml files emitted by `pharaoh-write-plan` | no | +| `.pharaoh/session.json` | Session / gate state | no | +| `.pharaoh/cache/` | Derived caches | no | + +Entries to add (create `.gitignore` if missing): + +``` +.pharaoh/runs/ +.pharaoh/plans/ +.pharaoh/session.json +.pharaoh/cache/ +``` + +If `.gitignore` already contains a bare `.pharaoh/` (or `.pharaoh`) line, leave it alone and warn the user that the wide form hides `.pharaoh/project/` tailoring which should be committed; recommend narrowing to the four ephemeral entries above. Do not auto-migrate — respect user control. ### Step 4: Recommend Tooling @@ -87,8 +112,13 @@ Present everything configured and list available agents: ``` Available agents (GitHub Copilot): - @pharaoh.setup @pharaoh.change @pharaoh.trace @pharaoh.mece - @pharaoh.author @pharaoh.verify @pharaoh.release @pharaoh.plan + . Do not hardcode this list — the skill set has grown + beyond the original happy-path agents to include atomic skills like + pharaoh.req-draft, pharaoh.req-review, pharaoh.arch-draft, + pharaoh.tailor-detect, pharaoh.tailor-fill, pharaoh.audit-fanout, and + others.> Workflow: @pharaoh.change -> @pharaoh.author -> @pharaoh.verify -> @pharaoh.release ``` diff --git a/.github/agents/pharaoh.spec.agent.md b/.github/agents/pharaoh.spec.agent.md index 13e89a8..a3b87b5 100644 --- a/.github/agents/pharaoh.spec.agent.md +++ b/.github/agents/pharaoh.spec.agent.md @@ -1,5 +1,5 @@ --- -description: Generate a Superpowers-compatible spec and plan document from sphinx-needs requirements, bridging requirements to implementation. +description: Use when generating a Superpowers-compatible spec and plan document from sphinx-needs requirements, bridging requirements to implementation handoffs: - label: Execute Plan agent: pharaoh.plan diff --git a/.github/agents/pharaoh.sphinx-extension-add.agent.md b/.github/agents/pharaoh.sphinx-extension-add.agent.md index 67ceb53..9f9e20c 100644 --- a/.github/agents/pharaoh.sphinx-extension-add.agent.md +++ b/.github/agents/pharaoh.sphinx-extension-add.agent.md @@ -1,10 +1,10 @@ --- -description: Idempotently add one or more sphinx extension modules to a project's `conf.py` extensions list, optionally installing the corresponding pypi packages via the detected package manager. +description: Use when you need to idempotently add one or more sphinx extension modules to a project's `conf.py` extensions list, optionally installing the corresponding pypi packages via the detected package manager. Invoked by plans produced by pharaoh-write-plan when a diagram-emitting task requires a renderer extension that `conf.py` does not yet load. Does NOT emit RST. Does NOT build. handoffs: [] --- # @pharaoh.sphinx-extension-add -Add sphinx extensions (e.g. `sphinxcontrib.mermaid`, `sphinxcontrib.plantuml`, `myst_parser`) to a project's `conf.py` extensions list. Idempotent: noop when all requested extensions are already loaded. Optionally installs the corresponding pypi packages via the detected package manager (rye / uv / poetry / pdm / pip-venv). Typically inserted into a plan by `pharaoh.write-plan` as a prerequisite to diagram-emitting tasks when `conf.py` lacks the required renderer extension. +Use when you need to idempotently add one or more sphinx extension modules to a project's `conf.py` extensions list, optionally installing the corresponding pypi packages via the detected package manager. Invoked by plans produced by pharaoh-write-plan when a diagram-emitting task requires a renderer extension that `conf.py` does not yet load. Does NOT emit RST. Does NOT build. See [`skills/pharaoh-sphinx-extension-add/SKILL.md`](../../skills/pharaoh-sphinx-extension-add/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.standard-conformance.agent.md b/.github/agents/pharaoh.standard-conformance.agent.md index 17ea5f7..ae0163c 100644 --- a/.github/agents/pharaoh.standard-conformance.agent.md +++ b/.github/agents/pharaoh.standard-conformance.agent.md @@ -1,10 +1,10 @@ --- -description: Evaluate a single artefact against one regulatory standard (ISO 26262, ASPICE, ISO/SAE 21434). +description: Use when evaluating a single sphinx-needs artefact against one regulatory standard (ISO 26262-8 §6, ASPICE 4.0, ISO/SAE 21434). Emits per-indicator findings JSON with pass/fail on mechanizable indicators and 0-3 scores on subjective ones. handoffs: [] --- # @pharaoh.standard-conformance -Evaluate a single artefact against one regulatory standard (ISO 26262, ASPICE, ISO/SAE 21434). +Use when evaluating a single sphinx-needs artefact against one regulatory standard (ISO 26262-8 §6, ASPICE 4.0, ISO/SAE 21434). Emits per-indicator findings JSON with pass/fail on mechanizable indicators and 0-3 scores on subjective ones. See [`skills/pharaoh-standard-conformance/SKILL.md`](../../skills/pharaoh-standard-conformance/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.state-diagram-draft.agent.md b/.github/agents/pharaoh.state-diagram-draft.agent.md index 652dc24..ec261c4 100644 --- a/.github/agents/pharaoh.state-diagram-draft.agent.md +++ b/.github/agents/pharaoh.state-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Use when drafting one state-machine diagram showing lifecycle or behavioral states of a component/entity, with labeled transitions. +description: Use when drafting one state-machine diagram showing lifecycle or behavioral states of a component/entity, with labeled transitions. Renderer tailored via `pharaoh.toml`. Does NOT emit component, sequence, or class diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). handoffs: [] --- # @pharaoh.state-diagram-draft -Use when drafting one state-machine diagram showing lifecycle or behavioral states of a component/entity, with labeled transitions. +Use when drafting one state-machine diagram showing lifecycle or behavioral states of a component/entity, with labeled transitions. Renderer tailored via `pharaoh.toml`. Does NOT emit component, sequence, or class diagrams. Status — PLANNED (design-only scaffold; invoking returns sentinel FAIL until implemented). See [`skills/pharaoh-state-diagram-draft/SKILL.md`](../../skills/pharaoh-state-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.status-lifecycle-check.agent.md b/.github/agents/pharaoh.status-lifecycle-check.agent.md index 935ba38..f04f403 100644 --- a/.github/agents/pharaoh.status-lifecycle-check.agent.md +++ b/.github/agents/pharaoh.status-lifecycle-check.agent.md @@ -1,5 +1,5 @@ --- -description: Release-gate check over a sphinx-needs corpus — counts needs still in the `draft` bucket (per workflows.yaml) and returns binary pass/fail when `enforce=true`. Advisory mode reports counts without failing. +description: Use when running a release-gate check over a full sphinx-needs corpus to confirm that zero needs remain in the initial `draft` status. Single mechanical binary gate — aggregates `status` across every need in `needs.json`, compares against the initial-state declaration in `workflows.yaml`, and returns pass/fail plus per-status counts. Advisory by default (pre-release development passes); release pipelines override `enforce=true` so any draft blocks the gate. handoffs: - label: Aggregate into quality gate agent: pharaoh.quality-gate @@ -8,6 +8,6 @@ handoffs: # @pharaoh.status-lifecycle-check -Aggregate `status` across every need in `needs.json` against the `initial_state` declared in `workflows.yaml`. Binary release gate — under `enforce=true`, zero drafts pass, one draft fails. Under `enforce=false` (default), the findings are reported without failing so pre-release development is unblocked. Distinct from `pharaoh-lifecycle-check`, which evaluates per-need transition legality against `requires:` prerequisites. +Use when running a release-gate check over a full sphinx-needs corpus to confirm that zero needs remain in the initial `draft` status. Single mechanical binary gate — aggregates `status` across every need in `needs.json`, compares against the initial-state declaration in `workflows.yaml`, and returns pass/fail plus per-status counts. Advisory by default (pre-release development passes); release pipelines override `enforce=true` so any draft blocks the gate. See [`skills/pharaoh-status-lifecycle-check/SKILL.md`](../../skills/pharaoh-status-lifecycle-check/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.tailor-bootstrap.agent.md b/.github/agents/pharaoh.tailor-bootstrap.agent.md index fc6465e..2e37a48 100644 --- a/.github/agents/pharaoh.tailor-bootstrap.agent.md +++ b/.github/agents/pharaoh.tailor-bootstrap.agent.md @@ -1,10 +1,10 @@ --- -description: Use when a sphinx-needs project has just been bootstrapped (post pharaoh-bootstrap, pre any needs authoring) and you need to generate minimal tailoring files from declared types — workflows. +description: Use when a sphinx-needs project has just been bootstrapped (post pharaoh-bootstrap, pre any needs authoring) and you need to generate minimal tailoring files from declared types — workflows.yaml, id-conventions.yaml, artefact-catalog.yaml, and per-type checklists — without requiring any needs to exist. Complements pharaoh-tailor-detect which requires ≥10 needs. handoffs: [] --- # @pharaoh.tailor-bootstrap -Use when a sphinx-needs project has just been bootstrapped (post pharaoh-bootstrap, pre any needs authoring) and you need to generate minimal tailoring files from declared types — workflows. +Use when a sphinx-needs project has just been bootstrapped (post pharaoh-bootstrap, pre any needs authoring) and you need to generate minimal tailoring files from declared types — workflows.yaml, id-conventions.yaml, artefact-catalog.yaml, and per-type checklists — without requiring any needs to exist. Complements pharaoh-tailor-detect which requires ≥10 needs. See [`skills/pharaoh-tailor-bootstrap/SKILL.md`](../../skills/pharaoh-tailor-bootstrap/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.tailor-code-grounding-filters.agent.md b/.github/agents/pharaoh.tailor-code-grounding-filters.agent.md index b17d90c..f2f5bb6 100644 --- a/.github/agents/pharaoh.tailor-code-grounding-filters.agent.md +++ b/.github/agents/pharaoh.tailor-code-grounding-filters.agent.md @@ -1,10 +1,10 @@ --- -description: Detect language + CLI framework + config-default idiom in a project source tree and emit a code-grounding-filters.yaml wiring the four parameterised filter strategies to the detected stack. +description: Use when authoring a project's `code-grounding-filters.yaml` from observed stack conventions. Detects language + CLI framework + config-object style in the project source tree and emits a tailoring YAML populated with the four parameterised filter strategies. Does not invoke `pharaoh-req-code-grounding-check`; purely produces tailoring. handoffs: [] --- # @pharaoh.tailor-code-grounding-filters -Detect language + CLI framework + config-default idiom in a project source tree and emit a code-grounding-filters.yaml wiring the four parameterised filter strategies to the detected stack. +Use when authoring a project's `code-grounding-filters.yaml` from observed stack conventions. Detects language + CLI framework + config-object style in the project source tree and emits a tailoring YAML populated with the four parameterised filter strategies. Does not invoke `pharaoh-req-code-grounding-check`; purely produces tailoring. See [`skills/pharaoh-tailor-code-grounding-filters/SKILL.md`](../../skills/pharaoh-tailor-code-grounding-filters/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.tailor-detect.agent.md b/.github/agents/pharaoh.tailor-detect.agent.md index 233a42d..680f063 100644 --- a/.github/agents/pharaoh.tailor-detect.agent.md +++ b/.github/agents/pharaoh.tailor-detect.agent.md @@ -1,10 +1,10 @@ --- -description: Inspect a sphinx-needs project and emit a structured report of detected conventions. +description: Use when inspecting a sphinx-needs project to emit a structured report of detected conventions — prefixes, ID regex candidates, separator, lifecycle states, artefact types with observed required/optional fields. Does NOT author tailoring files (see pharaoh-tailor-fill). handoffs: [] --- # @pharaoh.tailor-detect -Inspect a sphinx-needs project and emit a structured report of detected conventions. +Use when inspecting a sphinx-needs project to emit a structured report of detected conventions — prefixes, ID regex candidates, separator, lifecycle states, artefact types with observed required/optional fields. Does NOT author tailoring files (see pharaoh-tailor-fill). See [`skills/pharaoh-tailor-detect/SKILL.md`](../../skills/pharaoh-tailor-detect/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.tailor-fill.agent.md b/.github/agents/pharaoh.tailor-fill.agent.md index 92f35f3..11afcd1 100644 --- a/.github/agents/pharaoh.tailor-fill.agent.md +++ b/.github/agents/pharaoh.tailor-fill.agent.md @@ -1,10 +1,10 @@ --- -description: Author .pharaoh/project/ tailoring files from a detected-conventions report. +description: Use when authoring the .pharaoh/project/ tailoring files (id-conventions.yaml, workflows.yaml, artefact-catalog.yaml, checklists/requirement.md) from detected-conventions JSON produced by pharaoh-tailor-detect. handoffs: [] --- # @pharaoh.tailor-fill -Author .pharaoh/project/ tailoring files from a detected-conventions report. +Use when authoring the .pharaoh/project/ tailoring files (id-conventions.yaml, workflows.yaml, artefact-catalog.yaml, checklists/requirement.md) from detected-conventions JSON produced by pharaoh-tailor-detect. See [`skills/pharaoh-tailor-fill/SKILL.md`](../../skills/pharaoh-tailor-fill/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.tailor-review.agent.md b/.github/agents/pharaoh.tailor-review.agent.md index 2a2abff..30a5d4e 100644 --- a/.github/agents/pharaoh.tailor-review.agent.md +++ b/.github/agents/pharaoh.tailor-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit .pharaoh/project/ tailoring files against JSON schemas and cross-file consistency. +description: Use when auditing .pharaoh/project/ tailoring files against JSON schemas (id-conventions, workflows, artefact-catalog, checklists frontmatter) plus cross-file consistency checks (every lifecycle state referenced in artefact-catalog exists in workflows.yaml, every prefix in artefact-catalog is declared in id-conventions, etc.). handoffs: [] --- # @pharaoh.tailor-review -Audit .pharaoh/project/ tailoring files against JSON schemas and cross-file consistency. +Use when auditing .pharaoh/project/ tailoring files against JSON schemas (id-conventions, workflows, artefact-catalog, checklists frontmatter) plus cross-file consistency checks (every lifecycle state referenced in artefact-catalog exists in workflows.yaml, every prefix in artefact-catalog is declared in id-conventions, etc.). See [`skills/pharaoh-tailor-review/SKILL.md`](../../skills/pharaoh-tailor-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.toctree-emit.agent.md b/.github/agents/pharaoh.toctree-emit.agent.md index 3aa35f5..1532bdb 100644 --- a/.github/agents/pharaoh.toctree-emit.agent.md +++ b/.github/agents/pharaoh.toctree-emit.agent.md @@ -1,10 +1,10 @@ --- -description: Use when a composition skill has just emitted a set of RST files into a directory and needs to add (or regenerate) an `index. +description: Use when a composition skill has just emitted a set of RST files into a directory and needs to add (or regenerate) an `index.rst` with a Sphinx toctree over them. Prevents orphan-file warnings under `sphinx-build -W`. Does NOT modify the emitted RST files. Does NOT wire the emitted directory into any parent toctree — that is a caller concern. handoffs: [] --- # @pharaoh.toctree-emit -Use when a composition skill has just emitted a set of RST files into a directory and needs to add (or regenerate) an `index. +Use when a composition skill has just emitted a set of RST files into a directory and needs to add (or regenerate) an `index.rst` with a Sphinx toctree over them. Prevents orphan-file warnings under `sphinx-build -W`. Does NOT modify the emitted RST files. Does NOT wire the emitted directory into any parent toctree — that is a caller concern. See [`skills/pharaoh-toctree-emit/SKILL.md`](../../skills/pharaoh-toctree-emit/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.trace.agent.md b/.github/agents/pharaoh.trace.agent.md index b6c4ba8..095c023 100644 --- a/.github/agents/pharaoh.trace.agent.md +++ b/.github/agents/pharaoh.trace.agent.md @@ -1,5 +1,5 @@ --- -description: Navigate traceability links between requirements, specifications, implementations, tests, and code in any direction. +description: Use when navigating traceability links between requirements, specifications, implementations, tests, and code in a sphinx-needs project handoffs: - label: Analyze Impact agent: pharaoh.change diff --git a/.github/agents/pharaoh.use-case-diagram-draft.agent.md b/.github/agents/pharaoh.use-case-diagram-draft.agent.md index 59255eb..a32fd11 100644 --- a/.github/agents/pharaoh.use-case-diagram-draft.agent.md +++ b/.github/agents/pharaoh.use-case-diagram-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Draft a single use-case diagram for one feat — actors, use cases, system boundary. +description: Use when drafting one use-case diagram for a single feat — actors (primary, secondary, external systems), use cases (one per user-facing capability), and system boundary. Renderer-aware (mermaid or plantuml per `.pharaoh/project/diagram-conventions.yaml`). First concrete `*-diagram-draft` skill — others follow the same shape. handoffs: [pharaoh.diagram-review] --- # @pharaoh.use-case-diagram-draft -Draft a single use-case diagram for one feat — actors, use cases, system boundary. +Use when drafting one use-case diagram for a single feat — actors (primary, secondary, external systems), use cases (one per user-facing capability), and system boundary. Renderer-aware (mermaid or plantuml per `.pharaoh/project/diagram-conventions.yaml`). First concrete `*-diagram-draft` skill — others follow the same shape. -See [`skills/pharaoh-use-case-diagram-draft/SKILL.md`](../../skills/pharaoh-use-case-diagram-draft/SKILL.md) for the full atomic specification. +See [`skills/pharaoh-use-case-diagram-draft/SKILL.md`](../../skills/pharaoh-use-case-diagram-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.verify.agent.md b/.github/agents/pharaoh.verify.agent.md new file mode 100644 index 0000000..f02b890 --- /dev/null +++ b/.github/agents/pharaoh.verify.agent.md @@ -0,0 +1,19 @@ +--- +description: Use when checking whether one sphinx-needs artefact actually addresses the substance of every parent it links to via :satisfies: or :verifies:. Cross-need content check — distinct from structural MECE, schema-level tailor-review, and per-axis req-review/arch-review. +handoffs: + - label: MECE Check + agent: pharaoh.mece + prompt: Run a structural gap-and-orphan analysis around the verified need + - label: Trace the Need + agent: pharaoh.trace + prompt: Trace the verified need through every link type + - label: Re-author the Need + agent: pharaoh.author + prompt: Revise the body to address the missing parent claims +--- + +# @pharaoh.verify + +Use when checking whether one sphinx-needs artefact actually addresses the substance of every parent it links to via :satisfies: or :verifies:. Cross-need content check — distinct from structural MECE, schema-level tailor-review, and per-axis req-review/arch-review. + +See [`skills/pharaoh-verify/SKILL.md`](../../skills/pharaoh-verify/SKILL.md) for the full atomic specification — inputs, scoring scale, and composition patterns. diff --git a/.github/agents/pharaoh.vplan-draft.agent.md b/.github/agents/pharaoh.vplan-draft.agent.md index 2b1b828..24c2d1f 100644 --- a/.github/agents/pharaoh.vplan-draft.agent.md +++ b/.github/agents/pharaoh.vplan-draft.agent.md @@ -1,10 +1,10 @@ --- -description: Draft a single sphinx-needs test-case (verification plan item) for one requirement. +description: Use when drafting a single sphinx-needs test-case (verification plan item) for one requirement. The artefact type is parameterised via `target_level` (any catalog-declared verification-plan / test-case type — e.g. `tc`, `test`, `vplan`). Emits an RST directive with inputs, steps, and expected outcome, linking to the parent req via `:verifies:`. handoffs: [] --- # @pharaoh.vplan-draft -Draft a single sphinx-needs test-case (verification plan item) for one requirement. +Use when drafting a single sphinx-needs test-case (verification plan item) for one requirement. The artefact type is parameterised via `target_level` (any catalog-declared verification-plan / test-case type — e.g. `tc`, `test`, `vplan`). Emits an RST directive with inputs, steps, and expected outcome, linking to the parent req via `:verifies:`. See [`skills/pharaoh-vplan-draft/SKILL.md`](../../skills/pharaoh-vplan-draft/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.vplan-review.agent.md b/.github/agents/pharaoh.vplan-review.agent.md index af3d327..e01ddbf 100644 --- a/.github/agents/pharaoh.vplan-review.agent.md +++ b/.github/agents/pharaoh.vplan-review.agent.md @@ -1,10 +1,10 @@ --- -description: Audit a single test case against ISO 26262-8 §6 axes plus vplan-specific axes. +description: Use when auditing a single test case against ISO 26262-8 §6 axes plus vplan-specific axes (coverage of parent req, completeness of steps, clarity of expected outcome). Emits structured findings JSON. handoffs: [] --- # @pharaoh.vplan-review -Audit a single test case against ISO 26262-8 §6 axes plus vplan-specific axes. +Use when auditing a single test case against ISO 26262-8 §6 axes plus vplan-specific axes (coverage of parent req, completeness of steps, clarity of expected outcome). Emits structured findings JSON. See [`skills/pharaoh-vplan-review/SKILL.md`](../../skills/pharaoh-vplan-review/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/agents/pharaoh.write-plan.agent.md b/.github/agents/pharaoh.write-plan.agent.md index 934c18d..a9584a4 100644 --- a/.github/agents/pharaoh.write-plan.agent.md +++ b/.github/agents/pharaoh.write-plan.agent.md @@ -1,10 +1,10 @@ --- -description: Use when you have an intent (e. +description: Use when you have an intent (e.g. "reverse-engineer features and reqs from this module") and need a concrete plan.yaml that pharaoh-execute-plan can run. Picks a plan template by intent, fills project-specific values, emits a plan that validates against schema.md. Does NOT execute anything. handoffs: [] --- # @pharaoh.write-plan -Use when you have an intent (e. +Use when you have an intent (e.g. "reverse-engineer features and reqs from this module") and need a concrete plan.yaml that pharaoh-execute-plan can run. Picks a plan template by intent, fills project-specific values, emits a plan that validates against schema.md. Does NOT execute anything. See [`skills/pharaoh-write-plan/SKILL.md`](../../skills/pharaoh-write-plan/SKILL.md) for the full atomic specification — inputs, outputs, atomicity contract, and composition patterns. diff --git a/.github/prompts/pharaoh.author.prompt.md b/.github/prompts/pharaoh.author.prompt.md index f8a06dd..1234b39 100644 --- a/.github/prompts/pharaoh.author.prompt.md +++ b/.github/prompts/pharaoh.author.prompt.md @@ -1,3 +1,23 @@ --- agent: pharaoh.author --- + +# /pharaoh.author + +Author or modify one sphinx-needs artefact — a requirement, an architecture element, a test +case, or a decision — by routing to the right atomic drafting skill based on the project's +artefact catalog. One invocation produces one drafted RST directive with an ID, a parent link, +and a suggested file placement. + +Hand the agent: + +- the **target type** (e.g. `req`, `arch`, `tc`, `decision`), +- a short **draft seed** describing what to author, +- the **parent link** the new artefact will trace to (need-id), and +- any type-specific extras the dispatched drafter needs (e.g. `arch_type`, + `verification_level`). + +The agent picks the matching atomic drafter (`pharaoh-req-draft`, `pharaoh-arch-draft`, +`pharaoh-vplan-draft`, or `pharaoh-decide`), forwards the inputs, and returns the drafted RST +directive plus an authoring summary. Run `@pharaoh.verify` next to check the new artefact +against the substance of its parent. diff --git a/.github/prompts/pharaoh.verify.prompt.md b/.github/prompts/pharaoh.verify.prompt.md index 1726175..57d5ee9 100644 --- a/.github/prompts/pharaoh.verify.prompt.md +++ b/.github/prompts/pharaoh.verify.prompt.md @@ -1,3 +1,22 @@ --- agent: pharaoh.verify --- + +# /pharaoh.verify + +Check whether one sphinx-needs artefact actually addresses the substance of every parent it +links to via `:satisfies:` or `:verifies:`. This is a cross-need content check — distinct from +structural MECE (`@pharaoh.mece`), schema-level tailoring review (`@pharaoh.tailor-review`), +and per-axis prose review (`@pharaoh.req-review`, `@pharaoh.arch-review`, +`@pharaoh.vplan-review`). + +Hand the agent: + +- the **need-id** to verify, and +- optionally `transitive: true` to walk the full parent chain rather than just direct parents. + +The agent reads `needs.json`, walks the parent links, scores each (child, parent) pair on a +0-3 ordinal for substantive coverage, and returns a JSON document with per-pair verdicts and +concrete missing aspects. Use the result to decide whether to re-author the body via +`@pharaoh.author`, regenerate it per-axis via `@pharaoh.req-regenerate`, or move on to a +corpus-wide check with `@pharaoh.mece`. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5eca926..fd61e50 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -85,6 +85,28 @@ jobs: status=1 fi + # Detect truncation artefacts in description: unbalanced parens, + # brackets, or backticks render as broken Markdown in Copilot UIs + # (see issue #12 — pharaoh.write-plan and pharaoh.toctree-emit). + description=$(echo "$frontmatter" | sed -n 's/^description:[[:space:]]*//p') + opens=$(echo -n "$description" | tr -cd '(' | wc -c) + closes=$(echo -n "$description" | tr -cd ')' | wc -c) + if [ "$opens" -ne "$closes" ]; then + echo "ERROR: $agent_file 'description' has unbalanced parentheses ($opens '(' vs $closes ')')" + status=1 + fi + obrack=$(echo -n "$description" | tr -cd '[' | wc -c) + cbrack=$(echo -n "$description" | tr -cd ']' | wc -c) + if [ "$obrack" -ne "$cbrack" ]; then + echo "ERROR: $agent_file 'description' has unbalanced brackets ($obrack '[' vs $cbrack ']')" + status=1 + fi + ticks=$(echo -n "$description" | tr -cd '`' | wc -c) + if [ $((ticks % 2)) -ne 0 ]; then + echo "ERROR: $agent_file 'description' has unbalanced backticks ($ticks total)" + status=1 + fi + echo "OK: $agent_file" done exit $status diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e83b66..f9fb167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Migration + +- `id-conventions.yaml`: rename `id_regex_by_type:` to `id_regex_exceptions:` to + match the canonical schema. Existing tailoring with the old key name will fail + pharaoh-tailor-review C-rule validation. +- `id-conventions.yaml` `prefixes:` value form: values must be literal identifier + prefix tokens (matching pattern `^[A-Za-z][A-Za-z0-9_]*$`), not human-readable + descriptions. Existing tailoring with description-style values will fail schema + validation. +- `artefact-catalog.yaml`: drop `child_of:` and `lifecycle_ref:` per type if + present (schema's `additionalProperties: false` now rejects them). +- `artefact-catalog.yaml` release-gate fields (`required_links`, + `required_metadata_fields`, `required_roles`): pharaoh-tailor-review rule C6 + now surfaces a finding (severity: warning, not error) when these keys are + absent on a per-type entry. Existing projects without these fields previously + validated cleanly; after this change they will see new C6 findings. The + `overall` value remains `warnings_only` in that case — no CI gate that + treats warnings as non-blocking will break. Migrate by populating the + required-* fields per type using sensible project-specific defaults; consult + `schemas/artefact-catalog.schema.json` and `pharaoh-tailor-fill` Step 5 for + guidance. An explicit empty array (`[]`) is accepted and declares "no + requirement". + ### Removed - **pharaoh-author** -- monolithic requirement-authoring skill, replaced by the atomic chain below. - **pharaoh-verify** -- monolithic requirement-review skill, replaced by the atomic chain below. - Empirical justification: Phase-1 pilot (pharaoh-validation `runs/phase1-*/FINDINGS.md`) and Phase-2 mini-pilot (pharaoh-validation `runs/phase2-1776446795/FINDINGS.md`) showed the atomic chain achieves A_exec 0.79 vs 0.15 for the monolith (+0.641 delta). + Rationale: the atomic chain enforces per-axis review and per-artefact drafting boundaries, so each step has an isolated scope, deterministic inputs/outputs, and is independently testable. The previous monolithic skills bundled drafting and review in one prompt, blurring atomicity and producing weaker per-axis findings. ### Added diff --git a/examples/score/.pharaoh/project/artefact-catalog.yaml b/examples/score/.pharaoh/project/artefact-catalog.yaml index 82ec7f3..f8c349c 100644 --- a/examples/score/.pharaoh/project/artefact-catalog.yaml +++ b/examples/score/.pharaoh/project/artefact-catalog.yaml @@ -5,24 +5,40 @@ gd_req: # "required" means "should be present in well-formed needs" — not "100% present in corpus". optional_fields: [complies, tags, rationale, verification] lifecycle: [draft, valid, inspected] + required_links: [satisfies] + optional_links: [complies, verification] + required_metadata_fields: [status] + required_roles: [] wp: required_fields: [id, status] # NOTE: wp needs do NOT carry a satisfies field (0/74 in corpus). Plan specified # satisfies as required but real data contradicts this; removed from required_fields. # wp needs are linked to wf via input_back/output_back back-links, not satisfies. optional_fields: [tags, complies] + required_links: [] + optional_links: [complies] + required_metadata_fields: [status] + required_roles: [] wf: required_fields: [id, status, input, output, responsible] # NOTE: wf needs do NOT carry a satisfies field (0/79) and do NOT use rasic (0/79). # Plan specified satisfies as required and rasic as optional — both removed/corrected. # Actual wf fields used: input, output, responsible, approved_by, supported_by, has, contains. optional_fields: [tags, approved_by, supported_by, has, contains] + required_links: [input, output] + optional_links: [has, contains, supported_by] + required_metadata_fields: [status, responsible] + required_roles: [responsible] arch: required_fields: [id, status, satisfies, type] # type: one of module | component | interface # satisfies: links to parent requirement (gd_req or equivalent) optional_fields: [tags, rationale, description] lifecycle: [draft, valid, inspected] + required_links: [satisfies] + optional_links: [] + required_metadata_fields: [status, type] + required_roles: [] tc: required_fields: [id, status, verifies] # verifies: links to parent requirement or arch element. @@ -32,3 +48,7 @@ tc: optional_fields: [tags, rationale, level] required_body_sections: [Inputs, Steps, Expected] lifecycle: [draft, valid, inspected] + required_links: [verifies] + optional_links: [] + required_metadata_fields: [status] + required_roles: [] diff --git a/examples/score/.pharaoh/project/id-conventions.yaml b/examples/score/.pharaoh/project/id-conventions.yaml index 328b13a..a411c01 100644 --- a/examples/score/.pharaoh/project/id-conventions.yaml +++ b/examples/score/.pharaoh/project/id-conventions.yaml @@ -1,12 +1,15 @@ # examples/score/.pharaoh/project/id-conventions.yaml +# Values are the literal identifier-prefix strings prepended to the local-part +# to form an id (e.g. gd_req__abs_pump_activation). Human descriptions of each +# prefix live in artefact-catalog.yaml entries, not here. prefixes: - gd_req: requirement (guide-level) - wp: work product - wf: workflow - std_req: external standard requirement (ISO/ASPICE) - gd_chklst: checklist - arch: architecture - tc: test case + gd_req: gd_req + wp: wp + wf: wf + std_req: std_req + gd_chklst: gd_chklst + arch: arch + tc: tc # NOTE: std_req IDs embed source-standard codes that may contain uppercase and hyphens, # e.g. std_req__aspice_40__MAN-3-BP1. The regex below applies to all other prefixes; # std_req is intentionally exempt because the local-part mirrors upstream identifier diff --git a/pharaoh.toml.example b/pharaoh.toml.example index aec78dd..8afe984 100644 --- a/pharaoh.toml.example +++ b/pharaoh.toml.example @@ -1,6 +1,11 @@ # Pharaoh configuration # Copy to pharaoh.toml and adjust to your project needs. # All settings are optional. Without this file, advisory mode applies. +# +# This file is the canonical source of truth for default values consumed by +# Pharaoh skills. Other skills (e.g. pharaoh-gate-advisor, the shared +# strictness contract in shared/strictness.md) defer to the values declared +# here rather than redeclaring their own defaults. [pharaoh] # "advisory" (default) - suggests workflow but never blocks @@ -14,6 +19,14 @@ pattern = "{TYPE}-{MODULE}-{NUMBER}" auto_increment = true [pharaoh.workflow] +# Lifecycle stage of the project. Read by pharaoh-setup to choose between +# descriptive (existing-project) and prescriptive (new-project) defaults. +# "reverse-eng": existing codebase; setup captures what already exists. +# Workflow gates start permissive and tighten over time. +# "greenfield": new project; setup imposes Pharaoh defaults from day one. +# "steady-state": mature catalogue (≥10 needs); full gating in effect. +mode = "reverse-eng" + # Gate-enablement ladder — see skills/shared/gate-enablement.md for rationale. # Bootstrap ships step 1 (require_verification) on by default; projects enable # the other steps as the pre-work for each lands. @@ -36,3 +49,58 @@ required_links = [ [pharaoh.codelinks] # Follow sphinx-codelinks in change analysis enabled = true +# Project-relative path containing source files to scan when resolving +# sphinx-codelinks comments. Consumed by pharaoh-write-plan and +# pharaoh-feat-file-map. If unset, the skills fall back to the +# sphinx-codelinks `[source_discover].src_dir` from `ubproject.toml`, then to +# the project root. +src_dir = "src" + +[pharaoh.codelink_comments] +# How code-anchored requirements are written into source files. Consumed by +# pharaoh-req-codelink-annotate and pharaoh-req-from-code; the latter branches +# on `mode` to decide between emitting an RST directive or a one-line comment. +# "backref": source file gets a minimal `# @req REQ_ID: title` pointer; +# the need itself lives in an RST file. +# "codelinks": source file carries the full sphinx-codelinks one-line form +# `# @ title, id, type, [links]`; the comment IS the need. +mode = "backref" +# `backref` mode only — the comment marker used for grep and the line template. +prefix = "@req" +format = "{prefix} {id}: {title}" + +[pharaoh.diagrams] +# Default renderer for diagrams emitted by *-diagram-draft skills. +# Allowed: "mermaid", "plantuml". Per-type override via [pharaoh.diagrams.]. +# See skills/shared/diagram-tailoring.md for the resolution order. +renderer = "mermaid" +# Optional: gates pharaoh-mece and future CI skills on diagram coverage. +# Diagram-draft skills themselves do NOT consult this list; they emit what the +# caller asks for. +# required = ["component", "sequence"] + +# Per-diagram-type overrides. Omit a [pharaoh.diagrams.] block to use +# [pharaoh.diagrams].renderer. Allowed type keys: component, sequence, class, +# state, activity, use_case, block, deployment, fault_tree. +[pharaoh.diagrams.component] +# direction = "TB" # TB | LR | BT | RL +# renderer = "mermaid" + +[pharaoh.diagrams.sequence] +# renderer = "plantuml" # PlantUML sequence diagrams are richer than Mermaid + +[pharaoh.diagrams.type_styles] +# Visual styling overrides applied per need-type. Map of need-type to inline +# table; renderer-specific values translated by each diagram skill (e.g. +# Mermaid classDef, PlantUML skinparam). Read by *-diagram-draft skills when +# emitting typed nodes; absent → renderer defaults (no styling). +# feat = { shape = "stadium", color = "#4ECDC4" } +# comp_req = { shape = "rect", color = "#BFD8D2" } +# arch = { shape = "hexagon", color = "#F7B2B7" } + +[pharaoh.quality_gate] +# Enables strict-mode checks across quality skills. When true, +# pharaoh-diagram-lint upgrades parser warnings to errors. Other quality +# skills may consult this flag for their own strict-mode behavior; per-skill +# semantics live in the relevant SKILL.md. +strict = false diff --git a/schemas/README.md b/schemas/README.md new file mode 100644 index 0000000..1ebfe70 --- /dev/null +++ b/schemas/README.md @@ -0,0 +1,24 @@ +# Pharaoh tailoring schemas + +JSON Schemas (Draft 2020-12) for the four tailoring files Pharaoh +authors and consumes: + +| File | Validates | Authored by | Consumed by | +|---------------------------------------|--------------------------------------------|---------------------------------------|------------------------------------------------| +| `artefact-catalog.schema.json` | `.pharaoh/project/artefact-catalog.yaml` | `pharaoh-tailor-bootstrap`, `pharaoh-tailor-fill` | `pharaoh-tailor-review`, `pharaoh-link-completeness-check`, `pharaoh-output-validate`, `pharaoh-review-completeness`, `pharaoh-quality-gate` | +| `workflows.schema.json` | `.pharaoh/project/workflows.yaml` | `pharaoh-tailor-bootstrap`, `pharaoh-tailor-fill` | `pharaoh-tailor-review`, `pharaoh-lifecycle-check`, `pharaoh-status-lifecycle-check` | +| `id-conventions.schema.json` | `.pharaoh/project/id-conventions.yaml` | `pharaoh-tailor-bootstrap`, `pharaoh-tailor-fill` | `pharaoh-tailor-review`, `pharaoh-id-convention-check`, `pharaoh-id-allocate` | +| `checklists-frontmatter.schema.json` | `.pharaoh/project/checklists/*.md` (frontmatter only) | `pharaoh-tailor-bootstrap`, `pharaoh-tailor-fill` | `pharaoh-tailor-review` | + +`pharaoh-tailor-review` resolves the schema set in this order: + +1. Explicit `schemas_dir` argument from the caller. +2. `/schemas/` if present in the project (per-project overrides). +3. The Pharaoh-shipped `schemas/` directory (this folder). +4. Built-in structural rules (degraded mode — emits a warning). + +Per-project overrides may add fields, never remove required ones. + +To extend: add a property to the schema, then update the matching emitter (`pharaoh-tailor-bootstrap` or `pharaoh-tailor-fill`) to populate it. Cross-file referential checks (every lifecycle state in artefact-catalog must appear in workflows; every prefix in artefact-catalog must appear in id-conventions) are enforced by `pharaoh-tailor-review` as cross-file rules C1-C6, not by JSON Schema. + +The four release-gate fields on each per-type entry of `artefact-catalog.yaml` (`required_links`, `optional_links`, `required_metadata_fields`, `required_roles`) are all optional in the schema but their absence is surfaced as a finding by `pharaoh-tailor-review` rule C6 — empty arrays declare an explicit "no requirement" choice, missing keys mean the project never decided. Consumers (`pharaoh-link-completeness-check`, `pharaoh-output-validate`, `pharaoh-review-completeness`) treat absent keys as empty so a project with none of these fields ships a silent no-op release gate; rule C6 is what makes the choice explicit. diff --git a/examples/score/.pharaoh/project/schemas/artefact-catalog.schema.json b/schemas/artefact-catalog.schema.json similarity index 52% rename from examples/score/.pharaoh/project/schemas/artefact-catalog.schema.json rename to schemas/artefact-catalog.schema.json index a8a07f0..3cd8ef2 100644 --- a/examples/score/.pharaoh/project/schemas/artefact-catalog.schema.json +++ b/schemas/artefact-catalog.schema.json @@ -47,6 +47,42 @@ "minLength": 1 }, "uniqueItems": true + }, + "required_links": { + "type": "array", + "description": "Link-relation names that every need of this type must declare with a non-empty target list. Enforced at release by pharaoh-link-completeness-check (and aggregated by pharaoh-quality-gate via the link_types_covered invariant). Empty array explicitly disables the check for this type; absent key is treated as empty.", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "optional_links": { + "type": "array", + "description": "Link-relation names that may be declared on a need of this type. Read by pharaoh-link-completeness-check for completeness reporting. Must not overlap with required_links (enforced by pharaoh-tailor-review).", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "required_metadata_fields": { + "type": "array", + "description": "sphinx-needs option keys that must be set with non-empty values before release. Enforced by pharaoh-output-validate in graph mode (delegated by pharaoh-quality-gate via the metadata_fields_present invariant). Empty array explicitly disables the check for this type; absent key is treated as empty.", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "required_roles": { + "type": "array", + "description": "Role-bearing option keys that must be set with non-empty values before release (e.g. reviewer, approved_by). Enforced by pharaoh-review-completeness. Empty array explicitly disables the check for this type; absent key is treated as no review/approval requirement.", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true } }, "additionalProperties": false diff --git a/examples/score/.pharaoh/project/schemas/checklists-frontmatter.schema.json b/schemas/checklists-frontmatter.schema.json similarity index 100% rename from examples/score/.pharaoh/project/schemas/checklists-frontmatter.schema.json rename to schemas/checklists-frontmatter.schema.json diff --git a/examples/score/.pharaoh/project/schemas/id-conventions.schema.json b/schemas/id-conventions.schema.json similarity index 76% rename from examples/score/.pharaoh/project/schemas/id-conventions.schema.json rename to schemas/id-conventions.schema.json index c303ac9..df6c441 100644 --- a/examples/score/.pharaoh/project/schemas/id-conventions.schema.json +++ b/schemas/id-conventions.schema.json @@ -8,10 +8,11 @@ "properties": { "prefixes": { "type": "object", - "description": "Map of prefix token (e.g. gd_req) to human-readable description.", + "description": "Map from prefix key (e.g. feat, gd_req) to the literal identifier-prefix string that is prepended to the local-part to form an id (e.g. FEAT_, gd_req). Values must be identifier-shaped tokens, not human descriptions — they are consumed by pharaoh-id-allocate and pharaoh-id-convention-check.", "minProperties": 1, "additionalProperties": { "type": "string", + "pattern": "^[A-Za-z][A-Za-z0-9_]*$", "minLength": 1 } }, diff --git a/examples/score/.pharaoh/project/schemas/workflows.schema.json b/schemas/workflows.schema.json similarity index 100% rename from examples/score/.pharaoh/project/schemas/workflows.schema.json rename to schemas/workflows.schema.json diff --git a/skills/pharaoh-arch-draft/SKILL.md b/skills/pharaoh-arch-draft/SKILL.md index cc7c4fe..58bead7 100644 --- a/skills/pharaoh-arch-draft/SKILL.md +++ b/skills/pharaoh-arch-draft/SKILL.md @@ -1,6 +1,6 @@ --- name: pharaoh-arch-draft -description: Use when drafting a single sphinx-needs architecture element (component / interface / module) from one parent requirement. Emits an RST directive block linking back to the parent via :satisfies:. +description: Use when drafting a single sphinx-needs architecture element from one parent requirement. The artefact type is parameterised via `target_level` (any catalog-declared architecture type — e.g. `arch`, `swarch`, `sys-arch`, `module`, `component`, `interface`). Emits an RST directive block linking back to the parent via `:satisfies:`. chains_from: [pharaoh-req-draft, pharaoh-req-regenerate] chains_to: [pharaoh-arch-review] --- @@ -10,8 +10,10 @@ chains_to: [pharaoh-arch-review] ## When to use Invoke when the user has a validated requirement (ideally reviewed by `pharaoh-req-review`) and -wants to derive one architecture element from it. Target element types: `component`, `module`, -or `interface`. +wants to derive one architecture element from it. The element's directive name and ID prefix +come from the project's `artefact-catalog.yaml` / `id-conventions.yaml`; this skill is +type-agnostic and supports any architecture-shaped type the catalog declares +(`arch`, `swarch`, `sys-arch`, `module`, `component`, `interface`, …). Do NOT draft multiple architecture elements in a single invocation — one element per call. Do NOT create architecture elements without a parent requirement — every arch element must trace @@ -23,12 +25,16 @@ Do NOT review — use `pharaoh-arch-review` after drafting. ## Inputs - **parent_req_id** (from user): need-id of the parent requirement — must exist in needs.json -- **arch_type** (from user): one of `module`, `component`, or `interface` +- **target_level** (from user): the artefact-catalog type name to emit. Any type declared in + `.pharaoh/project/artefact-catalog.yaml` is accepted (typical examples: `arch`, `swarch`, + `sys-arch`, `module`, `component`, `interface`). The emitted directive uses `target_level` + verbatim as the directive name; the ID prefix is resolved from the catalog / id-conventions. - **element_description** (from user): 1-3 sentences describing the element's responsibility - **tailoring** (from `.pharaoh/project/`): - - `artefact-catalog.yaml` — look up the `arch` entry if it exists; fall back to placeholder - prefix `arch__` if the entry is absent - - `id-conventions.yaml` — prefix, separator, id_regex + - `artefact-catalog.yaml` — look up the entry for `target_level` to read `required_fields`, + `optional_fields`, and `lifecycle` + - `id-conventions.yaml` — `prefixes` map (key = type name → value = identifier prefix + string), `separator`, `id_regex` - **needs.json**: required for parent resolution and ID uniqueness > Note: A `shared/tailoring-access.md` helper module is planned. Until it exists, Steps 1-2 below @@ -41,11 +47,12 @@ Do NOT review — use `pharaoh-arch-review` after drafting. A single RST directive block for the architecture element, containing: -- Unique ID using the project's arch prefix (from artefact-catalog `arch` entry) or `arch__` if - no entry exists +- Unique ID using the prefix resolved for `target_level` from `id-conventions.yaml` - `:status: draft` - `:satisfies:` pointing to parent_req_id -- `:type:` set to the requested arch_type (`module` / `component` / `interface`) +- Every field listed in the catalog entry's `required_fields` (the directive name itself + carries the type, so a separate `:type:` option is only emitted when the catalog entry + declares it as required) - Body: 1-3 sentences describing the element's responsibility; no `shall` — architecture elements state what something *is*, not what it *shall do* (requirements do that) @@ -57,34 +64,34 @@ A single RST directive block for the architecture element, containing: **1a. `artefact-catalog.yaml`** -Look up the `arch` entry. If found, read: -- `required_fields` — fields that must be present +Look up the entry whose key equals `target_level`. If found, read: + +- `required_fields` — fields that must be present in the emitted directive - `optional_fields` — fields that may be added - `lifecycle` — valid `:status:` values -If the `arch` entry does not exist (likely for Score until the catalog extension commit), use these -defaults: -- `required_fields`: `[id, status, satisfies, type]` -- `optional_fields`: `[tags, rationale, description]` -- `lifecycle`: `[draft, valid, inspected]` +If the entry is absent, FAIL: -Note the fallback in output if defaults were applied. +``` +FAIL: target_level "" is not declared in .pharaoh/project/artefact-catalog.yaml. +Add an entry for "" (with required_fields, optional_fields, lifecycle) before +drafting, or pass a target_level that is already declared. +``` **1b. `id-conventions.yaml`** -Extract `separator` and `id_regex`. Determine the arch prefix: -- If artefact-catalog has an `arch` entry with a prefix key, use it -- Otherwise use `arch__` (two underscores, matching Score id convention) - -**1c. Validate arch_type** +Read the `prefixes:` map and look up the prefix for `target_level`. Also extract +`separator` and `id_regex`. -Accepted values: `module`, `component`, `interface`. If the user supplies a different value, FAIL: +If `prefixes` does not declare `target_level`, FAIL: ``` -FAIL: arch_type "" is not recognised. -Accepted values: module, component, interface. +FAIL: id-conventions.yaml prefixes map has no entry for "". +Declare a prefix for "" (e.g. SWARCH_) before drafting. ``` +The resolved prefix is the value of `prefixes[target_level]`. + --- ### Step 2: Locate and parse needs.json @@ -124,23 +131,22 @@ Architecture elements should trace to requirements. Proceeding at user's discret **4a. Derive local-ID part** -Format: `` where local is derived from `element_description`: +Format: `` where `` is the value resolved in Step 1b. The local part +is derived from `element_description`: + - Lowercase, words separated by underscores - Maximum 5 words; trim articles, prepositions, conjunctions - Example: "Power management module for ECU startup" → local `power_management_module` -Prepend arch_type as first word if the local part does not already imply the type: -- `module` → local starts with `mod_` if not already -- `component` → no additional prefix (component is the default) -- `interface` → local starts with `if_` if not already - **4b. Check uniqueness** -Candidate = ``. If already in needs.json ID set, append `_2`, `_3`, etc. +Candidate = `` (or `` if `id-conventions.yaml` +declares an explicit separator distinct from the prefix's trailing punctuation). +If the candidate is already in the needs.json ID set, append `_2`, `_3`, etc. **4c. Validate against id_regex** -If the candidate does not match, FAIL: +If the candidate does not match the `id_regex` declared in `id-conventions.yaml`, FAIL: ``` FAIL: generated ID "" does not match id_regex "". @@ -152,6 +158,7 @@ Revise element_description to use lowercase ASCII words. ### Step 5: Draft the element body Write 1-3 sentences describing: + 1. What the element *is* (its role in the system) 2. What it contains or depends on (if known from parent req) 3. Its boundary (what it does NOT include) — only if the parent req implies a clear scope limit @@ -199,22 +206,16 @@ Manual correction required before running pharaoh-arch-review. ### Step 7: Emit the directive block ```rst -.. arch:: +.. :: :id: :status: draft :satisfies: - :type: <1-3 sentence description> ``` -If the tailoring fallback was applied (no `arch` entry in catalog), append: - -``` -[NOTE] artefact-catalog.yaml has no 'arch' entry. Prefix 'arch__' and default required fields -[id, status, satisfies, type] were used. Run the catalog extension commit or add an 'arch' entry -to .pharaoh/project/artefact-catalog.yaml before promoting this element beyond draft. -``` +Add any catalog-declared `required_fields` not already shown above (the catalog is the source +of truth — emit every field it lists). --- @@ -229,9 +230,11 @@ If parent_req_id is absent from needs.json, FAIL immediately (Step 3 handles thi If element_description covers more than one distinct concern, FAIL (Step 5 handles this). Do not silently draft a compound element. -**G3 — arch_type not recognised** +**G3 — target_level not declared** -If arch_type is not `module`, `component`, or `interface`, FAIL (Step 1c handles this). +If `target_level` is not declared in `artefact-catalog.yaml` or has no entry in +`id-conventions.yaml`'s `prefixes` map, FAIL (Step 1 handles this). Do not silently fall +back to a hardcoded default — the catalog is the contract. **G4 — needs.json unavailable** @@ -254,11 +257,11 @@ Do not show this if the emit included a `[DIAGNOSTIC]`. ## Worked example **User input:** -> Parent: `gd_req__abs_pump_activation`; type: `component`; description: "Manages the ABS pump -> drive circuit, including PWM duty-cycle control and over-current protection." +> Parent: `gd_req__abs_pump_activation`; target_level: `arch`; description: "Manages the ABS +> pump drive circuit, including PWM duty-cycle control and over-current protection." -**Step 1:** No `arch` entry found in artefact-catalog.yaml. Falling back to defaults: prefix -`arch__`, required `[id, status, satisfies, type]`. arch_type `component` is valid. +**Step 1:** `artefact-catalog.yaml` has an `arch` entry with `required_fields: +[id, status, satisfies]`. `id-conventions.yaml` `prefixes` map has `arch: arch__`. **Step 2:** needs.json found at `docs/_build/needs/needs.json`; 185 IDs loaded. @@ -278,22 +281,23 @@ needs.json. Passes id_regex `^[a-z][a-z_]*__[a-z0-9_]+$`. ID assigned. :id: arch__abs_pump_driver :status: draft :satisfies: gd_req__abs_pump_activation - :type: component The ABS pump driver component manages the pump drive circuit, controlling output PWM duty cycle and providing over-current protection for the pump motor. ``` ``` -[NOTE] artefact-catalog.yaml has no 'arch' entry. Prefix 'arch__' and default required fields -[id, status, satisfies, type] were used. Run the catalog extension commit or add an 'arch' entry -to .pharaoh/project/artefact-catalog.yaml before promoting this element beyond draft. - Consider running `pharaoh-arch-review arch__abs_pump_driver` to audit against ISO 26262-8 §6 axes. ``` +For a project that distinguishes system-level and software-level architecture, the same skill +serves both — pass `target_level: sys-arch` to draft a system architecture element, or +`target_level: swarch` for a software architecture element. The directive name and prefix come +from the project's catalog and id-conventions; nothing in this skill is hardcoded to the three +classical names `module` / `component` / `interface`. + ## Last step -After emitting the artefact, invoke `pharaoh-arch-review` on it. Pass the emitted artefact (or its `need_id`) as `target`. Attach the returned review JSON to the skill's output under the key `review`. If the review emits any axis with `score: 0` or `severity: critical`, return a non-success status with the review findings verbatim and do NOT finalize the artefact — the caller must regenerate (via `pharaoh-arch-regenerate` if available, or by re-invoking this skill with the findings as input). +After emitting the artefact, invoke `pharaoh-arch-review` on it. Pass the emitted artefact (or its `need_id`) as `target`. Attach the returned review JSON to the skill's output under the key `review`. If the review emits any axis with `score: 0` or `severity: critical`, return a non-success status with the review findings verbatim and do NOT finalize the artefact — the caller must address the action items and re-invoke this skill with the revised target as input. See [`shared/self-review-invariant.md`](../shared/self-review-invariant.md) for the rationale and enforcement mechanism. Coverage is mechanically enforced by `pharaoh-self-review-coverage-check` in `pharaoh-quality-gate`. diff --git a/skills/pharaoh-arch-review/SKILL.md b/skills/pharaoh-arch-review/SKILL.md index 6b3f3cd..3561758 100644 --- a/skills/pharaoh-arch-review/SKILL.md +++ b/skills/pharaoh-arch-review/SKILL.md @@ -1,7 +1,7 @@ --- name: pharaoh-arch-review description: Use when auditing a single architecture element against the 10 ISO 26262-8 §6 axes plus arch-specific axes (traceability back to requirement). Emits structured findings JSON. -chains_from: [pharaoh-arch-draft, pharaoh-arch-regenerate] +chains_from: [pharaoh-arch-draft] chains_to: [pharaoh-req-regenerate] --- @@ -13,7 +13,7 @@ Invoke when the user has a single architecture element (either just drafted by ` or retrieved from needs.json by ID) and wants per-axis inspection against ISO 26262-8 §6. Do NOT review sets of arch elements — each invocation audits exactly one element. -Do NOT re-author or fix — invoke `pharaoh-arch-regenerate` (planned) after reviewing if needed. +Do NOT re-author or fix — emit findings only. Re-authoring is a follow-up step outside this skill's scope. Do NOT audit requirements — use `pharaoh-req-review` for those. --- @@ -89,7 +89,7 @@ In the output JSON, record each as ### Chain-level axis `maintainability` requires observing convergence across regeneration iterations. Record as -`{"score": null, "reason": "chain-level axis — assess after pharaoh-arch-regenerate runs"}`. +`{"score": null, "reason": "chain-level axis — assess after the parent requirement and architecture revisions land"}`. ### `overall` field @@ -199,7 +199,7 @@ elements (score 1), normal engineering effort (score 2), or tightly and clearly Set `completeness`, `external_consistency`, `no_duplication` to `{"score": "deferred", "reason": "set-level axis — assess with pharaoh-arch-set-review"}` and `maintainability` to -`{"score": null, "reason": "chain-level axis — assess after pharaoh-arch-regenerate runs"}`. +`{"score": null, "reason": "chain-level axis — assess after the parent requirement and architecture revisions land"}`. --- @@ -257,7 +257,7 @@ Continue evaluating remaining axes. If `overall` is `"needs_work"` or `"fail"`, append — after the JSON — a single line: ``` -Consider `pharaoh-arch-regenerate ` after addressing action items. +Re-run this review after action items are addressed to confirm the findings are resolved. ``` This is the only prose permitted after the JSON. @@ -310,7 +310,7 @@ This is the only prose permitted after the JSON. "completeness": {"score": "deferred", "reason": "set-level axis — assess with pharaoh-arch-set-review"}, "external_consistency": {"score": "deferred", "reason": "set-level axis — assess with pharaoh-arch-set-review"}, "no_duplication": {"score": "deferred", "reason": "set-level axis — assess with pharaoh-arch-set-review"}, - "maintainability": {"score": null, "reason": "chain-level axis — assess after pharaoh-arch-regenerate runs"}, + "maintainability": {"score": null, "reason": "chain-level axis — assess after the parent requirement and architecture revisions land"}, "unambiguity_prose": {"score": 3, "reason": "single clear interpretation: manages pump drive circuit"}, "comprehensibility": {"score": 3, "reason": "subject, responsibility, and constraints all explicit"}, "feasibility": {"score": 3, "reason": "standard automotive power electronics function; well-constrained"} diff --git a/skills/pharaoh-author/SKILL.md b/skills/pharaoh-author/SKILL.md new file mode 100644 index 0000000..a30e67f --- /dev/null +++ b/skills/pharaoh-author/SKILL.md @@ -0,0 +1,308 @@ +--- +name: pharaoh-author +description: Use when authoring or modifying a single sphinx-needs artefact (requirement, architecture element, test case, decision) by routing to the matching atomic drafting skill based on the project's artefact catalog. Returns the drafted RST directive with an ID, file placement suggestion, and parent link. +chains_from: [pharaoh-change, pharaoh-plan, pharaoh-spec] +chains_to: [pharaoh-verify] +--- + +# pharaoh-author + +## When to use + +Invoke when the user wants to create or modify one sphinx-needs artefact (one need per call) +and needs the right atomic drafting skill picked for them based on the artefact type. + +This skill is a thin type-router. It does not author content itself — it dispatches to one of +the atomic drafting skills (`pharaoh-req-draft`, `pharaoh-arch-draft`, `pharaoh-vplan-draft`, +`pharaoh-decide`) and forwards their RST output verbatim, plus a file-placement hint and the +parent link. + +Do NOT use when: + +- The user wants the full V-model chain in one call — use `pharaoh-flow`. +- The user wants to draft multiple artefacts at once — invoke this skill once per artefact. +- The user wants to review or verify content — use `pharaoh-req-review`, `pharaoh-arch-review`, + or `pharaoh-verify` instead. + +> This is a compositional orchestrator. The atomicity criterion (a) does not apply: by design +> it dispatches to one atomic skill. Scope is bounded to "one artefact → one drafted directive". + +--- + +## Inputs + +- **target_type** (from user or inferred): the artefact type to draft. Recognised values come + from `.pharaoh/project/artefact-catalog.yaml`. Common values: `req`, `gd_req`, `arch`, + `tc`, `decision`, plus ISO 26262 safety-V types `hazard`, `safety_goal`, `fsr`, `tsr`. + Synonyms are tolerated — e.g. `requirement` → `req`/`gd_req`, `architecture` / `spec` → + `arch`, `test_case` / `verification` → `tc`, `safety_requirement` → `fsr`/`tsr`. +- **target_id** (optional): if the user is modifying an existing need, the need-id to update. + When absent, the dispatched drafter generates a fresh ID. +- **draft_seed** (from user): short prose describing what to author. Forwarded as + `feature_context` / `element_description` / parent claim depending on the dispatch target. +- **parent_link** (from user, required for everything except top-level requirements and + decisions): the need-id this artefact will trace to via `:satisfies:` or `:verifies:`. +- **tailoring** (from `.pharaoh/project/`): + - `artefact-catalog.yaml` — used to resolve `target_type` to a known prefix and confirm a + drafter is available + - `id-conventions.yaml` — read by the dispatched drafter (not by this skill directly) +- **needs.json**: required by every dispatched drafter for parent resolution and ID uniqueness + +--- + +## Outputs + +The drafted RST directive block exactly as produced by the dispatched skill, plus a thin +authoring-summary block: + +``` +=== [ARTEFACT] : === + + +=== [AUTHORING SUMMARY] === +{ + "need_id": "", + "type": "", + "dispatched_skill": "pharaoh-req-draft|pharaoh-arch-draft|pharaoh-vplan-draft|pharaoh-decide", + "parent_link": "", + "file_placement": "", + "stop_reason": null +} +``` + +If the dispatched drafter returns a hard FAIL or `[DIAGNOSTIC]`, forward it verbatim and set +`stop_reason` in the summary. + +--- + +## Process + +### Step 0: Resolve target_type + +Normalise the user-supplied type to a catalog key: + +| User input (any case) | Resolves to | +|---|---| +| `req`, `requirement`, `gd_req`, `comp_req`, `sysreq`, `swreq`, `feat` | the catalog key matching the user's `target_type` exactly when present; otherwise the catalog key whose suffix matches the request and which appears first in `artefact-catalog.yaml`'s declaration order. If two or more catalog keys match equally, FAIL with a clear `ambiguous target_type` error and list the candidates so the caller can resolve | +| `hazard` | `hazard` (catalog key) | +| `safety_goal`, `sg` | `safety_goal` (catalog key) | +| `fsr`, `safety_requirement_functional`, `functional_safety_requirement` | `fsr` (catalog key) | +| `tsr`, `safety_requirement_technical`, `technical_safety_requirement` | `tsr` (catalog key) | +| `arch`, `architecture`, `spec`, `specification`, `module`, `component`, `interface` | `arch` | +| `tc`, `test_case`, `test`, `verification_plan`, `vplan` | `tc` | +| `decision`, `dec`, `adr` | `decision` | + +If the user's input does not map to a key present in `.pharaoh/project/artefact-catalog.yaml`, +emit: + +``` +FAIL: target_type "" is not in the project's artefact catalog. +Catalog keys available: . +``` + +Read `.pharaoh/project/artefact-catalog.yaml` to confirm the resolved key exists. If the +catalog file is missing, fall back to the bundled defaults — `gd_req`, `arch`, `tc` — and note +the fallback in the authoring summary. + +--- + +### Step 1: Select the dispatch skill + +Apply the routing table: + +| Resolved key | Dispatched skill | Notes | +|---|---|---| +| `req`, `gd_req`, `comp_req`, `sysreq`, `swreq`, `feat`, or any key whose suffix matches `req`; ISO 26262 safety-V types (`hazard`, `safety_goal`, `fsr`, `tsr`) | `pharaoh-req-draft` | type-agnostic; `target_level` forwarded verbatim. Safety-V types route here because `pharaoh-req-draft` is the canonical drafter for any requirement-shaped artefact and reads required fields / links / metadata fields from the catalog. | +| any catalog key whose suffix matches `arch` (e.g. `arch`, `swarch`, `sys-arch`) or whose synonym in the Step 0 table resolves to architecture (`module`, `component`, `interface`) | `pharaoh-arch-draft` | type-agnostic; `target_level` forwarded verbatim | +| any catalog key whose suffix matches `tc`, `test`, `vplan`, or `safety_v` | `pharaoh-vplan-draft` | type-agnostic; `target_level` forwarded verbatim | +| `decision` | `pharaoh-decide` | | + +Routing is driven solely by the synonym table in Step 0 plus the suffix-matching rules +above. The artefact-catalog schema does not carry a `category` field on per-type entries +(`additionalProperties: false`), so the router does not read one. Any catalog-declared +type whose key matches one of the suffix patterns above routes correctly without +modification to this skill; types whose keys do not match are caught by Guardrail G2. + +These routing entries were thin passthroughs in the initial `pharaoh-author` commit. This +update reflects the parameterised interfaces of the three drafting skills — +`pharaoh-req-draft`, `pharaoh-arch-draft`, and `pharaoh-vplan-draft` all now accept any +catalog-declared type via `target_level` (no more hardcoded `arch_type ∈ {module, +component, interface}` allow-list, no more hardcoded `tc__` prefix, no more "no drafter for +type X yet" FAIL on safety-V types). The router forwards `target_level` verbatim and lets +the drafter resolve prefix, required fields, required links, and required metadata fields +from `artefact-catalog.yaml` / `id-conventions.yaml`. + +--- + +### Step 2: Forward inputs to the dispatched skill + +Pack a minimal input set per skill and invoke it. Pass through any field the user supplied; +let the dispatched skill apply its own defaults and FAIL when its inputs are insufficient. + +**`pharaoh-req-draft`** + +- `target_level` ← the resolved catalog key from Step 0 (e.g. `gd_req`, `comp_req`, `sysreq`, + `swreq`, `hazard`, `safety_goal`, `fsr`, `tsr`). The drafter looks up the entry in + `artefact-catalog.yaml` and reads `required_fields`, `required_metadata_fields`, and + `required_links`; if the type is missing from the catalog it FAILs with a clear + "type X not declared" message +- `feature_context` ← `draft_seed` +- `parent_link` ← `parent_link` (may be a workflow-id when drafting a top-level requirement) + +**`pharaoh-arch-draft`** + +- `parent_req_id` ← `parent_link` +- `target_level` ← the resolved catalog key from Step 0 (e.g. `arch`, `swarch`, `sys-arch`, + `module`, `component`, `interface`). The drafter looks up the entry in + `artefact-catalog.yaml` and the prefix in `id-conventions.yaml`; if either is missing it + FAILs with a clear "type X not declared" message +- `element_description` ← `draft_seed` + +**`pharaoh-vplan-draft`** + +- `parent_id` ← `parent_link` +- `target_level` ← the resolved catalog key from Step 0 (e.g. `tc`, `test`, `vplan`). The + drafter derives the directive name from `target_level` and the ID prefix from + `id-conventions.yaml`'s `prefixes` map — a project whose `test` type uses prefix `T_` + emits compliant `T_…` IDs without modifying the skill +- `verification_level` ← user-supplied if present (`unit` / `integration` / `system`); the + drafter will FAIL on a missing or unrecognised value + +**`pharaoh-decide`** + +- forward `draft_seed`, the `:decides:` link list (parsed from `parent_link` — comma-separated + is supported), and any `decided_by` / `alternatives` / `rationale` provided by the caller + +If the caller provides additional fields (e.g. `safety_context`, `tags`, `level`), forward +them as-is. The dispatched skill ignores keys it does not recognise. + +--- + +### Step 3: Capture the drafter output + +Capture the full output of the dispatched skill — the RST directive block plus any +`[NOTE]` / `[DIAGNOSTIC]` annotations. + +If the dispatched skill returned a hard FAIL, propagate it verbatim and set +`stop_reason = " FAIL"` in the authoring summary. Do not attempt to fix +the inputs and retry — the caller decides. + +--- + +### Step 4: File placement + +Suggest where to write the new RST directive. The author router does not write files — it +only suggests a path that the caller can use. + +Default placement rules: + +| Dispatched skill | Suggested file | +|---|---| +| `pharaoh-req-draft` | same directory as `parent_link`'s source file; filename matching the project's existing convention (e.g. `requirements.rst`) | +| `pharaoh-arch-draft` | sibling `architecture.rst` in the same directory as `parent_link`'s source | +| `pharaoh-vplan-draft` | `tests/` subdirectory if one exists, else sibling `tests.rst` | +| `pharaoh-decide` | `decisions.rst` next to the first `:decides:` target | + +If `parent_link` is empty or its source location cannot be resolved from `needs.json`, emit +`file_placement: null` and let the caller decide. + +--- + +### Step 5: Emit the authoring summary + +Emit the `=== [ARTEFACT] ===` block followed by the `=== [AUTHORING SUMMARY] ===` JSON. No +prose wrapper. + +If the dispatched drafter advised a follow-up (e.g. `pharaoh-arch-review`), preserve that +line below the summary so callers can chain. + +--- + +## Guardrails + +**G1 — Unknown target_type** + +If the resolved key is not in the artefact catalog, FAIL (Step 0). Do not invent a new +artefact type at runtime. + +**G2 — No drafter for known type** + +If the resolved key is in the catalog but does not match any of the four router categories +(requirement-shaped, architecture, verification-plan, decision), FAIL with the catalog +key and the four supported categories listed. Do not silently fall back to a drafter. +This guardrail is rarely hit in practice — the four categories cover every artefact type +declared in the bundled catalogs and every safety-V type — but stays in place to make +"my catalog declared a type the router does not classify" a loud error rather than a +silent miscategorisation. + +**G3 — Dispatched drafter failed** + +Forward FAIL / `[DIAGNOSTIC]` verbatim. Record `stop_reason` in the summary. Do not retry. + +**G4 — Tailoring missing** + +If `.pharaoh/project/artefact-catalog.yaml` is absent, the dispatched drafter will operate on +its built-in defaults. Note the fallback in the authoring summary so the caller knows the +output is not catalog-validated. + +--- + +## Advisory chain + +After a successful authoring summary, advise the caller: + +``` +Consider running `pharaoh-verify ` to confirm the drafted artefact +addresses the substance of its parent. For a per-axis review of the prose itself, +use `pharaoh-req-review` / `pharaoh-arch-review` / `pharaoh-vplan-review`. +``` + +--- + +## Worked example + +**User input:** + +> target_type: `arch` +> draft_seed: "Manages the ABS pump drive circuit, including PWM duty-cycle control and +> over-current protection." +> parent_link: `gd_req__abs_pump_activation` + +**Step 0:** `arch` resolves directly to catalog key `arch`. + +**Step 1:** routing table → `pharaoh-arch-draft` (architecture category). + +**Step 2:** forward `parent_req_id`, `target_level=arch`, `element_description`. + +**Step 3:** `pharaoh-arch-draft` returns its RST block for `arch__abs_pump_driver`. + +**Step 4:** `gd_req__abs_pump_activation` lives in `docs/requirements/braking.rst`. +Suggested placement: `docs/requirements/architecture.rst`. + +**Step 5 output (condensed):** + +``` +=== [ARTEFACT] arch: arch__abs_pump_driver === +.. arch:: ABS pump driver component + :id: arch__abs_pump_driver + :status: draft + :satisfies: gd_req__abs_pump_activation + + The ABS pump driver component manages the pump drive circuit, controlling + output PWM duty cycle and providing over-current protection for the pump motor. + +=== [AUTHORING SUMMARY] === +{ + "need_id": "arch__abs_pump_driver", + "type": "arch", + "dispatched_skill": "pharaoh-arch-draft", + "parent_link": "gd_req__abs_pump_activation", + "file_placement": "docs/requirements/architecture.rst", + "stop_reason": null +} +``` + +``` +Consider running `pharaoh-verify arch__abs_pump_driver` to confirm the drafted +artefact addresses the substance of its parent. +``` diff --git a/skills/pharaoh-flow/SKILL.md b/skills/pharaoh-flow/SKILL.md index 24c9b8d..7088167 100644 --- a/skills/pharaoh-flow/SKILL.md +++ b/skills/pharaoh-flow/SKILL.md @@ -1,6 +1,6 @@ --- name: pharaoh-flow -description: Use when orchestrating the full V-model chain for one feature context — requirement → architecture element → verification plan → FMEA, each with a review pass. Invokes pharaoh-req-draft, pharaoh-req-review, pharaoh-arch-draft, pharaoh-arch-review, pharaoh-vplan-draft, pharaoh-vplan-review, pharaoh-fmea in sequence. +description: "Use when orchestrating the full V-model chain for one feature context — across the optional ISO 26262 safety V (hazard / safety_goal / fsr), the ASPICE SYS layer (sysreq / sys-arch), the ASPICE SW layer (swreq / swarch), and the classical component V (req / comp_req → arch → vplan → fmea), each with a review pass. Auto-detects which layers to run from `.pharaoh/project/artefact-catalog.yaml`; the caller can pass a `stages` argument to skip layers explicitly. Dispatches to pharaoh-req-draft, pharaoh-req-review, pharaoh-arch-draft, pharaoh-arch-review, pharaoh-vplan-draft, pharaoh-vplan-review, and pharaoh-fmea — no new safety-V drafting skills are introduced; safety-V types route through pharaoh-req-draft with the appropriate target_level." chains_from: [] chains_to: [] --- @@ -10,82 +10,152 @@ chains_to: [] ## When to use Invoke when the user wants to produce a complete V-model artefact chain from a single feature -context in one operation. This skill orchestrates the seven atomic skills; it does not author -content itself. +context in one operation. This skill orchestrates the atomic drafting and review skills; it +does not author content itself. -**Scope is exactly:** one feature context → one `gd_req` + one `arch` element + one `tc` test -case + one `fmea` entry, with a review pass after the requirement and architecture steps. +**Scope is bounded to one feature context.** Each layer that runs emits exactly one artefact +of each type the layer covers, with a review pass after every drafted artefact. + +The orchestrator walks up to three optional layers, top-down through the V: + +| Layer | Stages drafted | Catalog types it expects | +|---|---|---| +| `safety_v` | hazard → safety_goal → fsr | `hazard`, `safety_goal`, `fsr` | +| `sys` | sysreq → sys-arch | `sysreq`, `sys-arch` | +| `sw` | swreq → swarch | `swreq`, `swarch` | +| `component` | req (or `comp_req` / `gd_req`) → arch → vplan → fmea | one requirement-shaped key (e.g. `req`, `comp_req`, `gd_req`), `arch`, `tc`, `fmea` | + +A layer runs only if its types are declared in `.pharaoh/project/artefact-catalog.yaml`. A +project that declares only the classical types runs only the `component` layer (the prior +behaviour of this skill is preserved exactly). Do NOT invoke when the user wants to draft only one artefact type — use the individual atomic -skills directly. Do NOT invoke when the feature context implies multiple requirements (the -orchestrator will draft the single most direct requirement and advise re-invocation). +skills directly. Do NOT invoke when the feature context implies multiple requirements at the +same level (the orchestrator drafts the single most direct requirement per layer and advises +re-invocation). > This is a compositional orchestrator. The atomicity criterion (a) does not apply: by design -> it invokes multiple skills. Scope is bounded to "one feature → one V-model chain". +> it invokes multiple skills. Scope is bounded to "one feature → one V-model chain across the +> declared layers". --- ## Inputs -- **feature_context** (from user): short prose describing the feature (1–5 sentences), target - level, safety relevance -- **parent_link** (from user): ID of the parent requirement or workflow the new requirement - will satisfy -- **safety_context** (from user, optional): ASIL level (A–D) or safety goal if known — passed - through to `pharaoh-fmea` -- **tailoring** (from `.pharaoh/project/`): same tailoring files read by each atomic skill -- **needs.json**: required for parent resolution and uniqueness checks in each sub-skill +- **feature_context** (from user): short prose describing the feature / hazard / safety goal + (1–5 sentences). Forwarded to the top-most layer that runs. +- **parent_link** (from user): need-id of the parent the top-most layer's first artefact will + trace to (e.g. a workflow id for safety-V, an upstream sysreq id when entering at SYS, etc.). + When a higher layer runs first, the lower layers chain off the IDs produced upstream — the + caller does not supply an extra parent for each layer. +- **safety_context** (from user, optional): ASIL level (A–D) or safety-goal handle if known — + forwarded to `pharaoh-req-draft` (for safety-V types) and to `pharaoh-fmea`. +- **stages** (from user, optional): explicit list of layers to run. Allowed values: + `safety_v`, `sys`, `sw`, `component`. Order in the input is ignored — the orchestrator always + walks the layers top-down (`safety_v` → `sys` → `sw` → `component`). When omitted, + auto-detect from the catalog. +- **tailoring** (from `.pharaoh/project/`): every sub-skill consumes `artefact-catalog.yaml`, + `id-conventions.yaml`, `workflows.yaml`, and per-type checklists. +- **needs.json**: required for parent resolution and uniqueness checks in each sub-skill. + +### Auto-detect vs. explicit `stages` + +Default behaviour is **auto-detect**: the orchestrator runs every layer whose types are +declared in the catalog. This is the correct mode for a project that has finished tailoring +and wants the full V emitted in one call. + +The caller passes `stages` explicitly when: + +- A project is **bootstrapping** the safety V and wants only the upper-V emitted while the + classical layer is still being shaped. Without an explicit `stages: ["safety_v"]`, + auto-detect would also try to run the lower layers. +- An audit run wants to **regenerate one layer in isolation** without retouching others + already emitted (e.g. `stages: ["sys"]` to refresh the SYS layer after a tailoring edit). +- The catalog declares a layer's types but the caller knows that layer's parent IDs aren't + yet stable, so the layer should be deferred. + +When `stages` is supplied, every requested layer must have its types declared in the catalog; +a missing declaration is a hard FAIL (see Guardrail G2). --- ## Outputs -Four artefacts + up to two review finding reports, each in a labeled fenced block: +For every layer that runs, emit each drafted artefact and its review (where the layer +includes one) in a labeled fenced block, then a single flow summary at the end. Block +ordering follows the V (top-down then layer-internal): ``` -=== [ARTEFACT 1] gd_req: === - - -=== [REVIEW 1] req-review: === - - -=== [ARTEFACT 2] arch: === - - -=== [REVIEW 2] arch-review: === - - -=== [ARTEFACT 3] tc: === - - -=== [ARTEFACT 4] fmea: === - +=== [SAFETY_V 1/3] hazard: === (only if layer ran) +=== [REVIEW SAFETY_V 1/3] req-review: === +=== [SAFETY_V 2/3] safety_goal: === +=== [REVIEW SAFETY_V 2/3] req-review: === +=== [SAFETY_V 3/3] fsr: === +=== [REVIEW SAFETY_V 3/3] req-review: === + +=== [SYS 1/2] sysreq: === (only if layer ran) +=== [REVIEW SYS 1/2] req-review: === +=== [SYS 2/2] sys-arch: === +=== [REVIEW SYS 2/2] arch-review: === + +=== [SW 1/2] swreq: === (only if layer ran) +=== [REVIEW SW 1/2] req-review: === +=== [SW 2/2] swarch: === +=== [REVIEW SW 2/2] arch-review: === + +=== [COMPONENT 1/4] : === (only if layer ran) +=== [REVIEW COMPONENT 1/4] req-review: === +=== [COMPONENT 2/4] arch: === +=== [REVIEW COMPONENT 2/4] arch-review: === +=== [COMPONENT 3/4] tc: === +=== [REVIEW COMPONENT 3/4] vplan-review: === +=== [COMPONENT 4/4] fmea: === === [FLOW SUMMARY] === ``` +Each `[REVIEW …]` block is omitted only when its corresponding draft step was skipped or +failed. + **Flow summary shape:** ```json { "feature_context_summary": "one sentence", - "artefacts": { - "gd_req": {"id": "gd_req__...", "overall": "pass|needs_work|fail"}, - "arch": {"id": "arch__...", "overall": "pass|needs_work|fail"}, - "tc": {"id": "tc__...", "status": "drafted"}, - "fmea": {"id": "fmea__...", "rpn": 160} + "stages_run": ["safety_v", "sys", "sw", "component"], + "stages_skipped": [], + "skip_reasons": { + "": "auto-detect: catalog does not declare " }, - "reviews": { - "req_review": "pass|needs_work|fail", - "arch_review": "pass|needs_work|fail" + "artefacts": { + "safety_v": { + "hazard": {"id": "hazard__...", "overall": "pass|needs_work|fail"}, + "safety_goal": {"id": "safety_goal__...", "overall": "pass|needs_work|fail"}, + "fsr": {"id": "fsr__...", "overall": "pass|needs_work|fail"} + }, + "sys": { + "sysreq": {"id": "sysreq__...", "overall": "pass|needs_work|fail"}, + "sys-arch": {"id": "sys_arch__...", "overall": "pass|needs_work|fail"} + }, + "sw": { + "swreq": {"id": "swreq__...", "overall": "pass|needs_work|fail"}, + "swarch": {"id": "swarch__...", "overall": "pass|needs_work|fail"} + }, + "component": { + "req": {"id": "__...", "overall": "pass|needs_work|fail"}, + "arch": {"id": "arch__...", "overall": "pass|needs_work|fail"}, + "tc": {"id": "tc__...", "overall": "pass|needs_work|fail"}, + "fmea": {"id": "fmea__...", "rpn": 160} + } }, "stop_reason": null } ``` -If the chain was stopped early (see Guardrail G2), `stop_reason` contains the diagnostic from -the failing skill. +When a layer is skipped, its key in `artefacts` is omitted and the layer name appears in +`stages_skipped` with the reason in `skip_reasons`. When the chain stops early (Guardrail +G3), `stop_reason` carries the diagnostic from the failing skill. --- @@ -101,83 +171,144 @@ FAIL: pharaoh-flow requires feature_context and parent_link. Provide both before invoking the orchestrator. ``` +If the caller supplied `stages`, validate every entry against the allowed set +(`safety_v`, `sys`, `sw`, `component`). Unknown values FAIL. + --- -### Step 1: Draft requirement — invoke pharaoh-req-draft +### Step 1: Resolve which layers will run -Pass `feature_context`, `parent_link`, and tailoring to `pharaoh-req-draft`. Capture output. +Read `.pharaoh/project/artefact-catalog.yaml`. For each layer, mark it `present-in-catalog` +when **every** required type for that layer is declared: -If `pharaoh-req-draft` returns a FAIL (not a `[DIAGNOSTIC]`), stop the chain: -emit the failure in a `=== [CHAIN STOP: req-draft] ===` block and set `stop_reason` in the -summary. Do not proceed to Step 2. +| Layer | Required catalog keys | +|---|---| +| `safety_v` | `hazard`, `safety_goal`, `fsr` | +| `sys` | `sysreq`, `sys-arch` | +| `sw` | `swreq`, `swarch` | +| `component` | one of (`req`, `comp_req`, `gd_req`), plus `arch`, `tc`. (`fmea` is best-effort and may be absent — see Step 6 of the component layer.) | ---- +Selection rules: -### Step 2: Review requirement — invoke pharaoh-req-review +- **No `stages` argument (auto-detect)** — every layer where `present-in-catalog` is true + runs; layers whose types are not declared are silently skipped, with `skip_reasons[""] + = "auto-detect: catalog does not declare "`. +- **Explicit `stages` argument** — only requested layers run; layers not requested record + `skip_reasons[""] = "not requested by caller"`. For every requested layer that is + NOT `present-in-catalog`, FAIL hard: -Pass the RST block from Step 1 to `pharaoh-req-review`. Capture findings JSON. + ``` + FAIL: stages argument requested "" but artefact-catalog.yaml does not + declare the required types: . + Either declare the types in the catalog (run pharaoh-tailor-fill), or remove + "" from the stages argument. + ``` -If `pharaoh-req-review` returns a hard FAIL (unresolved target), stop the chain. +If neither auto-detect nor an explicit `stages` argument selects any layer, FAIL: -If `overall` is `"needs_work"` or `"fail"`, **do not stop** — continue the chain but record -the review result in the summary. The user can address the action items independently. +``` +FAIL: no layers selected. Catalog declares none of {safety_v, sys, sw, component} +artefact types and the caller did not pass a stages argument. +``` + +For the `component` layer, also resolve which requirement key to use (the first of +`req` / `comp_req` / `gd_req` declared in the catalog wins). Record the chosen key as +`` and use it consistently throughout the layer. --- -### Step 3: Draft architecture element — invoke pharaoh-arch-draft +### Step 2: Run the safety_v layer (if selected) + +For each stage in order — `hazard`, `safety_goal`, `fsr` — invoke `pharaoh-req-draft` with +`target_level=`, then `pharaoh-req-review` on the drafted RST. + +Inputs forwarded to `pharaoh-req-draft`: + +| Stage | feature_context | parent_link | +|---|---|---| +| `hazard` | the user's `feature_context` | the user's `parent_link` | +| `safety_goal` | "Safety goal addressing hazard ``: …" — derived from the user's `feature_context` and the hazard ID emitted in the prior step | the `hazard` ID | +| `fsr` | "Functional safety requirement deriving safety goal ``: …" | the `safety_goal` ID | -Pass `feature_context`, the `gd_req` ID from Step 1, and tailoring to `pharaoh-arch-draft`. +Forward `safety_context` to every step. The drafter uses the catalog's `required_links` +(e.g. `derives_from`, `safety_goal_for`) to attach the correct link relation; the +orchestrator does not hardcode link names. -If `pharaoh-arch-draft` returns a FAIL, stop the chain and record `stop_reason`. +Capture the IDs emitted by the layer; the `fsr` ID becomes the parent for the SYS layer's +`sysreq` (if SYS runs). If the SYS layer is skipped, the `fsr` ID becomes the parent for the +SW layer's `swreq` (if SW runs). If SYS and SW are both skipped, the `fsr` ID becomes the +parent for the `component` layer's requirement. + +Review-policy: a `pharaoh-req-review` returning `overall: needs_work` or `overall: fail` does +NOT stop the chain (Guardrail G4). A hard FAIL from `pharaoh-req-draft` does (Guardrail G3). --- -### Step 4: Review architecture element — invoke pharaoh-arch-review +### Step 3: Run the sys layer (if selected) + +Step 3a — `pharaoh-req-draft` with `target_level=sysreq`. Parent is whichever upstream ID +was last produced (the `fsr` ID when safety-V ran, otherwise the user's `parent_link`). + +Step 3b — `pharaoh-req-review` on the `sysreq`. -Pass the RST block from Step 3 to `pharaoh-arch-review`. Capture findings JSON. +Step 3c — `pharaoh-arch-draft` with `target_level=sys-arch`. Parent is the `sysreq` ID. -Same policy as Step 2: `needs_work` or `fail` does not stop the chain. +Step 3d — `pharaoh-arch-review` on the `sys-arch`. + +Capture both IDs. The `sys-arch` ID is the upstream parent for the SW layer (if SW runs); when +SW is skipped, the `sys-arch` ID becomes the parent for the `component` layer's requirement. --- -### Step 5: Draft verification plan — invoke pharaoh-vplan-draft +### Step 4: Run the sw layer (if selected) -Pass the `gd_req` ID from Step 1 (primary parent for the test case) and tailoring to -`pharaoh-vplan-draft`. +Step 4a — `pharaoh-req-draft` with `target_level=swreq`. Parent is whichever upstream ID was +last produced (`sys-arch` when SYS ran, `fsr` when safety-V ran without SYS, or the user's +`parent_link` otherwise). -If `pharaoh-vplan-draft` returns a FAIL, emit a warning block but do not stop the full chain: +Step 4b — `pharaoh-req-review` on the `swreq`. -``` -=== [WARNING: vplan-draft failed] === - -tc artefact will be absent from the summary. -``` +Step 4c — `pharaoh-arch-draft` with `target_level=swarch`. Parent is the `swreq` ID. + +Step 4d — `pharaoh-arch-review` on the `swarch`. -Record `tc: null` in the summary. +Capture both IDs. The `swarch` ID is the upstream parent for the `component` layer's +requirement (if the `component` layer runs). --- -### Step 6: Draft FMEA entry — invoke pharaoh-fmea +### Step 5: Run the component layer (if selected) -Pass the `gd_req` ID from Step 1 as `parent_id`, and `safety_context` if provided, to -`pharaoh-fmea`. +This is the classical chain preserved from the prior behaviour, with an explicit review pass +after every drafted artefact (req, arch, tc) and an FMEA at the end. -If `pharaoh-fmea` returns a FAIL, emit a warning block but do not stop: +Step 5a — `pharaoh-req-draft` with `target_level=` (the key resolved in Step 1). +Parent is the closest upstream ID — `swarch` when SW ran, else `sys-arch` when SYS ran, else +`fsr` when safety_V ran, else the user's `parent_link`. -``` -=== [WARNING: fmea failed] === - -fmea artefact will be absent from the summary. -``` +Step 5b — `pharaoh-req-review` on the requirement. -Record `fmea: null` in the summary. +Step 5c — `pharaoh-arch-draft` with `target_level=arch` and the requirement's ID as parent. + +Step 5d — `pharaoh-arch-review` on the architecture element. + +Step 5e — `pharaoh-vplan-draft` with `target_level=tc` and the requirement's ID as parent. + +Step 5f — `pharaoh-vplan-review` on the test case. + +Step 5g — `pharaoh-fmea` with `parent_id=` and the user's `safety_context`. + +For Steps 5e (vplan-draft) and 5g (fmea), a hard FAIL emits a `=== [WARNING …] ===` block but +does NOT stop the chain — the artefact is recorded as `null` in the summary. Steps 5a and +5c (the load-bearing draft steps) DO stop the chain on hard FAIL, per Guardrail G3. --- -### Step 7: Emit all outputs and flow summary +### Step 6: Emit all outputs and the flow summary -Emit each artefact and review in its labeled fenced block in the order shown in the Outputs -section. Emit the flow summary last. +Emit each artefact and review block in the order shown in the Outputs section. Emit the +flow summary last. List every layer that ran in `stages_run` and every layer that was +skipped in `stages_skipped`, with the reason recorded under `skip_reasons`. --- @@ -187,128 +318,199 @@ section. Emit the flow summary last. `feature_context` or `parent_link` absent → FAIL before any sub-skill runs (Step 0). -**G2 — Hard failure in req-draft or arch-draft** +**G2 — Explicit stages argument referencing un-declared types** -These two steps are load-bearing. If either returns a hard FAIL, stop and record `stop_reason`. -The vplan and fmea steps are best-effort (warnings but not chain stops). +When the caller passes `stages` and a requested layer's types are not declared in +`artefact-catalog.yaml`, FAIL hard with the missing types listed (Step 1). Auto-detect +silently skips a missing layer; an explicit request never falls back silently. -**G3 — Review findings don't block chain** +**G3 — Hard failure in a load-bearing draft step** -A review returning `overall: fail` is informational — the chain continues. The action items -are preserved in the review block for the user to address. The orchestrator does not -auto-regenerate; that would require `pharaoh-req-regenerate`. +Within each layer, the draft skills are load-bearing. A hard FAIL from any +`pharaoh-req-draft` or `pharaoh-arch-draft` invocation stops the chain at that point and +records `stop_reason` with the failing skill name and its diagnostic. The vplan and fmea +steps in the `component` layer are best-effort (warnings but not chain stops). -**G4 — Tailoring unavailable** +**G4 — Review findings don't block the chain** -If `.pharaoh/project/` tailoring files are missing, the sub-skills will fail. Fail fast with: +A review returning `overall: needs_work` or `overall: fail` is informational. The chain +continues. Action items are preserved in the review block for the user to address. The +orchestrator never auto-regenerates; that requires `pharaoh-req-regenerate`. + +**G5 — Tailoring unavailable** + +If `.pharaoh/project/` tailoring files are missing, the sub-skills will fail. Fail fast +with: ``` FAIL: pharaoh-flow cannot run without tailoring files at .pharaoh/project/. Run pharaoh-tailor-detect → pharaoh-tailor-fill first. ``` +**G6 — Catalog declares safety-V partial set** + +A project that declares only some of `hazard`, `safety_goal`, `fsr` is mis-tailored. In +auto-detect mode the safety_v layer skips with reason +`auto-detect: catalog declares only ; safety_v layer requires the full set`. +In explicit-stages mode this is a hard FAIL via Guardrail G2. + --- ## Advisory chain -This skill has `chains_to: []` — it is a terminal orchestrator. After the flow summary, advise -only if reviews returned action items: +This skill has `chains_to: []` — it is a terminal orchestrator. After the flow summary, +advise only when reviews returned action items: ``` -Review action items in [REVIEW 1] and [REVIEW 2] blocks. +Review action items in the [REVIEW …] blocks above. Use `pharaoh-req-regenerate` or `pharaoh-arch-draft` (with corrections) to address them. ``` --- -## Worked example +## Worked example — safety-V on a project that declares the full V **User input:** -> feature_context: "The brake controller shall engage the ABS pump when wheel slip exceeds a -> calibrated threshold. Target level: component. Safety relevance: ASIL B." + +> feature_context: "Unintended ABS pump activation while the brake pedal is released can +> destabilise the vehicle on slippery surfaces. The brake controller must prevent activation +> outside the slip-detection window." > parent_link: `wf__brake_system_design` > safety_context: ASIL B +> stages: (omitted — auto-detect) + +The project's `artefact-catalog.yaml` declares `hazard`, `safety_goal`, `fsr`, `sysreq`, +`sys-arch`, `swreq`, `swarch`, `comp_req`, `arch`, `tc`. All four layers will run. -**Step 0:** both inputs present. Continue. +**Layer 1 — safety_v:** -**Step 1 — req-draft:** produces `gd_req__abs_pump_activation`. +- `pharaoh-req-draft` (target_level=hazard) emits `hazard__unintended_abs_pump_activation`, + parent `wf__brake_system_design`, body describes the hazardous event. +- `pharaoh-req-draft` (target_level=safety_goal) emits + `safety_goal__no_unintended_abs_activation` linked via `:derives_from:` to the hazard. +- `pharaoh-req-draft` (target_level=fsr) emits `fsr__abs_activation_window_check` linked via + `:safety_goal_for:` to the safety goal. +- Each is reviewed by `pharaoh-req-review`; all three pass. -**Step 2 — req-review:** all axes pass → `overall: pass`. +**Layer 2 — sys:** -**Step 3 — arch-draft:** produces `arch__brake_controller_abs_module` satisfying -`gd_req__abs_pump_activation`. +- `sysreq__abs_activation_window_check` derives from `fsr__abs_activation_window_check`. +- `sys_arch__brake_controller_supervision` satisfies the sysreq. +- Both reviewed. -**Step 4 — arch-review:** all axes pass → `overall: pass`. +**Layer 3 — sw:** -**Step 5 — vplan-draft:** produces `tc__abs_pump_activation_001` verifying -`gd_req__abs_pump_activation`. +- `swreq__pedal_state_gate` derives from `sys_arch__brake_controller_supervision`. +- `swarch__abs_supervision_module` satisfies the swreq. +- Both reviewed. -**Step 6 — fmea:** produces `fmea__abs_pump_activation__no_activation`; RPN = 160. +**Layer 4 — component:** -**Step 7 output (condensed):** +- `comp_req__abs_pump_activation` (the `` resolved to `comp_req`) derives from + `swarch__abs_supervision_module`. +- `arch__abs_pump_driver` satisfies the comp_req. +- `tc__abs_pump_activation_001` verifies the comp_req. +- `fmea__abs_pump_activation__no_activation` derived from the comp_req; RPN = 160. +**Flow summary (condensed):** + +``` +=== [FLOW SUMMARY] === +{ + "feature_context_summary": "Prevent unintended ABS pump activation outside slip window (ASIL B)", + "stages_run": ["safety_v", "sys", "sw", "component"], + "stages_skipped": [], + "skip_reasons": {}, + "artefacts": { + "safety_v": { + "hazard": {"id": "hazard__unintended_abs_pump_activation", "overall": "pass"}, + "safety_goal": {"id": "safety_goal__no_unintended_abs_activation","overall": "pass"}, + "fsr": {"id": "fsr__abs_activation_window_check", "overall": "pass"} + }, + "sys": { + "sysreq": {"id": "sysreq__abs_activation_window_check", "overall": "pass"}, + "sys-arch": {"id": "sys_arch__brake_controller_supervision", "overall": "pass"} + }, + "sw": { + "swreq": {"id": "swreq__pedal_state_gate", "overall": "pass"}, + "swarch": {"id": "swarch__abs_supervision_module", "overall": "pass"} + }, + "component": { + "req": {"id": "comp_req__abs_pump_activation", "overall": "pass"}, + "arch": {"id": "arch__abs_pump_driver", "overall": "pass"}, + "tc": {"id": "tc__abs_pump_activation_001", "overall": "pass"}, + "fmea": {"id": "fmea__abs_pump_activation__no_activation", "rpn": 160} + } + }, + "stop_reason": null +} ``` -=== [ARTEFACT 1] gd_req: gd_req__abs_pump_activation === -.. gd_req:: ABS pump activation on wheel slip threshold - :id: gd_req__abs_pump_activation - :status: draft - :satisfies: wf__brake_system_design - :verification: tc__abs_pump_activation_001 - - The brake controller shall engage the ABS pump when measured wheel slip exceeds - the calibrated activation threshold. - -=== [REVIEW 1] req-review: gd_req__abs_pump_activation === -{"need_id": "gd_req__abs_pump_activation", "overall": "pass", "action_items": [], ...} - -=== [ARTEFACT 2] arch: arch__brake_controller_abs_module === -.. arch:: Brake Controller ABS Module - :id: arch__brake_controller_abs_module - :status: draft - :satisfies: gd_req__abs_pump_activation - :type: component - - The ABS module within the brake controller monitors wheel-slip signals and activates - the ABS pump actuator when the slip threshold is exceeded. - -=== [REVIEW 2] arch-review: arch__brake_controller_abs_module === -{"need_id": "arch__brake_controller_abs_module", "overall": "pass", "action_items": [], ...} - -=== [ARTEFACT 3] tc: tc__abs_pump_activation_001 === -.. tc:: ABS pump activation on wheel slip threshold — functional test - :id: tc__abs_pump_activation_001 - :status: draft - :verifies: gd_req__abs_pump_activation - - Inputs - ------ - Simulated wheel-speed sensor signals producing slip > calibrated threshold. - - Steps - ----- - 1. Inject slip-threshold-exceedance signal. - 2. Observe ABS pump actuator output. - - Expected - -------- - ABS pump activates within 10 ms of threshold exceedance. - -=== [ARTEFACT 4] fmea: fmea__abs_pump_activation__no_activation === -{"fmea_id": "fmea__abs_pump_activation__no_activation", "rpn": 160, ...} +--- + +## Worked example — classical V on a project without safety-V or SYS/SWE split + +**User input:** + +> feature_context: "The brake controller shall engage the ABS pump when wheel slip exceeds a +> calibrated threshold. Target level: component." +> parent_link: `wf__brake_system_design` +> safety_context: ASIL B +> stages: (omitted — auto-detect) + +The project's catalog declares only `gd_req`, `arch`, `tc`. Auto-detect skips `safety_v`, +`sys`, and `sw`; only the `component` layer runs. + +**Layer 4 — component (only):** + +- `gd_req__abs_pump_activation` parent `wf__brake_system_design`. +- `arch__brake_controller_abs_module` satisfies the requirement. +- `tc__abs_pump_activation_001` verifies the requirement. +- `fmea__abs_pump_activation__no_activation` derived from the requirement; RPN = 160. + +**Flow summary:** + +``` === [FLOW SUMMARY] === { "feature_context_summary": "Brake controller engages ABS pump on wheel-slip threshold exceedance (ASIL B)", - "artefacts": { - "gd_req": {"id": "gd_req__abs_pump_activation", "overall": "pass"}, - "arch": {"id": "arch__brake_controller_abs_module", "overall": "pass"}, - "tc": {"id": "tc__abs_pump_activation_001", "status": "drafted"}, - "fmea": {"id": "fmea__abs_pump_activation__no_activation","rpn": 160} + "stages_run": ["component"], + "stages_skipped": ["safety_v", "sys", "sw"], + "skip_reasons": { + "safety_v": "auto-detect: catalog does not declare hazard, safety_goal, fsr", + "sys": "auto-detect: catalog does not declare sysreq, sys-arch", + "sw": "auto-detect: catalog does not declare swreq, swarch" }, - "reviews": { - "req_review": "pass", - "arch_review": "pass" + "artefacts": { + "component": { + "req": {"id": "gd_req__abs_pump_activation", "overall": "pass"}, + "arch": {"id": "arch__brake_controller_abs_module", "overall": "pass"}, + "tc": {"id": "tc__abs_pump_activation_001", "overall": "pass"}, + "fmea": {"id": "fmea__abs_pump_activation__no_activation", "rpn": 160} + } }, "stop_reason": null } ``` + +This is the prior behaviour of the skill, preserved exactly. + +--- + +## Worked example — bootstrapping safety V in isolation + +**User input:** + +> feature_context: "Loss of brake pedal feedback while ABS is intervening can lead to a delayed +> driver response and longer stopping distances." +> parent_link: `wf__hara` +> safety_context: ASIL C +> stages: ["safety_v"] + +Even though the project's catalog also declares `sys`, `sw`, and `component` types, the +caller restricts the run to the safety V — typical when bootstrapping HARA outputs before the +lower V is mature enough to chain. + +Only Layer 1 runs: hazard → safety_goal → fsr, each reviewed. The `[FLOW SUMMARY]` +records `stages_run: ["safety_v"]`, `stages_skipped: ["sys", "sw", "component"]`, and a +`skip_reasons` map indicating each was skipped because the caller did not request it. diff --git a/skills/pharaoh-gate-advisor/SKILL.md b/skills/pharaoh-gate-advisor/SKILL.md index 18ea0bc..860b18f 100644 --- a/skills/pharaoh-gate-advisor/SKILL.md +++ b/skills/pharaoh-gate-advisor/SKILL.md @@ -30,16 +30,18 @@ Do NOT invoke to modify `pharaoh.toml` — this skill is advisory, read-only. Au - `pharaoh_toml_path`: absolute path to the project's `pharaoh.toml`. The skill reads exactly five keys: - `[pharaoh].strictness` — string; treated as `"advisory"` unless the value is exactly `"enforcing"`. - - `[pharaoh.workflow].require_verification` — boolean; default `false` when absent. - - `[pharaoh.workflow].require_change_analysis` — boolean; default `false` when absent. - - `[pharaoh.workflow].require_mece_on_release` — boolean; default `false` when absent. - - `[pharaoh.codelinks].enabled` — boolean; default `false` when absent. + - `[pharaoh.workflow].require_verification` — boolean. + - `[pharaoh.workflow].require_change_analysis` — boolean. + - `[pharaoh.workflow].require_mece_on_release` — boolean. + - `[pharaoh.codelinks].enabled` — boolean. + + Default values are NOT redeclared in this skill. If a flag is absent from the project's `pharaoh.toml`, the skill treats it as the value declared in `pharaoh.toml.example` at the Pharaoh repo root. The example currently sets `(require_change_analysis=true, require_verification=true, require_mece_on_release=false)` and `codelinks.enabled=true`; for absent strictness the example sets `"advisory"`. To change the defaults this skill walks against, edit `pharaoh.toml.example` only — never reintroduce competing defaults here. Edge cases: - `pharaoh_toml_path` missing or unreadable → emit `overall: "error"` with `errors: ["pharaoh.toml unresolved: "]` and no other keys. Callers branch on `overall` first. No ladder array is emitted on this path — the ladder is meaningful only when the file parsed. - TOML parse error (syntax bad) → same `overall: "error"` shape with the parser message included. -- Keys present but with unexpected types (e.g. `require_verification = "yes"` as a string) → treat as their typed default (`false` for booleans, `"advisory"` for strictness) and add a note `"unexpected type for ; treated as default"` in `notes`. -- Entire `[pharaoh.workflow]` or `[pharaoh.codelinks]` section absent → every flag in that section resolves to its `false` default; no error. +- Keys present but with unexpected types (e.g. `require_verification = "yes"` as a string) → treat as the typed default declared in `pharaoh.toml.example` (`true`/`false`/`"advisory"` per the example) and add a note `"unexpected type for ; treated as default"` in `notes`. +- Entire `[pharaoh.workflow]` or `[pharaoh.codelinks]` section absent → every flag in that section resolves to its example default; no error. ## Output diff --git a/skills/pharaoh-id-convention-check/SKILL.md b/skills/pharaoh-id-convention-check/SKILL.md index 30427d9..ae2a571 100644 --- a/skills/pharaoh-id-convention-check/SKILL.md +++ b/skills/pharaoh-id-convention-check/SKILL.md @@ -33,20 +33,20 @@ Do NOT use to discover or count id schemes — the tailoring author declares ONE id_regex: "^[a-z][a-z_]*__[a-z0-9_]+$" # per-type overrides — the regex applied to needs of that type - id_regex_by_type: + id_regex_exceptions: comp_req: "^CREQ_[a-z]+_[a-z]+_[a-z]+$" gd_req: "^CREQ_.+$|^gd_req__.+$" ``` - Resolution order for a need of type `T`: `id_regex_by_type[T]` if declared, else `id_regex` (top-level default), else fail the whole check with `reason: "no regex declared for type "` on every need of that type. + Resolution order for a need of type `T`: `id_regex_exceptions[T]` if declared, else `id_regex` (top-level default), else fail the whole check with `reason: "no regex declared for type "` on every need of that type. - `needs_json_path`: absolute path to the built sphinx-needs corpus `needs.json`. Accepts either the flat `{"needs": {: {id, type, ...}, ...}}` shape or the versioned `{"versions": {"": {"needs": {...}}}}` shape (uses `current_version` if declared, else the latest key). Each need object must carry at least `id` and `type`; needs missing either field are reported as violations with `reason: "missing id or type field"`. Edge cases: - Empty corpus (`needs` is `{}`) → `needs_checked: 0, violations: [], overall: "pass"` (vacuously true). -- `id-conventions.yaml` has neither `id_regex` nor `id_regex_by_type` → every need is a violation with `reason: "no regex declared for type "`. +- `id-conventions.yaml` has neither `id_regex` nor `id_regex_exceptions` → every need is a violation with `reason: "no regex declared for type "`. - Regex compilation error (invalid Python regex syntax in the tailoring) → `overall: "fail"` with a single violation `{need_id: "*", type: "", expected_regex: "", reason: "regex compile error: "}` and `needs_checked: 0`. -- Need `type` not mentioned in `id_regex_by_type` and no top-level default → violation with `reason: "no regex declared for type "`. +- Need `type` not mentioned in `id_regex_exceptions` and no top-level default → violation with `reason: "no regex declared for type "`. ## Output @@ -78,7 +78,7 @@ Edge cases: For every need `N` in the flattened needs map: 1. Read `N.id` and `N.type`. If either is absent, emit violation `{need_id: ">, type: ">, expected_regex: null, reason: "missing id or type field"}` and continue. -2. Resolve the regex for `N.type`: first `id_regex_by_type[N.type]`, else top-level `id_regex`. If neither is declared, emit violation `{need_id: N.id, type: N.type, expected_regex: null, reason: "no regex declared for type "}` and continue. +2. Resolve the regex for `N.type`: first `id_regex_exceptions[N.type]`, else top-level `id_regex`. If neither is declared, emit violation `{need_id: N.id, type: N.type, expected_regex: null, reason: "no regex declared for type "}` and continue. 3. Compile the regex with Python `re.compile(pattern)`. On `re.error`, emit a single synthetic violation (see Edge cases above) and abort. 4. Apply `re.fullmatch(pattern, N.id)`. If `None`, emit violation `{need_id: N.id, type: N.type, expected_regex: , reason: "does not match"}`. @@ -94,7 +94,7 @@ nj = json.load(open(needs_json_path)) needs = nj.get("needs") or next(iter(nj.get("versions", {}).values()), {}).get("needs", {}) default = conv.get("id_regex") -by_type = conv.get("id_regex_by_type", {}) or {} +by_type = conv.get("id_regex_exceptions", {}) or {} violations = [] for nid, n in needs.items(): diff --git a/skills/pharaoh-id-convention-check/fixtures/all-conform/input-id-conventions.yaml b/skills/pharaoh-id-convention-check/fixtures/all-conform/input-id-conventions.yaml index dfa6dcb..ffba0db 100644 --- a/skills/pharaoh-id-convention-check/fixtures/all-conform/input-id-conventions.yaml +++ b/skills/pharaoh-id-convention-check/fixtures/all-conform/input-id-conventions.yaml @@ -3,6 +3,6 @@ id_regex: "^[a-z][a-z_]*__[a-z0-9_]+$" -id_regex_by_type: +id_regex_exceptions: comp_req: "^CREQ_[a-z]+_[a-z]+_[a-z]+$" test_case: "^tc__[a-z0-9_]+$" diff --git a/skills/pharaoh-id-convention-check/fixtures/alternation-regex/input-id-conventions.yaml b/skills/pharaoh-id-convention-check/fixtures/alternation-regex/input-id-conventions.yaml index 9b6ab57..64c268b 100644 --- a/skills/pharaoh-id-convention-check/fixtures/alternation-regex/input-id-conventions.yaml +++ b/skills/pharaoh-id-convention-check/fixtures/alternation-regex/input-id-conventions.yaml @@ -3,5 +3,5 @@ id_regex: "^[a-z][a-z_]*__[a-z0-9_]+$" -id_regex_by_type: +id_regex_exceptions: comp_req: "^CREQ_.+$|^gd_req__.+$" diff --git a/skills/pharaoh-id-convention-check/fixtures/some-violate/input-id-conventions.yaml b/skills/pharaoh-id-convention-check/fixtures/some-violate/input-id-conventions.yaml index 14b360d..5b76b39 100644 --- a/skills/pharaoh-id-convention-check/fixtures/some-violate/input-id-conventions.yaml +++ b/skills/pharaoh-id-convention-check/fixtures/some-violate/input-id-conventions.yaml @@ -2,6 +2,6 @@ id_regex: "^[a-z][a-z_]*__[a-z0-9_]+$" -id_regex_by_type: +id_regex_exceptions: comp_req: "^CREQ_[a-z]+_[a-z]+_[a-z]+$" test_case: "^tc__[a-z0-9_]+$" diff --git a/skills/pharaoh-lifecycle-check/SKILL.md b/skills/pharaoh-lifecycle-check/SKILL.md index ac21236..99f8c9b 100644 --- a/skills/pharaoh-lifecycle-check/SKILL.md +++ b/skills/pharaoh-lifecycle-check/SKILL.md @@ -66,9 +66,12 @@ current state is a valid declared state for this artefact type. ### Step 1: Load tailoring and needs.json -**1a.** Read `workflows.yaml` from `.pharaoh/project/`. Extract: -- `lifecycle_states` map (keys are valid state names) -- `transitions` list: each entry has `from`, `to`, `requires` +**1a.** Read `workflows.yaml` from `.pharaoh/project/`. The file shape is fixed by +`schemas/workflows.schema.json` (flat `lifecycle_states` array, `transitions` array of +`{from, to, requires}`). Extract: +- `lifecycle_states` — flat list of declared state-name strings +- `transitions` list: each entry has `from`, `to`, and a `requires` list of gate-name + strings (always a list per the schema, never a scalar) **1b.** Read `artefact-catalog.yaml`. Find the entry for the artefact type of `need_id`. Record the `lifecycle` list for that type (if present). diff --git a/skills/pharaoh-quality-gate/SKILL.md b/skills/pharaoh-quality-gate/SKILL.md index c02a6c3..fb7f289 100644 --- a/skills/pharaoh-quality-gate/SKILL.md +++ b/skills/pharaoh-quality-gate/SKILL.md @@ -121,6 +121,8 @@ Each delegated check returns either `{passed: bool, ...}` or the atom's native ` `metadata_fields_present` delegates to the existing `pharaoh-output-validate` atom invoked in `mode: "graph"` (see that skill's `## Graph mode`). The tailored `required_metadata_fields` list is declared per-type in `artefact-catalog.yaml`; empty list disables the check for that type, absent key is treated as empty. No new atom is introduced for this invariant — graph mode is a second input-shape on the existing block-validator. +The four release-gate fields backing `link_types_covered`, `metadata_fields_present`, and the `pharaoh-review-completeness` invariant (`required_links`, `optional_links`, `required_metadata_fields`, `required_roles`) are declared per-type in `artefact-catalog.yaml`. Their canonical schema lives at `schemas/artefact-catalog.schema.json` (see `schemas/README.md`); the absence of any of the three required-* keys is surfaced as a finding by `pharaoh-tailor-review` rule C6, so a project running the gate after a clean `pharaoh-tailor-review` has explicitly declared (possibly as empty arrays) what every consumer reads. + If a delegated check is not yet implemented in the skill tree, the gate records a warning in the report but does not fail — so that adding new invariants in future is a config-only change. ## Output diff --git a/skills/pharaoh-req-draft/SKILL.md b/skills/pharaoh-req-draft/SKILL.md index bd484de..610f981 100644 --- a/skills/pharaoh-req-draft/SKILL.md +++ b/skills/pharaoh-req-draft/SKILL.md @@ -1,6 +1,6 @@ --- name: pharaoh-req-draft -description: Use when drafting a single sphinx-needs requirement from a feature description. Produces a new RST directive block with ID, status=draft, and a single shall-clause body, linking to a parent requirement or workflow per the project's artefact-catalog. +description: Use when drafting a single sphinx-needs requirement-shaped artefact (req, comp_req, sysreq, swreq, hazard, safety_goal, fsr, etc.) from a feature description. The artefact type is parameterised via `target_level` (any catalog-declared requirement-shaped type — including ISO 26262 safety-V types). Produces a new RST directive block with ID, status=draft, and either a shall-clause body (requirement-shaped) or a hazard/goal-shaped body, linking to a parent per the project's artefact-catalog. chains_to: [pharaoh-req-review] --- @@ -8,17 +8,56 @@ chains_to: [pharaoh-req-review] ## When to use -Invoke when the user provides a feature description (1-5 sentences) and wants a single requirement authored at a specific level. Do NOT decompose multiple levels; do NOT review existing requirements; do NOT draft architecture — those are separate skills. +Invoke when the user provides a short feature, hazard, or safety-goal description (1-5 sentences) and wants a single requirement-shaped artefact authored at a specific catalog-declared level. Do NOT decompose multiple levels; do NOT review existing artefacts; do NOT draft architecture — those are separate skills. -This skill produces exactly one requirement per invocation. If the user appears to want multiple requirements from a single feature description, draft only the most direct one and tell the user to re-invoke for any additional requirements. +This skill produces exactly one artefact per invocation. If the user appears to want multiple artefacts from a single description, draft only the most direct one and tell the user to re-invoke for any additional ones. + +This skill is the canonical drafter for any requirement-shaped type the project's +`artefact-catalog.yaml` declares — classical levels (`req`, `comp_req`, `sysreq`, `swreq`, +`gd_req`) as well as ISO 26262 safety-V types (`hazard` for HARA outputs, `safety_goal` +for Part 3 goals, `fsr` for Part 4 functional safety requirements, `tsr` for Part 4 +technical safety requirements). The skill drives every type from the catalog's +`required_fields` and `required_metadata_fields`; nothing in the skill is hardcoded to a +fixed allow-list of types. + +### ISO 26262 framing + +Safety-V types follow ISO 26262 Part 3 (HARA → safety goals) and Part 4 (FSR / TSR) +flow. This skill is not a safety expert system: it does not decide ASIL ratings or +hazard classifications. It surfaces the ISO-26262-relevant fields (`asil`, `severity`, +`exposure`, `controllability`, `safe_state`, etc.) as placeholders when the project's +catalog declares them required, and prompts the user to fill them. Projects that do +not declare these fields in their catalog get a plain requirement; projects that do +(e.g. `useblocks/sphinx-needs-demo` with a HARA tailoring) get the safety-V shape. ## Inputs -- **feature_context** (from user): short prose describing the feature, target level, safety relevance -- **parent_link** (from user or inferred): ID of the parent requirement or workflow the new req satisfies +- **feature_context** (from user): short prose describing the feature, hazard, or safety + goal — plus the safety relevance if any +- **target_level** (from user): the artefact-catalog type name to emit. Any type declared + in `.pharaoh/project/artefact-catalog.yaml` is accepted, including: + - classical requirement levels — `req`, `comp_req`, `sysreq`, `swreq`, `gd_req`, … + - ISO 26262 safety-V types — `hazard`, `safety_goal`, `fsr`, `tsr`, … + The emitted directive uses `target_level` verbatim as the directive name; the ID prefix, + required fields, and required metadata fields are resolved from the catalog and + `id-conventions.yaml`. If `target_level` is absent the skill falls back to the project's + primary requirement type (`gd_req` in Score, `req` in the bundled defaults) — pass it + explicitly when drafting safety-V artefacts. +- **parent_link** (from user or inferred): ID of the parent the new artefact links to + via the catalog-declared link relation (`:satisfies:` for classical reqs and FSRs, + `:safety_goal_for:` / `:derives_from:` / similar for safety-V — read from the catalog). +- **safety_classification** (optional, from user): metadata block for ASIL-related fields + on safety-V types. Recommended (but not required) when `target_level` is one of + `hazard`, `safety_goal`, `fsr`, or `tsr`. Common shape: + `{asil: "B", severity: "S2", exposure: "E3", controllability: "C2", safe_state: "..."}`. + Each field is emitted only if the catalog declares it as `required_fields` or + `required_metadata_fields`; surplus fields are dropped silently. Missing values for + catalog-required fields are emitted as `` placeholders with a `[FLAG]` line so the + user knows to fill them. - **tailoring** (from `.pharaoh/project/` files): - `id-conventions.yaml` — prefix, separator, and ID regex for each artefact type - - `artefact-catalog.yaml` — required and optional fields for the target type + - `artefact-catalog.yaml` — `required_fields`, `optional_fields`, `required_metadata_fields`, + `required_links`, `lifecycle` for the target type - `checklists/requirement.md` — ISO 26262-8 §6 axes used in self-check - **needs.json** (built artefact index): used for parent resolution and ID uniqueness @@ -45,36 +84,67 @@ A single RST directive block matching the project's requirement prefix (e.g. `gd Read three files from `.pharaoh/project/`: -**1a. `id-conventions.yaml`** +**1a. `artefact-catalog.yaml`** + +Resolve `target_level` against the catalog. Look up the entry whose top-level key equals +`target_level`. If found, record: + +- `required_fields` — every field that must appear in the directive (e.g. `id`, `status`, + `satisfies` for a classical req; plus `asil`, `severity`, `exposure`, + `controllability`, `safe_state` for safety-V types when the catalog declares them) +- `optional_fields` — fields that may appear +- `required_metadata_fields` — option keys that must be set with non-empty values before + release. Treated as required at draft time too — any missing value is emitted as `` + with a `[FLAG]` line. +- `required_links` — link-relation names that every artefact of this type must declare + with a non-empty target list (e.g. `satisfies` for a comp_req, `safety_goal_for` for + an `fsr`, `derives_from` for a `safety_goal`). Use this to pick the right link option + in Step 7 — never hardcode `:satisfies:`. +- `lifecycle` — valid values for `:status:` + +If the entry is absent, FAIL: + +``` +FAIL: target_level "" is not declared in .pharaoh/project/artefact-catalog.yaml. +Add an entry for "" (with required_fields, optional_fields, lifecycle, and any +required_metadata_fields / required_links) before drafting, or pass a target_level that +is already declared. +``` + +If `target_level` was not provided by the caller, fall back to the project's primary +requirement type — the first catalog key whose suffix is `req` (e.g. `gd_req` in Score, +`req` in the bundled defaults) — and note the fallback in the output. Always pass +`target_level` explicitly when drafting safety-V types (`hazard`, `safety_goal`, `fsr`, +`tsr`); the fallback is only safe for classical requirements. + +Built-in default profile (bundled example, used when no catalog is present): `req` with +required = `[id, status, satisfies]`; optional = `[complies, tags, rationale, verification]`; +lifecycle = `[draft, valid, inspected]`. + +**1b. `id-conventions.yaml`** Extract: -- `prefixes` — map of artefact-type key to description (e.g. `gd_req: requirement (guide-level)`) +- `prefixes` — map of artefact-type key to its identifier prefix string. Read the value + for `target_level`. - `separator` — string used between prefix and local-ID part (e.g. `__`) - `id_regex` — regex pattern all generated IDs must match (e.g. `^[a-z][a-z_]*__[a-z0-9_]+$`) - `id_regex_exceptions` — per-type overrides (note: `std_req` is exempt for Score) -Determine the correct prefix key for the requested requirement level. For Score, use `gd_req` for guide-level requirements. If the user specifies a different level, select the matching prefix from the `prefixes` map. If no matching prefix exists, FAIL: +If `prefixes` does not declare `target_level`, FAIL: ``` -FAIL: prefix for level "" not found in id-conventions.yaml. -Available prefixes: +FAIL: id-conventions.yaml prefixes map has no entry for "". +Declare a prefix for "" before drafting. ``` -**1b. `artefact-catalog.yaml`** - -Read the entry for the resolved prefix key. Record: -- `required_fields` — every field that must appear in the directive -- `optional_fields` — fields that may appear -- `lifecycle` — valid values for `:status:` - -Built-in default profile (bundled example): required = `[id, status, satisfies]`; optional = `[complies, tags, rationale, verification]`; lifecycle = `[draft, valid, inspected]`. - **1c. `checklists/requirement.md`** -Read the Individual checklist axes. These will be used in Step 6 self-check. You do not need to apply the Set-level axes at draft time. Record which axes are mechanically checkable at single-requirement level: -- `unambiguity` — one `shall`, no coordinating conjunctions in shall clause -- `atomicity` — body is a single shall statement -- `verifiability` — `:verification:` link present and non-empty +Read the Individual checklist axes. These will be used in Step 6 self-check. You do not need to apply the Set-level axes at draft time. Record which axes are mechanically checkable at single-artefact level: +- `unambiguity` — one `shall`, no coordinating conjunctions in shall clause (applies to + shall-clause types — `req`, `fsr`, `tsr`, `safety_goal`) +- `atomicity` — body is a single shall statement (or a single hazard statement for + `hazard` types — see Step 5) +- `verifiability` — `:verification:` link present and non-empty (where the catalog declares it) --- @@ -152,9 +222,22 @@ Revise the feature_context to use lowercase ASCII words. --- -### Step 5: Draft the requirement body +### Step 5: Draft the body + +Body shape depends on `target_level`: + +- **Shall-clause types** — `req`, `comp_req`, `sysreq`, `swreq`, `gd_req`, `fsr`, `tsr`, + `safety_goal` (and any catalog type whose checklist declares the unambiguity / atomicity + shall axes): write a single shall sentence per the rules below. +- **Hazard types** — `hazard` (and any catalog type that documents an event/situation rather + than a behaviour): write a single declarative sentence describing the hazardous event, + its trigger condition, and the affected vehicle/actor — NO `shall`. Example: + `Unintended ABS pump activation while driving on dry asphalt at >80 km/h causes loss of + braking force on the front axle.` Then rely on the catalog's `required_metadata_fields` + (severity / exposure / controllability / asil) to carry the HARA classification — do + NOT bake those values into the body prose. -Write a single sentence that: +For a **shall-clause** body, write a single sentence that: 1. Uses exactly one `shall` 2. Names a subject (the system, component, or actor) @@ -181,9 +264,9 @@ Bad patterns (reject these in Step 6): Before emitting, run these checks. If a check fails, attempt to re-draft (up to 2 retries). If still failing after 2 retries, emit the directive with a `[DIAGNOSTIC]` annotation explaining the issue. -**Check A — single shall** +**Check A — single shall (shall-clause types only)** -Count occurrences of `shall` in the body. Must be exactly 1. +For shall-clause types, count occurrences of `shall` in the body. Must be exactly 1. ```python assert body.count("shall") == 1 @@ -191,12 +274,19 @@ assert body.count("shall") == 1 If `> 1`: split into the first shall clause and discard the rest. Re-draft a clean single-shall body. -**Check B — no conjunction in shall clause** +For hazard types, skip this check — body must NOT contain `shall`. If `shall` appears in +a hazard body, re-draft the hazard as a declarative event statement. -Extract the shall clause (text from `shall` to end of sentence). Check for `, and `, `, or `, ` and `, ` or ` within it. +**Check B — no conjunction in shall clause (shall-clause types only)** + +For shall-clause types, extract the shall clause (text from `shall` to end of sentence). +Check for `, and `, `, or `, ` and `, ` or ` within it. If found: split into the primary action only. Re-draft. +For hazard types, skip this check — a single hazard sentence may legitimately combine a +trigger condition and an effect (`while driving on dry asphalt and braking…`). + **Check B.bis — no internal symbol in shall clause** Flag any of the following patterns inside the shall body: @@ -210,7 +300,10 @@ If found, re-draft to describe the observable behavior without naming the intern **Check C — parent resolves** -Confirm `satisfies` ID is present in needs.json (already checked in Step 3, re-confirm before emit). +Confirm the parent ID under the catalog-declared link relation (`:satisfies:` for classical +reqs, `:safety_goal_for:` / `:derives_from:` / similar per the catalog's `required_links` +for safety-V types) is present in needs.json (already checked in Step 3, re-confirm before +emit). **Check D — ID unique** @@ -218,36 +311,52 @@ Confirm chosen ID does not appear in needs.json (already checked in Step 4, re-c **Check E — required fields present** -Verify the directive block includes every field from `required_fields` in artefact-catalog.yaml. -For the built-in default profile: `id`, `status`, `satisfies` must all be present. +Verify the directive block includes every field from `required_fields` in +`artefact-catalog.yaml`. For the bundled default profile: `id`, `status`, `satisfies` must +all be present. For a safety-V type whose catalog entry declares e.g. +`required_fields: [id, status, safety_goal_for, asil, severity, exposure, controllability]`, +every one of those options must appear (use `` placeholder when the user did not +supply a value, and emit a `[FLAG]` line per placeholder). + +**Check F — required metadata fields present** + +For each entry in `required_metadata_fields` from the catalog, confirm the directive +emits the option with a non-empty value or a `` placeholder. Emit a `[FLAG]` line +for every `` so the user knows release will block until it is filled. --- ### Step 7: Emit the directive block -Produce the final RST directive. Follow the exact format: +Produce the final RST directive. Use `target_level` verbatim as the directive name. +Emit every option from `required_fields` (with values supplied by the user or `` +placeholders), every link in `required_links` (with the user-supplied parent ID), and +every option in `required_metadata_fields` (value or ``): ```rst -.. :: +.. <target_level>:: <title> :id: <id> :status: draft - :satisfies: <parent_link> - :verification: <test_id or tc__TBD> + :<required_link_relation>: <parent_link> + <... every other field from required_fields ...> + <... every option from required_metadata_fields ...> - <single-sentence body with exactly one shall> + <body per Step 5 — single shall for shall-clause types, declarative event for hazards> ``` Formatting rules: -- Directive line: `.. <prefix>:: <title>` with exactly one space after `..` and one space after `::`. +- Directive line: `.. <target_level>:: <title>` with exactly one space after `..` and one space after `::`. - Options: indented by 3 spaces. Format: `:<option>: <value>`. - One blank line between options block and content body. - Content body: indented by 3 spaces. - One blank line after the content body. -If `:verification:` is set to `tc__TBD`, append a flagged note after the block: +If `:verification:` (or any other field) is set to `<TBD>`, append a flagged note per +placeholder after the block: ``` [FLAG] :verification: set to tc__TBD — link to a real test case before promoting to status=valid. +[FLAG] :asil: set to <TBD> — assign an ASIL level (A/B/C/D/QM) before release. ``` Include optional fields only if the user explicitly provided values for them (e.g. rationale, tags). Do not invent optional field values. @@ -310,12 +419,17 @@ Do not show this if the emit included a `[DIAGNOSTIC]` (the user has a more urge --- -## Worked example +## Worked examples + +### Example 1 — classical guide-level requirement (Score) **Feature context (user input):** -> "The brake controller shall engage the ABS pump when wheel slip exceeds a calibrated threshold. Target level: component. Parent: gd_req__brake_system_safety" +> "The brake controller shall engage the ABS pump when wheel slip exceeds a calibrated +> threshold. target_level: gd_req. Parent: gd_req__brake_system_safety" -**Step 1 result:** prefix = `gd_req`, separator = `__`, id_regex = `^[a-z][a-z_]*__[a-z0-9_]+$`, required = `[id, status, satisfies]`, optional includes `verification`. +**Step 1 result:** catalog entry `gd_req` has `required_fields: [id, status, satisfies]`, +`required_links: [satisfies]`, optional includes `verification`. id-conventions prefix +`gd_req`, separator `__`, id_regex `^[a-z][a-z_]*__[a-z0-9_]+$`. **Step 2 result:** needs.json found at `docs/_build/needs/needs.json`; 185 IDs loaded. @@ -323,10 +437,10 @@ Do not show this if the emit included a `[DIAGNOSTIC]` (the user has a more urge **Step 4 result:** local = `abs_pump_activation`; candidate = `gd_req__abs_pump_activation`; not in needs.json; passes id_regex. ID assigned. -**Step 5 draft body:** +**Step 5 draft body** (shall-clause type): > The brake controller shall engage the ABS pump when measured wheel slip exceeds the calibrated activation threshold. -**Step 6 checks:** `shall` count = 1 ✓; no conjunction in shall clause ✓; parent resolves ✓; ID unique ✓; required fields all present ✓. +**Step 6 checks:** `shall` count = 1 ✓; no conjunction in shall clause ✓; parent resolves ✓; ID unique ✓; required fields all present ✓; no `required_metadata_fields` declared. **Step 7 output:** @@ -347,6 +461,64 @@ Do not show this if the emit included a `[DIAGNOSTIC]` (the user has a more urge Consider running `pharaoh-req-review gd_req__abs_pump_activation` to audit against ISO 26262-8 §6 axes. ``` +### Example 2 — ISO 26262 functional safety requirement (FSR) + +**Feature context (user input):** +> "The braking ECU shall command vehicle deceleration to a defined safe state within +> 100 ms of detecting unintended ABS pump activation. target_level: fsr. +> Parent (the safety goal it implements): sg__no_unintended_abs_pump_activation." +> +> safety_classification: `{asil: "B", safe_state: "wheels_unlocked_no_abs_modulation"}` + +**Step 1 result:** catalog entry for `fsr` declares +`required_fields: [id, status, safety_goal_for, asil, safe_state]`, +`required_links: [safety_goal_for]`, `required_metadata_fields: [asil, safe_state]`, +`lifecycle: [draft, reviewed, approved]`. id-conventions prefix `fsr`, separator `__`. + +**Step 2 result:** needs.json found at `docs/_build/needs/needs.json`; 240 IDs loaded. + +**Step 3 result:** `sg__no_unintended_abs_pump_activation` found in needs.json (type +`safety_goal`). Catalog-declared link relation for `fsr` is `safety_goal_for` (not +`satisfies`) — the skill uses that key, not a hardcoded `:satisfies:`. + +**Step 4 result:** local = `safe_deceleration_on_unintended_pump`; candidate = +`fsr__safe_deceleration_on_unintended_pump`; passes id_regex. ID assigned. + +**Step 5 draft body** (shall-clause type — `fsr` is a requirement-shaped safety-V type): +> The braking ECU shall command vehicle deceleration to the +> `wheels_unlocked_no_abs_modulation` safe state within 100 ms of detecting unintended +> ABS pump activation. + +**Step 6 checks:** `shall` count = 1 ✓; no conjunction ✓; parent resolves ✓; ID unique ✓; +required fields `[id, status, safety_goal_for, asil, safe_state]` all present (asil and +safe_state from `safety_classification`) ✓; required_metadata_fields `[asil, safe_state]` +both non-empty ✓. + +**Step 7 output:** + +```rst +.. fsr:: Safe deceleration on unintended ABS pump activation + :id: fsr__safe_deceleration_on_unintended_pump + :status: draft + :safety_goal_for: sg__no_unintended_abs_pump_activation + :asil: B + :safe_state: wheels_unlocked_no_abs_modulation + + The braking ECU shall command vehicle deceleration to the + wheels_unlocked_no_abs_modulation safe state within 100 ms of detecting + unintended ABS pump activation. +``` + +``` +Consider running `pharaoh-req-review fsr__safe_deceleration_on_unintended_pump` to audit +against ISO 26262-8 §6 axes (the same checklist applies to FSRs as to classical reqs). +``` + +For a hazard-typed draft (`target_level: hazard`), the catalog typically declares +`required_metadata_fields: [severity, exposure, controllability, asil]`. The skill emits +those options as `<TBD>` placeholders when `safety_classification` does not include +them, and the body is a single declarative event sentence (no `shall`) — see Step 5. + ## Last step After emitting the artefact, invoke `pharaoh-req-review` on it. Pass the emitted artefact (or its `need_id`) as `target`. Attach the returned review JSON to the skill's output under the key `review`. If the review emits any axis with `score: 0` or `severity: critical`, return a non-success status with the review findings verbatim and do NOT finalize the artefact — the caller must regenerate (via `pharaoh-req-regenerate` if available, or by re-invoking this skill with the findings as input). diff --git a/skills/pharaoh-setup/SKILL.md b/skills/pharaoh-setup/SKILL.md index 068faa2..b98a1e3 100644 --- a/skills/pharaoh-setup/SKILL.md +++ b/skills/pharaoh-setup/SKILL.md @@ -182,13 +182,18 @@ If the user does not specify, default to `"advisory"`. Pharaoh's workflow gates (`require_change_analysis`, `require_verification`, `require_mece_on_release`) have different natural defaults depending on where the project sits in its lifecycle. Hardcoding the example's values is what produced the pilot feedback: a reverse-engineering project had `require_change_analysis = true` on day one, alarming every newly-drafted need because there was no Pharaoh change issue yet. -Classify the project into one of three modes using the following heuristic (first matching branch wins): +Classify the project into one of three modes by inspecting **declared types in `ubproject.toml`** and **existing RST content under the source tree** — not by `needs.json` existence. `needs.json` is a gitignored build artefact; using it as a signal misclassifies every fresh clone as `reverse-eng` until `sphinx-build` runs. -| Signal | Inferred mode | -| ------------------------------------------------------------------------------------------------ | -------------- | -| `needs.json` exists (e.g. `docs/_build/needs/needs.json`) and contains ≥10 needs. | `steady-state` | -| No `needs.json` or <10 needs, AND the source tree has ≥5 code files AND `docs/` has prose files with section headers that read like user-facing features (e.g. imperative verbs, capability lists). | `reverse-eng` | -| Otherwise (thin project: no needs, minimal src, placeholder docs). | `greenfield` | +Apply rules in order; the first matching branch wins: + +| Signal | Inferred mode | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | +| `[[needs.types]]` declared **and** the source tree has at least one `.. <directive>::` block in any `.rst` file under the source dir **and** ≥10% of those needs carry a status from a "matured" set (`approved`, `closed`, `reviewed`, `passed`). | `steady-state` | +| `[[needs.types]]` declared **and** the source tree has at least one `.. <directive>::` block in any `.rst` file. (Active drafting; not enough matured-status needs to qualify as steady-state yet.) | `reverse-eng` | +| `[[needs.types]]` declared **but** no `.. <directive>::` blocks found in any `.rst` file. (Types declared, no needs authored.) | `greenfield` | +| `[[needs.types]]` **not** declared. Step 1 already routed this case to `pharaoh-bootstrap`; should not reach here. If it does, FAIL. | (n/a) | + +The classifier reads RST files directly; it does NOT depend on `needs.json` and does NOT depend on prose-feature heuristics. The heuristic "`docs/` has prose files with imperative verbs" was previously used to disambiguate `reverse-eng` vs `greenfield` — it is replaced by the cleaner test "are there sphinx-needs directives in the RST tree". Present the detected mode and ask the user to confirm or override: @@ -231,40 +236,117 @@ Generate the `pharaoh.toml` content using the detected project data. Use `pharao - Set `strictness` to the user's choice from Step 2a. **`[pharaoh.id_scheme]` section:** -- Analyze existing need IDs across all project roots to detect the ID pattern. -- Look for common patterns: `{TYPE}_{NUMBER}` (e.g., `REQ_001`), `{TYPE}-{MODULE}-{NUMBER}` (e.g., `REQ-BRAKE-001`), or other conventions. -- Set `pattern` to the detected pattern. If no clear pattern is detected, use `"{TYPE}_{NUMBER}"` as a reasonable default. -- Set `auto_increment = true`. + +Detect the ID pattern descriptively from existing IDs in the RST tree. Do NOT default to `{TYPE}_{NUMBER}` without first checking whether observed IDs conform to it. + +1. Sample existing need IDs: glob `<source-dir>/**/*.rst`, extract the `:id:` value from every sphinx-needs directive (`.. <directive>:: <ID>` or `:id: <ID>`). Take up to 20 samples (or all if fewer exist). +2. Classify the dominant shape: + + | Observed shape | Pattern token | Example | + | ----------------------------------------------------------- | ------------------------- | ---------------------- | + | `<TYPE-PREFIX-FROM-needs.types>_<digits>` | `{TYPE}_{NUMBER}` | `REQ_001`, `FEAT_42` | + | `<TYPE-PREFIX>-<UPPER-MODULE>-<digits>` | `{TYPE}-{MODULE}-{NUMBER}`| `REQ-BRAKE-001` | + | `<UPPER-DOMAIN>_<digits>` where the leading token is **not** any declared type prefix in `[[needs.types]]` | `{DOMAIN}_{NUMBER}` | `BRAKE_CTRL_01`, `FSR_POWER_01` | + | Heterogeneous / no clear shape | (no pattern) | (mixed) | + + The `{DOMAIN}_{NUMBER}` test is what catches the `useblocks/sphinx-needs-demo` case: IDs lead with a domain name (e.g. `BRAKE_CTRL`) rather than the directive's declared type prefix. + +3. Emit the detected pattern as `pattern = "{TYPE}_{NUMBER}"` / `pattern = "{DOMAIN}_{NUMBER}"` / etc. and a comment recording the sample size: + + ```toml + [pharaoh.id_scheme] + # Inferred from 20 sampled IDs in source-dir/**/*.rst. + # Observed shape: {DOMAIN}_{NUMBER} (e.g. BRAKE_CTRL_01). + pattern = "{DOMAIN}_{NUMBER}" + auto_increment = true + ``` + +4. **No-evidence fallback.** If zero IDs are found in the RST tree (greenfield), fall back to `pattern = "{TYPE}_{NUMBER}"` with a comment marking the value as a default not derived from observation: + + ```toml + pattern = "{TYPE}_{NUMBER}" # default; no IDs observed in RST tree + ``` + +5. **Heterogeneous fallback.** If observed IDs do not fit any single shape, emit `pattern = "{ANY}"` with a TODO comment asking the user to declare the project's convention manually. Do NOT silently force `{TYPE}_{NUMBER}`. + +6. `auto_increment = true` is unchanged. + +The matching `id_regex` for `.pharaoh/project/id-conventions.yaml` (Step 5b) is derived from the same observation: for `{DOMAIN}_{NUMBER}` emit `^[A-Z][A-Z0-9_]*_[0-9]+$`; for `{TYPE}_{NUMBER}` emit the union of declared `[[needs.types]] prefix` values + digits anchor; etc. **`[pharaoh.workflow]` section:** -- Populate the three flags from the mode table in Step 2a.bis based on the mode the user confirmed. Do NOT blindly copy values from `pharaoh.toml.example` — that file documents the steady-state shape, not the day-one defaults for every mode. -- Emit a one-line comment above the three flags naming the chosen mode, so a later reader of `pharaoh.toml` can see what assumption produced these values: +- Persist the chosen mode as a real key (`mode = "reverse-eng" | "greenfield" | "steady-state"`). The key lives in `pharaoh.toml` alongside the gate flags so a later reader (and any skill that wants to reason about lifecycle stage) can parse it directly. Do NOT persist it as a comment-only line — comments are not parseable. +- Populate the three gate flags from the mode table in Step 2a.bis based on the mode the user confirmed. Do NOT blindly copy values from `pharaoh.toml.example` — that file documents the steady-state shape, not the day-one defaults for every mode. +- Emit a short rationale comment above the gate flags naming the assumption that produced these values: ```toml [pharaoh.workflow] - # mode: reverse-eng — tighten as the catalogue stabilises + mode = "reverse-eng" + # Gates tuned for reverse-eng — tighten as the catalogue stabilises. require_change_analysis = false - require_verification = false + require_verification = true require_mece_on_release = false ``` **`[pharaoh.traceability]` section:** -- Build `required_links` from the detected extra link types, but **only for type pairs where BOTH types are declared in `ubproject.toml` `[[needs.types]]`.** A chain `comp_req -> test` where `test` is not a declared type is dead config — it alarms on every `comp_req` from day one. Skip it. -- For each extra link type, determine the source and target types by examining the link's usage in existing need directives. If the link name is `implements`, and it appears on `impl` directives pointing to `spec` directives, generate `"spec -> impl"` only if both `impl` and `spec` are declared. -- If usage cannot be determined from existing needs, infer from naming conventions: - - `implements` or `realizes` -> `"spec -> impl"` - - `tests` or `verifies` -> `"impl -> test"` - - `satisfies` or `fulfills` -> `"req -> spec"` - - `derives` or `derives_from` -> `"req -> req"` (parent to child) -- Also check for standard `links` usage to detect implicit traceability chains (e.g., specs linking to reqs via `:links:`). -- If the project has a clear type hierarchy (e.g., req -> spec -> impl -> test), generate the full chain — but filter out any edges whose target type is not declared: - ```toml - required_links = [ - "req -> spec", - "spec -> impl", - # "impl -> test", # SKIPPED: 'test' is not declared in [[needs.types]] - ] - ``` -- If no link types are detected, leave `required_links` as an empty array with a comment explaining how to add entries. + +`required_links` declares chains in the form `"source-type -> target-type"`. The semantics enforced by `pharaoh:mece` are: every need of `source-type` must have at least one outgoing link to a need of `target-type` (see `skills/pharaoh-mece/SKILL.md` Step 2). The chain direction is therefore the direction the link option resolves, **not** the direction of the conceptual type hierarchy. Both conventions exist in the wild — some projects put `:implements:` on the `impl` directive (child references parent, chain `impl -> spec`); others put `:specifies:` on the `spec` directive (parent references child, chain `spec -> impl`). Inferring direction from the link option name picks one convention and emits inverted chains for projects on the other; `pharaoh:mece` then reports 100% gaps for the source type. Resolve direction from ground truth instead. + +Apply the following sources in priority order. For each link option, stop at the first source that resolves a direction. + +**Source 1 — built `needs.json` (preferred, when available).** If the project has a built `needs.json` (typical paths: `<source-dir>/_build/needs/needs.json`, `<source-dir>/_build/html/needs.json`, or any `needs.json` under `_build/`), parse it and inspect the actual edges: + +For each declared link option `L` (including the standard `:links:`) and each ordered pair of declared types `(X, Y)`: + +1. Let `n_X` = count of needs of type `X` whose `:L:` value is non-empty. +2. Let `n_X_to_Y` = count of those needs whose `:L:` resolves to at least one need of type `Y`. +3. Emit `"X -> Y"` only if `n_X >= 3` and `n_X_to_Y / n_X >= 0.9`. + +The thresholds (`>= 3` instances, `>= 90%` coverage) suppress chains inferred from a single accidental edge while still emitting chains the project consistently produces. Include a comment recording the sample size: + +```toml +required_links = [ + "spec -> req", # needs.json: 18/18 spec needs link to req via :reqs: + "impl -> spec", # needs.json: 35/35 impl needs link to spec via :implements: +] +``` + +**Source 2 — declared semantics from `[needs.links.<name>]` (greenfield, no `needs.json`).** The `outgoing` and `incoming` descriptions identify the verb and which side bears the link option, but they do not, on their own, identify the type pair: any type can carry any link option. Without empirical edges or an explicit hint, the source and target types are unknown. + +Use this source only when `ubproject.toml` carries an explicit hint (e.g., a future `[needs.links.<name>] from = "<type>", to = "<type>"` extension). Do not invent the type pair from the link option name. + +**Source 3 — refuse to guess.** When neither source resolves a link option to a `(source-type, target-type)` pair, do **not** emit a chain for that link. Emit a TODO comment in its place so the user sees what was skipped and why: + +```toml +required_links = [ + "spec -> req", # needs.json: 18/18 spec needs link to req via :reqs: + # TODO: link option `implements` is declared but no `needs.json` was + # found. Build the docs once and re-run `pharaoh:setup`, or add an + # explicit chain manually in the form "source-type -> target-type". +] +``` + +The previous heuristic-name table (`implements -> "spec -> impl"`, `tests -> "impl -> test"`, etc.) is removed: it encoded one project convention as universal and produced inverted chains on every project that used the opposite convention. + +**Coverage note.** Source 1 iterates over **every** link option declared in `[needs.links.<name>]` (and the built-in `:links:`). There is no per-link-name allow-list. A `useblocks/sphinx-needs-demo`-style project declaring `verifies`, `satisfies`, `implements`, `triggers`, `derives_from`, etc. has every option evaluated against the same coverage threshold. This closes the PR #14 follow-up: the direction-inference rule is uniform across the full declared set, not specific to a fixed list of relations. + +**Type-pair filter (applied to every source).** Emit a chain only when both the source type and the target type are declared in `ubproject.toml` `[[needs.types]]`. When Source 1 resolves an edge whose target type is not declared, drop it with a comment naming the dropped target — the chain is dead config that would alarm on every source need from day one: + +```toml +required_links = [ + "req -> spec", + "spec -> impl", + # "impl -> test", # SKIPPED: 'test' is not declared in [[needs.types]] +] +``` + +**Empty-array fallback.** If no link option resolves to a chain by any source, emit: + +```toml +required_links = [ + # No traceability chains inferred. Add entries of the form + # "source-type -> target-type" once the link conventions stabilise, + # or build the docs and re-run `pharaoh:setup` to infer from `needs.json`. +] +``` **`[pharaoh.codelinks]` section:** - Set `enabled = true` if sphinx-codelinks was detected in Step 1e. @@ -508,13 +590,267 @@ Determine the current tier: --- -### Step 5b: Bootstrap tailoring from declared types +### Step 5b: Bootstrap tailoring from declared types and observed RST content + +After `pharaoh.toml` is written, generate `.pharaoh/project/{workflows,id-conventions,artefact-catalog}.yaml` plus `checklists/<type>.md` per declared type. The bootstrap is **descriptive**: it captures what the project already declares and what existing RST content already uses, falling back to Pharaoh-internal defaults only when no project signal is available. + +The base shapes and fallbacks are documented in `pharaoh-tailor-bootstrap` — invoke it for the structural emission. Before invoking it, gather the project-state inputs below and pass them as overrides so the emitted tailoring matches the project's reality, not a Pharaoh-internal placeholder set. + +#### 5b.1. Read `[needs.fields.X]` from `ubproject.toml` (artefact-catalog `optional_fields` and `required_metadata_fields`) + +For each declared `[needs.fields.<name>]` table in `ubproject.toml`: + +- The `<name>` is a sphinx-needs option key (e.g. `asil`, `severity`, `exposure`, `controllability`, `safe_state`). +- If the table declares `required = true` (or any explicit-required marker the project uses), add `<name>` to that type's `required_metadata_fields`. +- Otherwise, add `<name>` to that type's `optional_fields`. +- Scope: if `[needs.fields.<name>]` declares `applies_to = ["<type1>", "<type2>"]`, restrict to those types. Without an `applies_to`, treat as global and add to every declared type's `optional_fields`. + +When `[needs.fields.X]` is **declared** in `ubproject.toml`, the Pharaoh-internal placeholder set (`reviewer`, `approved_by`, `source_doc`) is appended only for types that do not already have at least one project-declared field — i.e., we add Pharaoh defaults on top of the project's own fields, never as a replacement. + +When `[needs.fields.X]` is **absent**, fall back to `pharaoh-tailor-bootstrap`'s built-in default (`optional_fields: [reviewer, approved_by, source_doc]`). + +#### 5b.2. Compute lifecycle from RST status histogram (`workflows.yaml lifecycle_states`) + +Glob `<source-dir>/**/*.rst` and parse `:status: <value>` from every sphinx-needs directive. Build a histogram of observed values. + +- If the histogram is non-empty and at least two distinct values appear, set `lifecycle_states` to the observed values, ordered by frequency descending. Emit a comment recording the histogram counts. +- If only one distinct value appears (e.g. every need has `:status: open`), still emit it as the first lifecycle state but append the Pharaoh defaults (`draft`, `reviewed`, `approved`) so transitions are at least defined. +- If no `:status:` fields are found anywhere, fall back to `pharaoh-tailor-bootstrap`'s default `[draft, reviewed, approved]`. + +Worked example for `useblocks/sphinx-needs-demo`-style histogram (`open: 145, closed: 16, passed: 7, approved: 2`): + +```yaml +# workflows.yaml — generated by pharaoh-setup with histogram override +# Observed status counts in <source-dir>/**/*.rst: +# open: 145, closed: 16, passed: 7, approved: 2 +lifecycle_states: + - open + - closed + - passed + - approved + +transitions: + - {from: open, to: passed, requires: []} + - {from: open, to: closed, requires: []} + - {from: passed, to: approved, requires: []} + # Add the inverse (passed -> open, approved -> open) only if the histogram or + # explicit project policy suggests they are reachable. The default is to + # leave the state machine as observed. +``` + +The transition graph is **not** inferred from the histogram (the histogram does not record transitions). The skill emits a permissive forward-only chain `state[i] -> state[i+1]`. The user is expected to edit transitions to match project policy; emit a comment naming this expectation. + +#### 5b.3. Detect ID-prefix collisions (`id-conventions.yaml prefixes`) + +Read `[[needs.types]]` from `ubproject.toml`. Build a map `prefix -> [directive...]`. Any prefix mapping to ≥2 directives is a collision. + +Real-world example from `useblocks/sphinx-needs-demo`: +- `R_` declared on both `req` and `release` +- `T_` declared on both `test` and `team` +- (empty prefix `""`) declared on both `arch` and `need` + +Behaviour by strictness mode (the value chosen in Step 2a): + +- **`advisory`** — emit a WARN to the user listing each collision with a remediation hint, and proceed with the prefixes as-declared (`pharaoh-id-convention-check` will then surface ambiguous IDs at runtime). The warning text: + + ``` + WARNING: ID-prefix collisions detected in [[needs.types]]: + - R_ used for: req, release + - T_ used for: test, team + - "" (empty) used for: arch, need + + Disambiguate by giving each declared type a unique prefix in + ubproject.toml, e.g. release -> REL_, team -> TEAM_, need -> NEED_. + Until disambiguated, pharaoh-id-convention-check cannot tell a release + ID from a requirement ID and pharaoh-id-allocate may emit colliding IDs. + ``` + +- **`enforcing`** — FAIL with the same message and refuse to write `id-conventions.yaml`. The user must fix `[[needs.types]]` first. + +When no collisions are detected, emit `prefixes` directly from `[[needs.types]]` as today. + +#### 5b.4. Detect ID regex from observed IDs (`id-conventions.yaml id_regex`) + +Use the same sample collected in Step 2b's `[pharaoh.id_scheme]` detection: + +- If the dominant observed shape is `{TYPE}_{NUMBER}` and observed IDs match the union of declared prefixes + digits, emit the union-of-prefixes regex (current default). +- If the dominant shape is `{DOMAIN}_{NUMBER}` (leading token does not match any declared type prefix), emit a regex matching the observation: + + ```yaml + id_regex: "^[A-Z][A-Z0-9_]*_[0-9]+$" + ``` + + with a comment naming the sampled IDs. + +- If the observed shape is `{TYPE}-{MODULE}-{NUMBER}`, emit: + + ```yaml + id_regex: "^(REQ|SPEC|IMPL|TEST)-[A-Z]+-[0-9]+$" + ``` + + (substituting actually-declared prefixes). + +- If observed IDs don't conform to a single shape, emit `id_regex: ".+"` with a TODO comment asking the user to declare the convention manually. + +Reject the heuristic union-of-prefixes regex when observed IDs do not match it — the regex would fail validation on every existing need. + +#### 5b.5. Emit Phase-5 release-gate fields per type (artefact-catalog) + +For each declared type, emit `required_links`, `optional_links`, `required_metadata_fields`, `required_roles` per the canonical schema (see `schemas/artefact-catalog.schema.json`): + +- **`required_links`:** for each `[needs.links.<name>]` (also written `[needs.extra_links]` in older sphinx-needs configs) declared with `required = true` — or, when the project has a built `needs.json`, for each link option that 100% of existing needs of this type carry (per Source 1 in `[pharaoh.traceability]` direction inference) — include the option name. +- **`optional_links`:** every other declared link option that is legal on this type (per `[needs.links.<name>] applies_to`, or default to "any declared option not in `required_links`"). Drop overlap with `required_links`. +- **`required_metadata_fields`:** every `[needs.fields.<name>]` declared with `required = true` for this type, plus `status` (every governed type has a lifecycle, so `status` is always required). When the project declares no required fields, emit `[status]`. +- **`required_roles`:** if the project declares any field whose name implies a role (`reviewer`, `approver`, `approved_by`, `responsible`, `assignee`), include the matching options. Otherwise emit `[]` — explicit "no policy", surfaced by `pharaoh-tailor-review` C6 if the user later wants to enforce a review gate. + +`pharaoh-tailor-bootstrap` handles the structural emission; `pharaoh-setup` supplies the derived inputs above. + +#### 5b.6. Invoke `pharaoh-tailor-bootstrap` + +After gathering 5b.1 through 5b.5, invoke `pharaoh-tailor-bootstrap` with: +- `project_root` = the workspace root. +- `on_missing_config` = `"prompt"` (so the user confirms the generated content). +- An overrides bundle carrying the descriptive values from 5b.1–5b.5. When `pharaoh-tailor-bootstrap` does not yet support an explicit overrides input, the caller is responsible for editing the emitted YAML in place to apply the overrides before showing the user the final form. Document this gap; the structural shape is unchanged. + +If the user rejects the proposal, skip — the caller may run `pharaoh-tailor-fill` later (after needs exist) as the alternative path. The `pharaoh-tailor-fill` skill is in fact the canonical descriptive author for matured projects (≥10 needs); `pharaoh-setup` here only seeds the file with what's available at setup time so the project doesn't sit with placeholder defaults. + +#### 5b.7. Worked example — `useblocks/sphinx-needs-demo` + +Concrete walk-through showing how Steps 2 through 5b together emit descriptive tailoring on a project that exposes every defect listed in issue #13 §8. + +**Input — `ubproject.toml` excerpt (paraphrased):** + +```toml +[[needs.types]] +directive = "req" +prefix = "R_" + +[[needs.types]] +directive = "release" +prefix = "R_" # collision with req + +[[needs.types]] +directive = "test" +prefix = "T_" + +[[needs.types]] +directive = "team" +prefix = "T_" # collision with test -After `pharaoh.toml` is written, invoke `pharaoh-tailor-bootstrap` with `project_root` = the workspace root and `on_missing_config` = `"prompt"` (so the user confirms the generated content). +[[needs.types]] +directive = "fsr" +prefix = "FSR_" + +[needs.fields.asil] +applies_to = ["fsr", "safety_goal", "hazard"] +required = true + +[needs.fields.severity] +applies_to = ["hazard"] + +[needs.fields.scenario] +[needs.fields.safe_state] +[needs.fields.customer] + +[needs.links.satisfies] +[needs.links.verifies] +[needs.links.derives_from] +``` + +**Input — observed RST IDs and statuses:** + +- `BRAKE_CTRL_01`, `BRAKE_CTRL_02`, `FSR_POWER_01`, `FSR_POWER_02`, ... (20 sampled, all matching `^[A-Z][A-Z0-9_]*_[0-9]+$`, none matching `^(R_|T_|FSR_)[0-9]+$`) +- Status histogram: `open: 145, closed: 16, passed: 7, approved: 2`. + +**Output — `pharaoh.toml`:** + +```toml +[pharaoh] +strictness = "advisory" + +[pharaoh.id_scheme] +# Inferred from 20 sampled IDs in source-dir/**/*.rst. +# Observed shape: {DOMAIN}_{NUMBER} (e.g. BRAKE_CTRL_01, FSR_POWER_01). +# Note: declared type prefixes (R_, T_, FSR_) do not match the leading +# token of observed IDs — IDs lead with a domain name, not a type prefix. +pattern = "{DOMAIN}_{NUMBER}" +auto_increment = true + +[pharaoh.workflow] +mode = "reverse-eng" +# Gates tuned for reverse-eng — tighten as the catalogue stabilises. +require_change_analysis = false +require_verification = true +require_mece_on_release = false + +[pharaoh.traceability] +# Direction inferred from needs.json edges (Source 1). +required_links = [ + "spec -> req", # 100% of spec needs link to req via :satisfies: + "fsr -> safety_goal", # 100% of fsr needs link to safety_goal via :derives_from: +] + +[pharaoh.codelinks] +enabled = false +``` + +**Output — pre-bootstrap WARNINGS (advisory mode):** + +``` +WARNING: ID-prefix collisions detected in [[needs.types]]: + - R_ used for: req, release + - T_ used for: test, team + +Disambiguate by giving each declared type a unique prefix in +ubproject.toml, e.g. release -> REL_, team -> TEAM_. +``` + +**Output — `.pharaoh/project/workflows.yaml`:** + +```yaml +# Observed status counts in <source-dir>/**/*.rst: +# open: 145, closed: 16, passed: 7, approved: 2 +lifecycle_states: + - open + - closed + - passed + - approved + +transitions: + - {from: open, to: passed, requires: []} + - {from: open, to: closed, requires: []} + - {from: passed, to: approved, requires: []} +``` + +**Output — `.pharaoh/project/id-conventions.yaml`:** + +```yaml +prefixes: + req: R_ + release: R_ # COLLISION — flagged, not silently merged + test: T_ + team: T_ # COLLISION — flagged + fsr: FSR_ +id_regex: "^[A-Z][A-Z0-9_]*_[0-9]+$" +separator: "_" +``` + +**Output — `.pharaoh/project/artefact-catalog.yaml` excerpt for `fsr`:** + +```yaml +fsr: + required_fields: [id, status, title, asil] + optional_fields: [scenario, safe_state, customer, reviewer, approved_by, source_doc] + lifecycle: [open, closed, passed, approved] + required_links: [derives_from] + optional_links: [satisfies, verifies] + required_metadata_fields: [status, asil] + required_roles: [] +``` -This produces `.pharaoh/project/{workflows,id-conventions,artefact-catalog}.yaml` plus `checklists/<type>.md` per declared type. Without this step, every emitted need has `:status: draft` forever with no defined lifecycle transitions. +Compare to the prescriptive default this skill emitted before the rewrite, which would have produced `optional_fields: [reviewer, approved_by, source_doc]` (Pharaoh-internal placeholder set), `lifecycle: [draft, reviewed, approved]` (Pharaoh-internal default), `required_metadata_fields: [status]` (no `asil` despite the project declaring it required), `id_regex: "^(R_|T_|FSR_)[0-9]+$"` (which fails on every actual ID in the project), and `pattern = "{TYPE}_{NUMBER}"` (which assumes the project's IDs lead with a declared type prefix). -If the user rejects the proposal, skip — the caller may run `pharaoh-tailor-fill` later (after needs exist) as the alternative path. +The descriptive emission captures what the project already declares and uses; the prescriptive emission imposed a Pharaoh-internal world-view onto a project that had never agreed to it. --- diff --git a/skills/pharaoh-tailor-bootstrap/SKILL.md b/skills/pharaoh-tailor-bootstrap/SKILL.md index 7163540..b7f4d94 100644 --- a/skills/pharaoh-tailor-bootstrap/SKILL.md +++ b/skills/pharaoh-tailor-bootstrap/SKILL.md @@ -64,7 +64,33 @@ If zero types declared, FAIL: `"no [[needs.types]] in ubproject.toml; run pharao ### Step 2: Emit workflows.yaml -For each declared type, emit a block with states `draft`, `reviewed`, `approved`, transitions `draft→reviewed` (gate `reviewer_present`), `reviewed→approved` (gate `approver_present`), `reviewed→draft` (gate `reviewer_rejected`), initial `draft`, final `approved`. +Emit a single project-wide state machine matching `schemas/workflows.schema.json`: a flat `lifecycle_states` list and a `transitions` array where each entry has `from`, `to`, and a `requires` list (always a list, never a scalar `gate` field). + +Default content for a greenfield bootstrap: + +```yaml +# workflows.yaml — generated by pharaoh-tailor-bootstrap +# Validates against schemas/workflows.schema.json. +# Edit transitions[*].requires to declare per-transition prerequisites. + +lifecycle_states: + - draft + - reviewed + - approved + +transitions: + - from: draft + to: reviewed + requires: [] + - from: reviewed + to: approved + requires: [] + - from: reviewed + to: draft + requires: [] +``` + +The state machine is project-wide, not per-type — `artefact-catalog.yaml` declares which subset of `lifecycle_states` applies to each type via its own `lifecycle` field (Step 4). `requires` is always a list of gate-name strings (empty list permitted); it replaces any older single-string `gate:` field. See `expected_output/workflows.yaml` in the fixture for exact format. @@ -79,8 +105,49 @@ See fixture for exact format. For each declared type, emit: - `required_fields`: at minimum `id`, `status`. - `optional_fields`: `reviewer`, `approved_by`, plus `source_doc` for types that typically carry provenance (heuristic: top-level types like `feat`, `story`, `use_case` — if unsure, include it). -- `child_of`: list of parent types inferred from extra_links. Rule: if `satisfies` link exists, types that commonly use it (`comp_req`, `spec`, `impl`) list their parent (`feat`, `story`, etc.). If no clear inference, `child_of: []` — caller tunes later. -- `lifecycle_ref`: `workflows.yaml#<type>`. +- `lifecycle`: list of states from `workflows.yaml` that apply to this type (typically the full state list). +- `required_body_sections`: optional list of body-prose section headings (e.g. `Inputs`, `Steps`, `Expected` for `tc`); omit when no body sections are required. +- `required_links`, `optional_links`, `required_metadata_fields`, `required_roles`: release-gate fields read by `pharaoh-link-completeness-check`, `pharaoh-output-validate`, and `pharaoh-review-completeness` (and aggregated by `pharaoh-quality-gate`). Emit all four as arrays of strings — empty arrays are valid and declare an explicit "no requirement" choice; absent keys are flagged by `pharaoh-tailor-review` rule C6 as an unmade decision. + +Inference rules for the four release-gate fields: + +- `required_links`: include the `option` of every `[[needs.extra_links]]` entry that resolves to this type as the source side of the link. Concretely: for an extra_link with `outgoing: <this_type>` (the link is declared on directives of this type), include its `option`. If the project does not declare the direction explicitly, default to including link options whose semantic name implies a parent reference (`satisfies`, `verifies`, `refines`, `derives_from`) for downstream artefact types (anything with `_req`, `arch`, `tc`, `impl`, `spec` in its directive). Other types default to `[]`. +- `optional_links`: any other extra_link `option` that may legally appear on this type but is not in `required_links`. Default to `[]` when no other links are declared. +- `required_metadata_fields`: include `status` always (every governed type has a lifecycle). Add any field that the project's `[needs.fields.X]` table declares as required for this directive. If `ubproject.toml` carries no such hints, emit `[status]`. +- `required_roles`: emit `[]` by default — bootstrap runs on greenfield projects with no observed review process. Tailoring authors are expected to fill in `[reviewer]` (or `[reviewer, approved_by]`) once a review gate is established. `pharaoh-tailor-review` rule C6 surfaces a finding if the key is absent so the project explicitly declares the choice. + +Worked example for a `comp_req` directive with `[[needs.extra_links]] option = "satisfies", outgoing = "comp_req"`: + +```yaml +comp_req: + required_fields: [id, status, title, satisfies] + optional_fields: [reviewer, approved_by, source_doc] + lifecycle: [draft, reviewed, approved] + required_links: [satisfies] + optional_links: [] + required_metadata_fields: [status] + required_roles: [] +``` + +A type with no observed link declarations emits empty arrays: + +```yaml +feat: + required_fields: [id, status, title] + optional_fields: [reviewer, approved_by, source_doc] + lifecycle: [draft, reviewed, approved] + required_links: [] + optional_links: [] + required_metadata_fields: [status] + required_roles: [] +``` + +Empty arrays are deliberate: they say "the project considered this and chose no requirement". Omitting the key entirely is what `pharaoh-tailor-review` flags as an unmade decision (rule C6). + +The emitted `artefact-catalog.yaml` validates against +`schemas/artefact-catalog.schema.json` shipped at the Pharaoh package root +(see `schemas/README.md`). `pharaoh-tailor-review` enforces this on the +output of every bootstrap run. ### Step 5: Emit per-type checklists diff --git a/skills/pharaoh-tailor-fill/SKILL.md b/skills/pharaoh-tailor-fill/SKILL.md index ae94cce..1a31b2c 100644 --- a/skills/pharaoh-tailor-fill/SKILL.md +++ b/skills/pharaoh-tailor-fill/SKILL.md @@ -118,10 +118,10 @@ id_regex: "^[a-z][a-z_]*__[a-z0-9_]+$" id_regex_exceptions: {} prefixes: - gd_req: "requirement (guide-level)" - wp: "work product" - wf: "workflow" - tc: "test case" + gd_req: GD_REQ_ + wp: WP_ + wf: WF_ + tc: TC_ # ... one entry per detected prefix ``` @@ -129,14 +129,13 @@ Rules: - `separator`: value from detect report; if `null`, write `separator: null # WARNING: not detected` - `id_regex`: value from `id_regex_candidate`; if `null`, write placeholder with warning comment - `id_regex_exceptions`: map from detect report `id_regex_exceptions`; empty map if none -- `prefixes`: one key per detected prefix from `detected_conventions.prefixes`; derive a - short human description from the prefix name using common conventions: - - suffix `_req` → "requirement (<qualifier>)" - - `wp` → "work product" - - `wf` → "workflow" - - `tc` → "test case" - - `chklst` → "checklist" - - otherwise → `"<prefix> artefact"` (placeholder) +- `prefixes`: one key per detected prefix from `detected_conventions.prefixes`. The value is the + identifier-prefix string that gets prepended to the local-part to form an id (e.g. `REQ_`, + `FEAT_`, `BRAKE_CTRL_`, or just `tc` if the project uses the directive name itself as the + prefix). Take the value from the detect report's `prefixes[<key>]`; if the detect report + reports the prefix as the directive name itself (e.g. `tc__`), use the directive name as + the value. Do not author human descriptions in the value position — `prefixes` is consumed + by `pharaoh-id-allocate` and must be a literal prefix token, not prose. --- @@ -181,12 +180,13 @@ Format: ```yaml # workflows.yaml — generated by pharaoh-tailor-fill +# Validates against schemas/workflows.schema.json. # Review default transitions before committing. lifecycle_states: - draft: "Initial authoring state — not yet reviewed" - valid: "Review completed — approved for use" - inspected: "Independent inspection passed" + - draft + - valid + - inspected transitions: - from: draft @@ -198,9 +198,10 @@ transitions: - from: inspected to: draft requires: [] - note: "regression path — allowed without prerequisite" ``` +State descriptions live in code review notes or per-project docs, not in `workflows.yaml` — `lifecycle_states` is a flat list of state-name strings per the schema. The optional `note:` field is not part of the schema and must be dropped from emitted output. + --- ### Step 5: Write artefact-catalog.yaml @@ -214,9 +215,13 @@ For each artefact type, emit a YAML block: required_fields: [<fields from observed_fields_required, excluding id — always implicit>] optional_fields: [<fields from observed_fields_optional>] lifecycle: [<lifecycle_states_observed>] # omit if prefix has no status field + required_links: [<link options observed on every need of this type>] + optional_links: [<link options observed on some but not all needs of this type>] + required_metadata_fields: [<option keys observed non-empty on every need of this type>] + required_roles: [<reviewer/approval options observed non-empty on every need of this type>] ``` -Rules: +Rules for the basic shape: - Include `id` and `status` in `required_fields` always (structural). - Copy remaining `observed_fields_required` field names (drop counts — counts are detect output, not catalog schema). @@ -225,11 +230,51 @@ Rules: - Add a YAML comment noting frequency for any field that was close to the 95% threshold (between 90–95%): `# <field>: present in <N>% of corpus — considered required by threshold`. +Rules for the four release-gate fields. These are read by +`pharaoh-link-completeness-check`, `pharaoh-output-validate`, and +`pharaoh-review-completeness` and aggregated by `pharaoh-quality-gate`. Empty +arrays are valid and explicit; absent keys are flagged by +`pharaoh-tailor-review` rule C6: + +- `required_links`: every link option that appears non-empty on ≥95% of needs of this type + (same threshold as `required_fields`). +- `optional_links`: link options that appear on ≥20% but <95% of needs. +- `required_metadata_fields`: option keys (excluding link options and the structural `id`) + that appear non-empty on ≥95% of needs of this type. Always include `status` for any type + with a lifecycle. +- `required_roles`: include `reviewer` if observed non-empty on ≥80% of needs of this type; + include `approved_by` if observed non-empty on ≥80%. The fill path is more opinionated + than the bootstrap path: detected presence in the corpus is the signal that the project + treats the role as required, even if the threshold for `required_fields` (95%) was not met. + +Always emit all four keys, even as empty arrays. Empty array means "the project's data shows +no requirement for this type"; omitting the key means "we never decided" — and rule C6 flags +the latter at review time. + +Worked example for a `comp_req` type whose corpus shows `satisfies` on every need, +`verifies` on 60%, `priority` non-empty on every need, `reviewer` on 90%, and +`approved_by` on 30%: + +```yaml +comp_req: + required_fields: [id, status, title, satisfies] + optional_fields: [reviewer, approved_by, priority, verifies] + lifecycle: [draft, reviewed, approved] + required_links: [satisfies] + optional_links: [verifies] + required_metadata_fields: [status, priority] + required_roles: [reviewer] +``` + Format header: ```yaml # artefact-catalog.yaml — generated by pharaoh-tailor-fill from pharaoh-tailor-detect output # Threshold: required = present in >= 95% of instances; optional = >= 20%. +# Release-gate fields (required_links, optional_links, required_metadata_fields, +# required_roles) read by pharaoh-link-completeness-check, pharaoh-output-validate, +# pharaoh-review-completeness; aggregated by pharaoh-quality-gate. Empty array means +# "explicit no requirement"; absent key is flagged by pharaoh-tailor-review C6. ``` --- diff --git a/skills/pharaoh-tailor-review/SKILL.md b/skills/pharaoh-tailor-review/SKILL.md index 7eb8aca..730b030 100644 --- a/skills/pharaoh-tailor-review/SKILL.md +++ b/skills/pharaoh-tailor-review/SKILL.md @@ -23,9 +23,16 @@ Do NOT invoke to author or repair tailoring files — use `pharaoh-tailor-fill` - **tailoring_dir** (from user): path to `.pharaoh/project/` containing the four tailoring files -- **schemas_dir** (from user, optional): path to JSON schema files. Defaults to - `<tailoring_dir>/schemas/` if that directory exists; otherwise applies built-in structural - checks (see Step 2). +- **schemas_dir** (from user, optional): path to JSON schema files. Resolved in + this order: + 1. The explicit value if provided. + 2. `<tailoring_dir>/schemas/` if that directory exists (per-project overrides). + 3. The Pharaoh-shipped `schemas/` directory at the package root + (`<pharaoh_repo>/schemas/`). This is the default and ships with the four + canonical schemas (`artefact-catalog.schema.json`, `workflows.schema.json`, + `id-conventions.schema.json`, `checklists-frontmatter.schema.json`). + 4. If none of the above resolve, falls back to built-in structural rules and + emits a `degraded_mode: true` flag in the output. The four expected files: - `<tailoring_dir>/id-conventions.yaml` @@ -117,9 +124,10 @@ but do not replace them. | `prefixes` | map | Must be present; must contain at least one entry | | `id_regex_exceptions` | map | Optional; if present must be a map of `<prefix>: <regex>` where `<prefix>` is declared in the `prefixes` map | -For each entry in `prefixes`, the key must be a non-empty string and the value must be a -non-empty string (the description). See -`examples/my-project/.pharaoh/project/schemas/id-conventions.schema.json` for the authoritative +For each entry in `prefixes`, the key must be a non-empty string and the value must be +a literal identifier-prefix token (matches schema pattern `^[A-Za-z][A-Za-z0-9_]*$`); +not a human description. See +`<pharaoh_repo>/schemas/id-conventions.schema.json` for the authoritative JSON Schema. **workflows.yaml required keys:** @@ -134,7 +142,7 @@ For each transition in `transitions`: - `from` and `to` must be non-empty strings. - `requires` must be a list (may be empty). -See `examples/my-project/.pharaoh/project/schemas/workflows.schema.json` for the authoritative +See `<pharaoh_repo>/schemas/workflows.schema.json` for the authoritative JSON Schema. **artefact-catalog.yaml required structure:** @@ -147,15 +155,19 @@ Top level must be a map of artefact-type keys. For each artefact type: | `optional_fields` | list | Optional; may be empty. Entries are sphinx-needs *option* keys. | | `required_body_sections` | list | Optional; entries are top-level heading names that must appear inside the directive body prose (e.g. `Inputs`, `Steps`, `Expected` for `tc`). Validated as body prose, not as `:key:` options. | | `lifecycle` | list | Optional; if present must be non-empty | +| `required_links` | list | Optional; entries are link-relation option names (e.g. `satisfies`). Empty list disables the release-gate check for this type; absent key is treated as empty by `pharaoh-link-completeness-check` but flagged by C6 below. | +| `optional_links` | list | Optional; entries are link-relation option names. Must not overlap with `required_links` (enforced by C6). | +| `required_metadata_fields` | list | Optional; entries are sphinx-needs option keys. Empty list disables the release-gate check; absent key is flagged by C6. | +| `required_roles` | list | Optional; entries are role-bearing option keys (e.g. `reviewer`, `approved_by`). Empty list explicitly declares no review/approval gate; absent key is flagged by C6. | -See `examples/my-project/.pharaoh/project/schemas/artefact-catalog.schema.json` for the +See `<pharaoh_repo>/schemas/artefact-catalog.schema.json` for the authoritative JSON Schema. **checklists/*.md frontmatter:** YAML frontmatter (delimited by `---`) at the top of a checklist file is **optional**. When present, it is validated against -`examples/my-project/.pharaoh/project/schemas/checklists-frontmatter.schema.json`: +`<pharaoh_repo>/schemas/checklists-frontmatter.schema.json`: | Key | Rule | |---|---| @@ -224,6 +236,40 @@ Violation (error): Field '<field>' appears in both required_fields and optional_fields for artefact type '<type>' in artefact-catalog.yaml. ``` +**C6 — Release-gate fields declared explicitly** + +The four release-gate fields on each per-type entry of `artefact-catalog.yaml` are +consumed by `pharaoh-link-completeness-check` (`required_links`, `optional_links`), +`pharaoh-output-validate` (`required_metadata_fields`), and `pharaoh-review-completeness` +(`required_roles`); all four are aggregated by `pharaoh-quality-gate`. Each consumer +treats an absent key as an empty list, so a project that omits all four fields ships a +release gate that silently does nothing. C6 makes the choice explicit: + +For every artefact type entry in `artefact-catalog.yaml`, three of the four fields must +be **present as keys** (the value may be an empty array). The three keys are +`required_links`, `required_metadata_fields`, `required_roles`. `optional_links` is +not part of C6 — it is purely informational and absent-equals-empty is fine. + +Violation (warning) for each missing key: +``` +Release-gate key '<field>' is absent from artefact-catalog.yaml for type '<type>'. Empty array declares an explicit "no requirement"; missing key is treated as empty by consumers but means the project never made the choice. Add the key with an empty list `[]` if no requirement applies. +``` + +Where `<field>` is one of `required_links`, `required_metadata_fields`, `required_roles`. + +Additionally — when both `required_links` and `optional_links` are present, no link +name may appear in both lists. + +Violation (error): +``` +Link name '<link>' appears in both required_links and optional_links for artefact type '<type>' in artefact-catalog.yaml. +``` + +The missing-key part of C6 is a `severity: warning` rather than `error` so that legacy +tailoring continues to validate while the project decides; the overlap-check part is +`severity: error` because consumers cannot reconcile a link declared as both required +and optional. + --- ### Step 4: Compute overall and emit @@ -239,22 +285,26 @@ Emit the JSON document. No prose before or after. ## Schema validation -Four JSON Schema (draft 2020-12) files live alongside the tailoring files and make structural +Four JSON Schema (draft 2020-12) files ship with Pharaoh and make structural validation deterministic: | Tailoring file | Schema | |---|---| -| `id-conventions.yaml` | `<tailoring_dir>/schemas/id-conventions.schema.json` | -| `workflows.yaml` | `<tailoring_dir>/schemas/workflows.schema.json` | -| `artefact-catalog.yaml` | `<tailoring_dir>/schemas/artefact-catalog.schema.json` | -| `checklists/*.md` (frontmatter) | `<tailoring_dir>/schemas/checklists-frontmatter.schema.json` | +| `id-conventions.yaml` | `<schemas_dir>/id-conventions.schema.json` | +| `workflows.yaml` | `<schemas_dir>/workflows.schema.json` | +| `artefact-catalog.yaml` | `<schemas_dir>/artefact-catalog.schema.json` | +| `checklists/*.md` (frontmatter) | `<schemas_dir>/checklists-frontmatter.schema.json` | + +`<schemas_dir>` is resolved per the order documented in Inputs above; the +default is the Pharaoh-shipped `schemas/` directory at the package root. See +`schemas/README.md` for the full resolution order and per-file responsibilities. Schema `$id` values are anchored under `https://pharaoh.useblocks.com/schemas/` and do not need to resolve at runtime. -The `pharaoh-validation` harness runs `python harness/validate_tailoring.py` to execute -these checks mechanically (exits 0 on all-PASS). Cross-file consistency rules C1–C5 are -**not** expressible in JSON Schema and remain implemented in Step 3 of this skill. +These checks can be executed by any JSON Schema validator against the canonical +schemas in `schemas/`. Cross-file consistency rules C1–C6 are **not** expressible in +JSON Schema and remain implemented in Step 3 of this skill. --- @@ -307,6 +357,8 @@ All four files present and well-formed. Cross-file check results: - C4: all six prefixes in id-conventions also appear in artefact-catalog. No orphan prefixes. Pass. - C5: no field appears in both required and optional for any type. Pass. +- C6: every artefact type declares `required_links`, `required_metadata_fields`, and + `required_roles` keys (empty arrays permitted). Pass. **Output:** diff --git a/skills/pharaoh-verify/SKILL.md b/skills/pharaoh-verify/SKILL.md new file mode 100644 index 0000000..250d4dd --- /dev/null +++ b/skills/pharaoh-verify/SKILL.md @@ -0,0 +1,330 @@ +--- +name: pharaoh-verify +description: Use when checking whether one sphinx-needs artefact actually addresses the substance of every parent it links to via :satisfies: or :verifies:. Cross-need content check — distinct from structural MECE, schema-level tailor-review, and per-axis req-review/arch-review. +chains_from: [pharaoh-author, pharaoh-req-draft, pharaoh-arch-draft, pharaoh-vplan-draft] +chains_to: [pharaoh-mece] +--- + +# pharaoh-verify + +## When to use + +Invoke when the user has one need-id (drafted, modified, or already-published) and wants to +know whether its body actually addresses the substance of its parent — does the architecture +element discharge the requirement, does the test case exercise the requirement's claim, does +the decision close the question its `:decides:` target raised. + +This is a **cross-need content check**. It is the only Pharaoh skill that compares two needs' +bodies for substantive coverage. + +How it differs from the neighbouring review skills: + +| Skill | Scope | Question answered | +|---|---|---| +| `pharaoh-mece` | full corpus | Are required links present? Are there orphans / gaps? (structural) | +| `pharaoh-tailor-review` | tailoring files | Does `.pharaoh/project/` validate against the schemas? (schema-level) | +| `pharaoh-req-review` | one requirement | Does this requirement pass the 11 ISO 26262 §6 axes? (per-axis prose rubric) | +| `pharaoh-arch-review` | one architecture element | Same axes plus arch-specific axes (per-axis prose rubric) | +| `pharaoh-vplan-review` | one test case | Same axes plus vplan-specific axes (per-axis prose rubric) | +| **`pharaoh-verify`** | one child + its parents | Does the child's body actually address the parent's substance? (content-level satisfaction) | + +Do NOT use when: + +- The user wants per-axis prose grading — use `pharaoh-req-review` / `pharaoh-arch-review` / + `pharaoh-vplan-review`. +- The user wants gap or orphan analysis across the corpus — use `pharaoh-mece`. +- The user wants to know if the tailoring files are well-formed — use `pharaoh-tailor-review`. + +--- + +## Inputs + +- **need_id** (from user): the child need-id to verify. Must exist in `needs.json`. +- **transitive** (from user, optional, default `false`): if `true`, walk every `:satisfies:` + / `:verifies:` link transitively and verify each ancestor pair (child↔direct-parent, + direct-parent↔grandparent, …). If `false`, verify only the direct parents. +- **tailoring** (from `.pharaoh/project/`): + - `artefact-catalog.yaml` — read the link-relationship map: which link types carry the + "satisfies its parent" semantics for each artefact type. Defaults: `:satisfies:` for + requirements and architecture; `:verifies:` for test cases; `:decides:` for decisions. + - `id-conventions.yaml` — only used when reporting parent IDs that fail the regex +- **needs.json**: required for body lookup on both child and every parent + +--- + +## Outputs + +A single JSON document. Shape: + +```json +{ + "need_id": "<child-id>", + "child_type": "<type>", + "parents": [ + { + "parent_id": "<id>", + "parent_type": "<type>", + "link_field": "satisfies|verifies|decides", + "verdict": "addresses|partial|absent|unresolved", + "score": 3, + "reason": "one-sentence justification", + "missing_aspects": ["..."] + } + ], + "overall": "addresses|partial|absent", + "action_items": ["..."] +} +``` + +### Verdict scale + +Per parent, score the child body on a 0-3 ordinal: + +| Score | Verdict | Definition | +|---|---|---| +| 3 | `addresses` | Child body explicitly covers every claim, condition, or actor named in the parent. No substantive aspect of the parent is missing. | +| 2 | `addresses` | Child covers all major claims; minor wording or a marginal sub-claim is paraphrased rather than restated. | +| 1 | `partial` | Child covers some but not all of the parent's substantive claims. Concrete missing aspects are listed in `missing_aspects`. | +| 0 | `absent` | Child body is generic, off-topic, or names the parent ID without substantively addressing the parent's claim. | +| n/a | `unresolved` | Parent ID does not resolve in `needs.json` — record as `unresolved` and skip scoring this pair. | + +### Overall + +Computed across all parent pairs (excluding `unresolved`): + +- `addresses` — every pair scores ≥ 2 +- `partial` — at least one pair scores 1, no pair scores 0 +- `absent` — at least one pair scores 0 + +If every parent is `unresolved`, set `overall` to `"absent"` and add an action item naming the +unresolved parents. + +--- + +## Process + +### Step 1: Resolve child + +Find `needs.json` (check `docs/_build/needs/needs.json`, then `_build/needs/needs.json`, then +any `needs.json` under a `_build` directory). If not found, FAIL: + +``` +FAIL: needs.json not found. Build the Sphinx project first +(`sphinx-build docs/ docs/_build/`), then re-run this skill. +``` + +Look up `need_id`. If not present, FAIL: + +``` +FAIL: need_id "<id>" not found in needs.json. +Verify the ID or build the project. +``` + +Extract the child's type, body, and the values of every parent-link field that applies to its +type per `artefact-catalog.yaml` (default mapping: requirements → `:satisfies:`; architecture +→ `:satisfies:`; test cases → `:verifies:`; decisions → `:decides:`). + +If the child has no parent-link values at all, emit: + +```json +{ + "need_id": "<id>", + "child_type": "<type>", + "parents": [], + "overall": "absent", + "action_items": [ + "Child has no :satisfies:/:verifies:/:decides: link. Add a parent before verifying." + ] +} +``` + +and stop. + +--- + +### Step 2: Resolve parents + +For each parent ID listed in the child's link fields, look it up in `needs.json`: + +- If found, capture the parent's type and body. +- If not found, mark the pair `verdict: "unresolved"` and continue. + +If `transitive = true`, push each resolved parent onto a queue and repeat Step 2 for its own +parents. Maintain a visited set to avoid cycles. The output `parents` list is flattened — +each parent appears once with its direct child noted in `link_field`. + +--- + +### Step 3: Score each pair + +For each (child, parent) pair, read both bodies and answer the satisfaction question for the +relevant link semantics: + +| Link field | Question to answer | +|---|---| +| `satisfies` | Does the child's prose discharge the parent requirement's claim — i.e. would building only what the child describes satisfy what the parent demands? | +| `verifies` | Does the test case's inputs / steps / expected outcome exercise the specific behaviour the parent requires? Would a passing run of this test give evidence the parent is met? | +| `decides` | Does the decision body resolve the design question that the affected need raises — alternatives weighed, choice stated, rationale matches the parent's concern? | + +Score on the 0-3 scale above. Be concrete in `reason` — name the parent claim that is or is +not covered. When `score < 2`, populate `missing_aspects` with the specific claims, actors, +or conditions from the parent that the child fails to address. + +For test cases, also flag `partial` when the test only exercises a happy path while the +parent requires negative or boundary cases. + +--- + +### Step 4: Compute overall and action items + +Compute `overall` per the table above. For every pair with `score < 2` or +`verdict == "unresolved"`, add a concrete action item naming the parent and the missing +aspect: + +``` +"satisfies <parent_id>: child does not cover <missing aspect>; rewrite the body to address it" +``` + +If every pair scores ≥ 2, `action_items` is an empty array. + +--- + +### Step 5: Emit JSON + +Emit the JSON document only. No prose wrapper. + +If `overall != "addresses"`, append below the JSON a single advisory line: + +``` +Consider `pharaoh-author <need_id>` to revise the body, or `pharaoh-req-regenerate <need_id>` +for a per-axis driven rewrite. Re-run `pharaoh-verify <need_id>` after the edit. +``` + +This is the only prose permitted after the JSON. + +--- + +## Guardrails + +**G1 — Child not found** + +`need_id` absent from `needs.json` → FAIL (Step 1). + +**G2 — Child has no parent links** + +Emit a JSON document with empty `parents` and a clear action item, then stop (Step 1). Do not +guess a parent. + +**G3 — All parents unresolved** + +Set `overall = "absent"`; do not crash. Action items must list every unresolved parent ID so +the user can fix the link or build the project first. + +**G4 — Empty bodies** + +If either the child's body or a parent's body is empty (only the title is set), score that +pair `0` with `reason: "<role> body is empty — substantive verification not possible"` and +add an action item to populate the body before re-running. + +--- + +## Advisory chain + +This skill has `chains_to: [pharaoh-mece]` because content satisfaction is the natural sibling +of structural MECE. After verifying one need, the user often wants the corpus-wide structural +view next: + +``` +Consider running `pharaoh-mece` to confirm the surrounding link structure +(orphans, gaps, status inconsistencies) is also healthy. +``` + +Show this line only when `overall == "addresses"`. + +--- + +## Worked example + +**User input:** + +> need_id: `arch__abs_pump_driver` +> transitive: false + +**Step 1:** child resolves; type `arch`. Parent-link field for `arch` is `:satisfies:`. Value: +`gd_req__abs_pump_activation`. + +**Step 2:** parent resolves. Body: "The brake controller shall engage the ABS pump when +measured wheel slip exceeds the calibrated activation threshold." + +**Step 3:** child body: "The ABS pump driver component manages the pump drive circuit, +controlling output PWM duty cycle and providing over-current protection for the pump motor." + +The child names the pump drive circuit and the actuation mechanism (PWM, over-current) but +does not state how the wheel-slip-threshold trigger reaches the driver. Score 2 — addresses +the actuation claim but the trigger linkage is implicit. + +**Step 4:** `overall = "addresses"`; one minor `missing_aspect` recorded. + +**Step 5 output:** + +```json +{ + "need_id": "arch__abs_pump_driver", + "child_type": "arch", + "parents": [ + { + "parent_id": "gd_req__abs_pump_activation", + "parent_type": "gd_req", + "link_field": "satisfies", + "verdict": "addresses", + "score": 2, + "reason": "child covers pump actuation and protection; the wheel-slip trigger linkage is implicit, not restated", + "missing_aspects": ["wheel-slip-threshold trigger pathway from sensor to driver"] + } + ], + "overall": "addresses", + "action_items": [] +} +``` + +``` +Consider running `pharaoh-mece` to confirm the surrounding link structure is also healthy. +``` + +--- + +**Variant: child does not address the parent** + +Same parent, but the child body reads: "The ABS pump driver component logs telemetry every +100 ms to the CAN bus." Logging is unrelated to the parent's actuation claim. + +```json +{ + "need_id": "arch__abs_pump_driver", + "child_type": "arch", + "parents": [ + { + "parent_id": "gd_req__abs_pump_activation", + "parent_type": "gd_req", + "link_field": "satisfies", + "verdict": "absent", + "score": 0, + "reason": "child describes telemetry logging only; does not address pump engagement on slip threshold", + "missing_aspects": [ + "ABS pump engagement actuation", + "wheel-slip-threshold trigger pathway" + ] + } + ], + "overall": "absent", + "action_items": [ + "satisfies gd_req__abs_pump_activation: child does not cover pump engagement; rewrite the body to describe the actuation pathway and the slip-threshold trigger" + ] +} +``` + +``` +Consider `pharaoh-author arch__abs_pump_driver` to revise the body, or `pharaoh-req-regenerate +arch__abs_pump_driver` for a per-axis driven rewrite. Re-run `pharaoh-verify +arch__abs_pump_driver` after the edit. +``` diff --git a/skills/pharaoh-vplan-draft/SKILL.md b/skills/pharaoh-vplan-draft/SKILL.md index 5ffdda4..be41d68 100644 --- a/skills/pharaoh-vplan-draft/SKILL.md +++ b/skills/pharaoh-vplan-draft/SKILL.md @@ -1,6 +1,6 @@ --- name: pharaoh-vplan-draft -description: Use when drafting a single sphinx-needs test-case (verification plan item) for one requirement. Emits an RST tc__ directive with inputs, steps, and expected outcome, linking to the parent req via :verifies:. +description: Use when drafting a single sphinx-needs test-case (verification plan item) for one requirement. The artefact type is parameterised via `target_level` (any catalog-declared verification-plan / test-case type — e.g. `tc`, `test`, `vplan`). Emits an RST directive with inputs, steps, and expected outcome, linking to the parent req via `:verifies:`. chains_from: [pharaoh-req-draft, pharaoh-req-regenerate, pharaoh-arch-draft] chains_to: [pharaoh-vplan-review] --- @@ -10,7 +10,10 @@ chains_to: [pharaoh-vplan-review] ## When to use Invoke when the user has a validated requirement (or architecture element) and wants to derive a -single test case that verifies it. Each invocation produces exactly one `tc__` directive. +single test case that verifies it. Each invocation produces exactly one directive of the +catalog-declared verification-plan type. The directive name and ID prefix are resolved from +the project's tailoring; this skill is type-agnostic and supports any catalog-declared +verification-plan type (typical names: `tc`, `test`, `vplan`). Do NOT draft multiple test cases in one invocation — one test case per call. Do NOT draft test cases for requirements that are not verifiable (see Guardrail G3). @@ -22,11 +25,16 @@ Do NOT review — use `pharaoh-vplan-review` after drafting. - **parent_id** (from user): need-id of the parent requirement or architecture element to verify — must exist in needs.json -- **verification_level** (from user): one of `unit`, `integration`, or `system` +- **target_level** (from user, default `tc`): the artefact-catalog type name to emit. Any + verification-plan / test-case type declared in `.pharaoh/project/artefact-catalog.yaml` + is accepted. The emitted directive uses `target_level` verbatim as the directive name; the + ID prefix is resolved from `id-conventions.yaml`'s `prefixes` map. +- **verification_level** (from user, optional, default `system`): one of `unit`, `integration`, or `system`. When the dispatching caller (e.g. `pharaoh-author`) does not propagate this input, the default applies — `system` is the broadest scope and the safest default for a top-level test case. - **tailoring** (from `.pharaoh/project/`): - - `artefact-catalog.yaml` — look up the `tc` entry if it exists; fall back to prefix `tc__` - and default required fields if absent - - `id-conventions.yaml` — prefix, separator, id_regex + - `artefact-catalog.yaml` — look up the entry for `target_level` to read `required_fields`, + `optional_fields`, `lifecycle`, and `required_body_sections` + - `id-conventions.yaml` — `prefixes` map (key = type name → value = identifier prefix + string), `separator`, `id_regex` - **needs.json**: required for parent resolution and ID uniqueness > Note: A `shared/tailoring-access.md` helper module is planned. Until it exists, Steps 1-2 below @@ -37,9 +45,10 @@ Do NOT review — use `pharaoh-vplan-review` after drafting. ## Outputs -A single RST `tc__` directive block containing: +A single RST directive block of type `target_level` containing: -- Unique ID per id-conventions (prefix `tc__` unless catalog overrides) +- Unique ID using the prefix resolved for `target_level` from `id-conventions.yaml`'s + `prefixes` map - `:status: draft` - `:verifies:` pointing to parent_id (validated in needs.json) - `:level:` set to the requested verification_level (`unit` / `integration` / `system`) @@ -56,28 +65,43 @@ without reading any other document beyond the referenced parent requirement. **1a. `artefact-catalog.yaml`** -Look up the `tc` entry. If found, read `required_fields`, `optional_fields`, `lifecycle`, -and `required_body_sections`. +Look up the entry whose key equals `target_level`. If found, read `required_fields`, +`optional_fields`, `lifecycle`, and `required_body_sections`. **`required_fields` / `optional_fields`** are directive option names (sphinx-needs `:key: value` options). **`required_body_sections`** are top-level Markdown/RST section headings that must appear in the directive body prose (e.g. `Inputs`, `Steps`, `Expected`). -If the `tc` entry does not exist, use these defaults: -- `required_fields`: `[id, status, verifies]` -- `optional_fields`: `[tags, rationale, level]` -- `required_body_sections`: `[Inputs, Steps, Expected]` -- `lifecycle`: `[draft, valid, inspected]` +If the entry is absent, FAIL: -Note the fallback in output if defaults were applied. +``` +FAIL: target_level "<value>" is not declared in .pharaoh/project/artefact-catalog.yaml. +Add an entry for "<value>" (with required_fields, required_body_sections, lifecycle) before +drafting, or pass a target_level that is already declared. +``` **1b. `id-conventions.yaml`** -Extract `separator` and `id_regex`. Use prefix `tc__` unless the catalog specifies otherwise. +Read the `prefixes:` map and look up the prefix for `target_level`. Also extract +`separator` and `id_regex`. + +If `prefixes` does not declare `target_level`, FAIL: + +``` +FAIL: id-conventions.yaml prefixes map has no entry for "<value>". +Declare a prefix for "<value>" (e.g. T_ for a type named "test", or TC_ for "tc") +before drafting. +``` + +The resolved prefix is the value of `prefixes[target_level]` — e.g. `tc__` for +`target_level: tc` on a project that uses the double-underscore convention, `T_` for +`target_level: test` on a project that uses underscore separators. **1c. Validate verification_level** -Accepted values: `unit`, `integration`, `system`. If a different value is supplied, FAIL: +Accepted values: `unit`, `integration`, `system`. If `verification_level` is absent, +default to `system` (the broadest scope; the override is documented in the Inputs +section above). If a different non-empty value is supplied, FAIL: ``` FAIL: verification_level "<value>" is not recognised. @@ -113,7 +137,8 @@ Specify an existing requirement or architecture element ID. 3. Check whether the parent's type is testable: - Requirement types (prefix ends in `req`) — always valid - - Architecture elements (prefix `arch__`) — valid at integration/system level only + - Architecture elements (any catalog-declared architecture type) — valid at + integration/system level only - Workflow/work-product types (`wf`, `wp`) — warn but do not block: ``` [WARNING] parent_id "<id>" has type "<type>". Verification plans are usually written @@ -143,20 +168,35 @@ test case. **5a. Derive local-ID part** -Format: `tc__<local>` where local is derived from the parent_id local part plus a level suffix: -- Strip the prefix from parent_id: `gd_req__abs_pump_activation` → `abs_pump_activation` -- Append `_<verification_level>`: → `abs_pump_activation_system` +Format: `<prefix><tail>` where `<prefix>` is the value resolved in Step 1b. The tail is +derived from the parent_id local part plus a level suffix: + +- Strip the parent's prefix from `parent_id`: `gd_req__abs_pump_activation` → `abs_pump_activation` +- Append `_<verification_level>` → `abs_pump_activation_system` +- Compose the full ID by concatenating `<prefix>` + `<tail>`. If `id-conventions.yaml` + declares an explicit `separator` distinct from any trailing punctuation in the prefix, + insert it between prefix and tail. + +Examples: + +- `prefixes: {tc: tc__}` → `tc__abs_pump_activation_system` +- `prefixes: {test: T_}` → `T_abs_pump_activation_system` Check uniqueness. If taken, append `_2`, `_3`, etc. **5b. Validate against id_regex** -Confirm the candidate matches `id_regex`. If it does not, FAIL: +Confirm the candidate matches the `id_regex` declared in `id-conventions.yaml`. If it does +not, FAIL: ``` FAIL: generated ID "<id>" does not match id_regex "<regex>". ``` +This is the gate that catches a hardcoded prefix mismatch — e.g. emitting `tc__foo_unit` +on a project whose `test` type uses prefix `T_` and a regex `^T_[A-Za-z0-9_]+$`. Because +the prefix is read from `prefixes[target_level]`, this case is now caught at draft time. + --- ### Step 6: Draft the test case body @@ -219,7 +259,7 @@ If any check fails after one rewrite attempt, emit with `[DIAGNOSTIC]`. ### Step 8: Emit the directive block ```rst -.. tc:: <test case title> +.. <target_level>:: <test case title> :id: <id> :status: draft :verifies: <parent_id> @@ -237,13 +277,8 @@ If any check fails after one rewrite attempt, emit with `[DIAGNOSTIC]`. <pass criterion> ``` -If the `tc` entry was absent from artefact-catalog and defaults were applied, append: - -``` -[NOTE] artefact-catalog.yaml has no 'tc' entry. Prefix 'tc__' and default required fields -[id, status, verifies, inputs, steps, expected] were used. Add a 'tc' entry to -.pharaoh/project/artefact-catalog.yaml before promoting beyond draft. -``` +The directive name is exactly `target_level`; the `:id:` value uses the prefix resolved from +`id-conventions.yaml`'s `prefixes` map. Both come from tailoring — neither is hardcoded. --- @@ -266,6 +301,12 @@ placeholder test case — improve the parent first. Cannot find needs.json → FAIL (Step 2). +**G5 — target_level not declared** + +If `target_level` is not declared in `artefact-catalog.yaml` or has no entry in +`id-conventions.yaml`'s `prefixes` map, FAIL (Step 1 handles this). The catalog is the +contract — never silently default to a hardcoded prefix. + --- ## Advisory chain @@ -282,14 +323,18 @@ Do not show this if the emit included a `[DIAGNOSTIC]`. ## Worked example +### Example A — default `target_level: tc` + **User input:** -> Parent: `gd_req__abs_pump_activation`; level: `system`. +> Parent: `gd_req__abs_pump_activation`; level: `system`. (`target_level` defaults to `tc`.) **Parent body (from needs.json):** > "The brake controller shall engage the ABS pump when measured wheel slip exceeds the calibrated > activation threshold." -**Step 1:** No `tc` entry in artefact-catalog.yaml. Defaults applied. Level `system` is valid. +**Step 1:** Catalog has a `tc` entry with `required_fields: [id, status, verifies]` and +`required_body_sections: [Inputs, Steps, Expected]`. `id-conventions.yaml` `prefixes` map +has `tc: tc__`. Level `system` is valid. **Step 2:** needs.json found; 185 IDs loaded. @@ -298,8 +343,8 @@ Do not show this if the emit included a `[DIAGNOSTIC]`. **Step 4:** Testable claim — "engage the ABS pump when wheel slip exceeds the calibrated activation threshold" — discrete activation event, verifiable by observing pump output signal. -**Step 5:** local = `abs_pump_activation_system`; candidate = `tc__abs_pump_activation_system`. -Not in needs.json. Passes id_regex. +**Step 5:** prefix = `tc__`; tail = `abs_pump_activation_system`; candidate = +`tc__abs_pump_activation_system`. Not in needs.json. Passes id_regex. **Step 6 body drafted** (see output below). @@ -332,13 +377,37 @@ concrete ("ABS pump output signal activates within 50 ms"). All pass. ``` ``` -[NOTE] artefact-catalog.yaml has no 'tc' entry. Prefix 'tc__' and default required fields -[id, status, verifies, inputs, steps, expected] were used. Add a 'tc' entry to -.pharaoh/project/artefact-catalog.yaml before promoting beyond draft. - Consider running `pharaoh-vplan-review tc__abs_pump_activation_system` to audit against per-axis criteria. ``` +### Example B — project that uses `test` with prefix `T_` + +**User input:** +> Parent: `req__login_lockout`; target_level: `test`; level: `unit`. + +**Step 1:** Catalog has a `test` entry with `required_fields: [id, status, verifies]` and +`required_body_sections: [Inputs, Steps, Expected]`. `id-conventions.yaml` `prefixes` map +has `test: T_`. Level `unit` is valid. + +**Step 5:** prefix = `T_`; tail = `login_lockout_unit`; candidate = `T_login_lockout_unit`. +Passes id_regex `^T_[A-Za-z0-9_]+$`. + +**Step 8 output (header only):** + +```rst +.. test:: Login lockout — unit test + :id: T_login_lockout_unit + :status: draft + :verifies: req__login_lockout + :level: unit + + ... +``` + +A skill that hardcoded `tc__` would have emitted `tc__login_lockout_unit`, which fails the +project's `T_…` `id_regex` at Step 5b. By deriving prefix and directive name from tailoring +the same skill serves both projects. + ## Last step After emitting the artefact, invoke `pharaoh-vplan-review` on it. Pass the emitted artefact (or its `need_id`) as `target`. Attach the returned review JSON to the skill's output under the key `review`. If the review emits any axis with `score: 0` or `severity: critical`, return a non-success status with the review findings verbatim and do NOT finalize the artefact — the caller must regenerate (via `pharaoh-vplan-regenerate` if available, or by re-invoking this skill with the findings as input). diff --git a/skills/shared/strictness.md b/skills/shared/strictness.md index 88a290e..4b06ac5 100644 --- a/skills/shared/strictness.md +++ b/skills/shared/strictness.md @@ -71,10 +71,7 @@ require_mece_on_release = false # pharaoh:release requires pharaoh:mece These gates only have effect when `strictness = "enforcing"`. In advisory mode, they are used only for tip messages. -Default values if keys are missing: -- `require_change_analysis = true` -- `require_verification = true` -- `require_mece_on_release = false` +The canonical default values for `require_change_analysis`, `require_verification`, and `require_mece_on_release` live in `pharaoh.toml.example` at the repo root. This document does not redeclare them: skills that need to reason about defaults should read the example file or fail loudly when a flag is absent. Do not introduce competing local defaults here. To change a default, edit `pharaoh.toml.example` only. ### Step 1d: Parse traceability requirements diff --git a/skills/shared/tailoring-access.md b/skills/shared/tailoring-access.md index 4a683e9..4c38636 100644 --- a/skills/shared/tailoring-access.md +++ b/skills/shared/tailoring-access.md @@ -6,7 +6,7 @@ Shared helper module documenting how Pharaoh skills resolve project tailoring pa Given a `tailoring_path` input (typically the absolute path to `.pharaoh/project/`): -1. **Artefact catalogue**: read `<tailoring_path>/artefact-catalog.yaml`. Contains `required_fields`, `optional_fields`, `child_of`, and `lifecycle_ref` per declared type. Produced by `pharaoh-tailor-bootstrap` or hand-authored. +1. **Artefact catalogue**: read `<tailoring_path>/artefact-catalog.yaml`. Contains `required_fields`, `optional_fields`, `lifecycle`, and `required_body_sections` per declared type. Validates against `schemas/artefact-catalog.schema.json`. Produced by `pharaoh-tailor-bootstrap` or hand-authored. 2. **ID conventions**: read `<tailoring_path>/id-conventions.yaml`. Contains `prefixes` (directive → prefix map), `id_regex` (validation regex), `separator`. Produced by `pharaoh-tailor-bootstrap`. 3. **Workflows**: read `<tailoring_path>/workflows.yaml`. Per-type state machine (`states`, `transitions`, `initial`, `final`). Produced by `pharaoh-tailor-bootstrap`. 4. **Checklists**: read `<tailoring_path>/checklists/<directive>.md` for per-type checklists. Use `<tailoring_path>/checklists/requirement.md` as the canonical-alias filename when the caller wants "the" requirement checklist without knowing the project's directive name (alias is emitted by `pharaoh-tailor-bootstrap`).